aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2016-10-13 17:21:41 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2016-10-13 17:21:48 +0200
commit90fa3414156522ef89f9ebe8cefd6dad303ce06c (patch)
tree65ba250895722795ce3d14fb9b4341953ffd1733
parent2a999f870e791d99c5c0463a11be05fc5a14dfcc (diff)
parenta05fec277d0a122e03bb6c7756777729df50b1f2 (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
-rw-r--r--.gitignore9
-rw-r--r--.qmake.conf3
-rw-r--r--LICENSE.GPLv32
-rw-r--r--LICENSE.LGPLv212
-rw-r--r--LICENSE.LGPLv32
-rwxr-xr-xbin/rename-qtdeclarative-symbols.sh642
-rw-r--r--config.tests/d3d12/d3d12.pro2
-rw-r--r--dist/changes-5.6.14
-rw-r--r--dist/changes-5.6.280
-rw-r--r--dist/changes-5.7.0114
-rw-r--r--examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp2
-rw-r--r--examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp2
-rw-r--r--examples/quick/demos/demos.pro4
-rw-r--r--examples/quick/demos/photosurface/main.cpp8
-rw-r--r--examples/quick/demos/photoviewer/deployment.pri19
-rw-r--r--examples/quick/demos/photoviewer/photoviewer.pro7
-rw-r--r--examples/quick/demos/samegame/samegame.pro2
-rw-r--r--examples/quick/embeddedinwidgets/main.cpp3
-rw-r--r--examples/quick/quick.pro2
-rw-r--r--examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp1
-rw-r--r--examples/quick/quickwidgets/quickwidget/customgl.qml59
-rw-r--r--examples/quick/quickwidgets/quickwidget/fbitem.cpp90
-rw-r--r--examples/quick/quickwidgets/quickwidget/fbitem.h53
-rw-r--r--examples/quick/quickwidgets/quickwidget/main.cpp41
-rw-r--r--examples/quick/quickwidgets/quickwidget/quickwidget.pro3
-rw-r--r--examples/quick/quickwidgets/quickwidget/quickwidget.qrc2
-rw-r--r--examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml66
-rw-r--r--examples/quick/rendercontrol/window_multithreaded.cpp8
-rw-r--r--examples/quick/rendercontrol/window_singlethreaded.cpp8
-rw-r--r--examples/quick/scenegraph/graph/linenode.cpp2
-rw-r--r--examples/quick/scenegraph/graph/noisynode.cpp2
-rw-r--r--examples/quick/scenegraph/rendernode/customrenderitem.cpp5
-rw-r--r--examples/quick/scenegraph/rendernode/d3d12renderer.cpp29
-rw-r--r--examples/quick/scenegraph/rendernode/d3d12renderer.h2
-rw-r--r--examples/quick/scenegraph/rendernode/main.cpp7
-rw-r--r--examples/quick/scenegraph/rendernode/main.qml5
-rw-r--r--examples/quick/scenegraph/rendernode/openglrenderer.cpp14
-rw-r--r--examples/quick/scenegraph/rendernode/openglrenderer.h6
-rw-r--r--examples/quick/scenegraph/rendernode/rendernode.pro4
-rw-r--r--examples/quick/scenegraph/rendernode/softwarerenderer.cpp101
-rw-r--r--examples/quick/scenegraph/rendernode/softwarerenderer.h63
-rw-r--r--examples/quick/scenegraph/scenegraph.pro2
-rw-r--r--examples/quick/scenegraph/sgengine/window.cpp2
-rw-r--r--examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc4
-rw-r--r--examples/quick/scenegraph/textureinthread/main.cpp2
-rw-r--r--examples/quick/shadereffects/content/shaders/+hlsl/blur.frag18
-rw-r--r--examples/quick/shadereffects/content/shaders/+hlsl/colorize.frag17
-rw-r--r--examples/quick/shadereffects/content/shaders/+hlsl/genie.vert31
-rw-r--r--examples/quick/shadereffects/content/shaders/+hlsl/outline.frag21
-rw-r--r--examples/quick/shadereffects/content/shaders/+hlsl/shadow.frag20
-rw-r--r--examples/quick/shadereffects/content/shaders/+hlsl/wobble.frag17
-rw-r--r--examples/quick/shadereffects/content/shaders/blur.frag14
-rw-r--r--examples/quick/shadereffects/content/shaders/colorize.frag12
-rw-r--r--examples/quick/shadereffects/content/shaders/genie.vert21
-rw-r--r--examples/quick/shadereffects/content/shaders/outline.frag16
-rw-r--r--examples/quick/shadereffects/content/shaders/shadow.frag14
-rw-r--r--examples/quick/shadereffects/content/shaders/wobble.frag13
-rw-r--r--examples/quick/shadereffects/doc/src/shadereffects.qdoc15
-rw-r--r--examples/quick/shadereffects/shadereffects.qml102
-rw-r--r--examples/quick/shadereffects/shadereffects.qrc12
-rw-r--r--examples/quick/shared/Label.qml46
-rw-r--r--examples/quick/shared/quick_shared.qrc1
-rw-r--r--examples/quick/shared/shared.qrc1
-rw-r--r--examples/quick/textureprovider/etcprovider.cpp8
-rw-r--r--examples/quick/textureprovider/etcprovider.h4
-rw-r--r--examples/quick/window/AllScreens.qml75
-rw-r--r--examples/quick/window/CurrentScreen.qml (renamed from examples/quick/window/ScreenInfo.qml)36
-rw-r--r--examples/quick/window/Splash.qml2
-rw-r--r--examples/quick/window/doc/src/window.qdoc2
-rw-r--r--examples/quick/window/main.cpp3
-rw-r--r--examples/quick/window/window.qml23
-rw-r--r--examples/quick/window/window.qrc3
-rw-r--r--src/3rdparty/masm/LICENSE22
-rw-r--r--src/3rdparty/masm/masm-defs.pri3
-rw-r--r--src/3rdparty/masm/qt_attribution.json23
-rw-r--r--src/3rdparty/masm/wtf/MathExtras.h4
-rw-r--r--src/3rdparty/masm/wtf/StdLibExtras.h2
-rw-r--r--src/3rdparty/masm/yarr/YarrJIT.cpp22
-rw-r--r--src/imports/builtins/builtins.qmltypes25
-rw-r--r--src/imports/folderlistmodel/fileinfothread.cpp5
-rw-r--r--src/imports/folderlistmodel/fileinfothread_p.h2
-rw-r--r--src/imports/folderlistmodel/fileproperty_p.h20
-rw-r--r--src/imports/folderlistmodel/plugins.qmltypes275
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp5
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.h12
-rw-r--r--src/imports/imports.pro6
-rw-r--r--src/imports/layouts/plugins.qmltypes4
-rw-r--r--src/imports/layouts/qquickgridlayoutengine_p.h6
-rw-r--r--src/imports/layouts/qquicklayout.cpp21
-rw-r--r--src/imports/layouts/qquicklinearlayout.cpp16
-rw-r--r--src/imports/layouts/qquicklinearlayout_p.h4
-rw-r--r--src/imports/localstorage/plugin.cpp44
-rw-r--r--src/imports/localstorage/plugins.qmltypes2
-rw-r--r--src/imports/models/plugins.qmltypes466
-rw-r--r--src/imports/particles/plugins.qmltypes206
-rw-r--r--src/imports/qtqml/plugins.qmltypes21
-rw-r--r--src/imports/qtquick2/plugin.cpp6
-rw-r--r--src/imports/qtquick2/plugins.qmltypes185
-rw-r--r--src/imports/settings/plugins.qmltypes2
-rw-r--r--src/imports/settings/qqmlsettings.cpp2
-rw-r--r--src/imports/settings/qqmlsettings_p.h6
-rw-r--r--src/imports/statemachine/plugins.qmltypes2
-rw-r--r--src/imports/statemachine/signaltransition.cpp31
-rw-r--r--src/imports/statemachine/signaltransition.h1
-rw-r--r--src/imports/statemachine/state.h4
-rw-r--r--src/imports/statemachine/statemachine.h4
-rw-r--r--src/imports/statemachine/timeouttransition.h4
-rw-r--r--src/imports/testlib/TestCase.qml81
-rw-r--r--src/imports/testlib/plugins.qmltypes5
-rw-r--r--src/imports/window/plugins.qmltypes16
-rw-r--r--src/imports/xmllistmodel/plugins.qmltypes267
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel.cpp4
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel_p.h12
-rw-r--r--src/particles/qquickage_p.h3
-rw-r--r--src/particles/qquickangledirection.cpp2
-rw-r--r--src/particles/qquickangledirection_p.h2
-rw-r--r--src/particles/qquickcumulativedirection.cpp2
-rw-r--r--src/particles/qquickcumulativedirection_p.h2
-rw-r--r--src/particles/qquickcustomaffector_p.h5
-rw-r--r--src/particles/qquickcustomparticle.cpp19
-rw-r--r--src/particles/qquickcustomparticle_p.h18
-rw-r--r--src/particles/qquickdirection.cpp2
-rw-r--r--src/particles/qquickdirection_p.h2
-rw-r--r--src/particles/qquickellipseextruder_p.h4
-rw-r--r--src/particles/qquickfriction_p.h2
-rw-r--r--src/particles/qquickgravity_p.h3
-rw-r--r--src/particles/qquickgroupgoal_p.h2
-rw-r--r--src/particles/qquickimageparticle.cpp10
-rw-r--r--src/particles/qquickimageparticle_p.h12
-rw-r--r--src/particles/qquickitemparticle_p.h10
-rw-r--r--src/particles/qquicklineextruder_p.h6
-rw-r--r--src/particles/qquickmaskextruder_p.h4
-rw-r--r--src/particles/qquickparticleaffector.cpp2
-rw-r--r--src/particles/qquickparticleaffector_p.h4
-rw-r--r--src/particles/qquickparticleemitter_p.h4
-rw-r--r--src/particles/qquickparticlegroup_p.h4
-rw-r--r--src/particles/qquickparticlepainter.cpp3
-rw-r--r--src/particles/qquickparticlepainter_p.h4
-rw-r--r--src/particles/qquickparticlesystem_p.h6
-rw-r--r--src/particles/qquickpointattractor_p.h3
-rw-r--r--src/particles/qquickpointdirection.cpp2
-rw-r--r--src/particles/qquickpointdirection_p.h2
-rw-r--r--src/particles/qquickrectangleextruder_p.h4
-rw-r--r--src/particles/qquickspritegoal_p.h3
-rw-r--r--src/particles/qquicktargetdirection.cpp2
-rw-r--r--src/particles/qquicktargetdirection_p.h2
-rw-r--r--src/particles/qquicktrailemitter_p.h4
-rw-r--r--src/particles/qquickturbulence_p.h6
-rw-r--r--src/particles/qquickv4particledata.cpp2
-rw-r--r--src/particles/qquickv4particledata_p.h2
-rw-r--r--src/particles/qquickwander_p.h3
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp18
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp38
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h10
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp108
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp5
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h5
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp16
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h1
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h14
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp121
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp32
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/globalinspector.h4
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/highlight.cpp26
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/highlight.h7
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp14
-rw-r--r--src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp7
-rw-r--r--src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp10
-rw-r--r--src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h4
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp29
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h1
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp71
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h4
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp39
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h13
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp28
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h2
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp88
-rw-r--r--src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp7
-rw-r--r--src/plugins/qmltooling/shared/qqmldebugserver.h2
-rw-r--r--src/plugins/scenegraph/d3d12/d3d12.pro20
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12adaptation.cpp11
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials.cpp13
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h3
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12context.cpp54
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12context_p.h10
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp361
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h26
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h13
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12glyphcache.cpp17
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12internalimagenode.cpp (renamed from src/plugins/scenegraph/d3d12/qsgd3d12imagenode.cpp)22
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12internalimagenode_p.h (renamed from src/plugins/scenegraph/d3d12/qsgd3d12imagenode_p.h)12
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12internalrectanglenode.cpp (renamed from src/plugins/scenegraph/d3d12/qsgd3d12rectanglenode.cpp)8
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12internalrectanglenode_p.h (renamed from src/plugins/scenegraph/d3d12/qsgd3d12rectanglenode_p.h)12
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12painternode.cpp3
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12painternode_p.h1
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12publicnodes.cpp254
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12publicnodes_p.h136
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp52
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h15
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp1
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp1219
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderloop_p.h41
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp123
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h11
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12spritenode.cpp314
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12spritenode_p.h90
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp8
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp1183
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop_p.h129
-rw-r--r--src/plugins/scenegraph/d3d12/shaders/shaders.pri11
-rw-r--r--src/plugins/scenegraph/d3d12/shaders/sprite.hlsl43
-rw-r--r--src/plugins/scenegraph/d3d12/shaders/textmask.hlsl16
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qparallelanimationgroupjob_p.h12
-rw-r--r--src/qml/compiler/compiler.pri13
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp129
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h134
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator.cpp71
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h741
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp703
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator_p.h87
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp1744
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h236
-rw-r--r--src/qml/compiler/qv4codegen.cpp133
-rw-r--r--src/qml/compiler/qv4codegen_p.h228
-rw-r--r--src/qml/compiler/qv4compilationunitmapper.cpp99
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_p.h87
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_unix.cpp (renamed from src/qml/qml/qqmlaccessors.cpp)84
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_win.cpp134
-rw-r--r--src/qml/compiler/qv4compileddata.cpp314
-rw-r--r--src/qml/compiler/qv4compileddata_p.h525
-rw-r--r--src/qml/compiler/qv4compiler.cpp234
-rw-r--r--src/qml/compiler/qv4compiler_p.h11
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h111
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp420
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h141
-rw-r--r--src/qml/compiler/qv4isel_p.cpp26
-rw-r--r--src/qml/compiler/qv4isel_p.h46
-rw-r--r--src/qml/compiler/qv4isel_util_p.h50
-rw-r--r--src/qml/compiler/qv4jsir.cpp345
-rw-r--r--src/qml/compiler/qv4jsir_p.h447
-rw-r--r--src/qml/compiler/qv4ssa.cpp1244
-rw-r--r--src/qml/compiler/qv4ssa_p.h181
-rw-r--r--src/qml/debugger/debugger.pri27
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter_p.h4
-rw-r--r--src/qml/debugger/qqmldebug.cpp17
-rw-r--r--src/qml/debugger/qqmldebug.h3
-rw-r--r--src/qml/debugger/qqmldebugconnector.cpp8
-rw-r--r--src/qml/debugger/qqmldebugconnector_p.h25
-rw-r--r--src/qml/debugger/qqmldebugservice.cpp33
-rw-r--r--src/qml/debugger/qqmldebugservice_p.h20
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces_p.h57
-rw-r--r--src/qml/debugger/qqmldebugstatesdelegate_p.h7
-rw-r--r--src/qml/debugger/qqmlmemoryprofiler.cpp (renamed from src/qml/qml/qqmlmemoryprofiler.cpp)0
-rw-r--r--src/qml/debugger/qqmlmemoryprofiler_p.h (renamed from src/qml/qml/qqmlmemoryprofiler_p.h)9
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h66
-rw-r--r--src/qml/debugger/qqmlprofilerdefinitions_p.h4
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc14
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/exposecppattributes.qdoc12
-rw-r--r--src/qml/doc/src/cppintegration/extending-tutorial.qdoc2
-rw-r--r--src/qml/doc/src/javascript/dynamicobjectcreation.qdoc2
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc9
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc36
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc5
-rw-r--r--src/qml/doc/src/qtqml.qdoc13
-rw-r--r--src/qml/jit/qv4assembler.cpp94
-rw-r--r--src/qml/jit/qv4assembler_p.h155
-rw-r--r--src/qml/jit/qv4binop.cpp22
-rw-r--r--src/qml/jit/qv4binop_p.h1
-rw-r--r--src/qml/jit/qv4isel_masm.cpp225
-rw-r--r--src/qml/jit/qv4isel_masm_p.h22
-rw-r--r--src/qml/jit/qv4regalloc.cpp284
-rw-r--r--src/qml/jit/qv4targetplatform_p.h4
-rw-r--r--src/qml/jit/qv4unop.cpp8
-rw-r--r--src/qml/jsapi/qjsengine.cpp43
-rw-r--r--src/qml/jsapi/qjsengine.h8
-rw-r--r--src/qml/jsapi/qjsvalue.cpp65
-rw-r--r--src/qml/jsapi/qjsvalue.h2
-rw-r--r--src/qml/jsapi/qjsvalue_p.h1
-rw-r--r--src/qml/jsruntime/jsruntime.pri10
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp28
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp40
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h5
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp14
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h2
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp64
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4context.cpp33
-rw-r--r--src/qml/jsruntime/qv4context_p.h69
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp22
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h4
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp36
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h6
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h15
-rw-r--r--src/qml/jsruntime/qv4engine.cpp88
-rw-r--r--src/qml/jsruntime/qv4engine_p.h37
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp39
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp2
-rw-r--r--src/qml/jsruntime/qv4function.cpp10
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp251
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h32
-rw-r--r--src/qml/jsruntime/qv4global_p.h2
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp38
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4include.cpp2
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp34
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h30
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp77
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp24
-rw-r--r--src/qml/jsruntime/qv4managed_p.h7
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp4
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h1
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp15
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4object.cpp19
-rw-r--r--src/qml/jsruntime/qv4object_p.h37
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp5
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp21
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h4
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp9
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h4
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp2
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h62
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp569
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h65
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp53
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp304
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h7
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h58
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h71
-rw-r--r--src/qml/jsruntime/qv4script.cpp65
-rw-r--r--src/qml/jsruntime/qv4script_p.h10
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp15
-rw-r--r--src/qml/jsruntime/qv4string.cpp71
-rw-r--r--src/qml/jsruntime/qv4string_p.h68
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp49
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp81
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h4
-rw-r--r--src/qml/jsruntime/qv4util_p.h6
-rw-r--r--src/qml/jsruntime/qv4value_p.h121
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp7
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp68
-rw-r--r--src/qml/memory/qv4heap_p.h74
-rw-r--r--src/qml/memory/qv4mm.cpp71
-rw-r--r--src/qml/memory/qv4mm_p.h8
-rw-r--r--src/qml/parser/qqmljsast_p.h554
-rw-r--r--src/qml/parser/qqmljsengine_p.cpp2
-rw-r--r--src/qml/qml.pro9
-rw-r--r--src/qml/qml/ftw/ftw.pri4
-rw-r--r--src/qml/qml/ftw/qdeferredcleanup_p.h74
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp23
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h39
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp6
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h24
-rw-r--r--src/qml/qml/qml.pri13
-rw-r--r--src/qml/qml/qqml.h3
-rw-r--r--src/qml/qml/qqmlabstractbinding.cpp19
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h15
-rw-r--r--src/qml/qml/qqmlaccessors_p.h177
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp3
-rw-r--r--src/qml/qml/qqmlbinding.cpp476
-rw-r--r--src/qml/qml/qqmlbinding_p.h35
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp20
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h4
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp151
-rw-r--r--src/qml/qml/qqmlcompiler_p.h139
-rw-r--r--src/qml/qml/qqmlcomponent.cpp74
-rw-r--r--src/qml/qml/qqmlcomponent.h9
-rw-r--r--src/qml/qml/qqmlcomponent_p.h10
-rw-r--r--src/qml/qml/qqmlcontext.cpp7
-rw-r--r--src/qml/qml/qqmlcontext_p.h2
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp3
-rw-r--r--src/qml/qml/qqmlcontextwrapper_p.h2
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp15
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h6
-rw-r--r--src/qml/qml/qqmldata_p.h63
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp2
-rw-r--r--src/qml/qml/qqmlengine.cpp218
-rw-r--r--src/qml/qml/qqmlengine.h3
-rw-r--r--src/qml/qml/qqmlengine_p.h13
-rw-r--r--src/qml/qml/qqmlerror.cpp4
-rw-r--r--src/qml/qml/qqmlexpression.cpp11
-rw-r--r--src/qml/qml/qqmlexpression_p.h7
-rw-r--r--src/qml/qml/qqmlextensionplugin.h2
-rw-r--r--src/qml/qml/qqmlfileselector_p.h2
-rw-r--r--src/qml/qml/qqmlimport.cpp131
-rw-r--r--src/qml/qml/qqmlincubator.cpp36
-rw-r--r--src/qml/qml/qqmlincubator_p.h4
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp81
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h26
-rw-r--r--src/qml/qml/qqmllist.cpp6
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp2
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h2
-rw-r--r--src/qml/qml/qqmlloggingcategory.cpp128
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h (renamed from src/qml/qml/ftw/qdeletewatcher_p.h)74
-rw-r--r--src/qml/qml/qqmlmetatype.cpp21
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp414
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h12
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlopenmetaobject_p.h4
-rw-r--r--src/qml/qml/qqmlproperty.cpp428
-rw-r--r--src/qml/qml/qqmlproperty_p.h44
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp750
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h639
-rw-r--r--src/qml/qml/qqmlpropertyindex_p.h133
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor_p.h4
-rw-r--r--src/qml/qml/qqmlproxymetaobject.cpp6
-rw-r--r--src/qml/qml/qqmlproxymetaobject_p.h4
-rw-r--r--src/qml/qml/qqmltypeloader.cpp646
-rw-r--r--src/qml/qml/qqmltypeloader_p.h116
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp2
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp9
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h8
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding.cpp8
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h8
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp39
-rw-r--r--src/qml/qml/qqmlvme.cpp1
-rw-r--r--src/qml/qml/qqmlvme_p.h4
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp68
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h17
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp63
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp76
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h3
-rw-r--r--src/qml/qml/v8/qv8engine.cpp3
-rw-r--r--src/qml/types/qqmlbind.cpp1
-rw-r--r--src/qml/types/qqmlbind_p.h6
-rw-r--r--src/qml/types/qqmlconnections.cpp3
-rw-r--r--src/qml/types/qqmlconnections_p.h8
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp66
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h24
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h34
-rw-r--r--src/qml/types/qqmlinstantiator.cpp6
-rw-r--r--src/qml/types/qqmlinstantiator_p.h6
-rw-r--r--src/qml/types/qqmllistmodel.cpp60
-rw-r--r--src/qml/types/qqmllistmodel_p.h10
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h10
-rw-r--r--src/qml/types/qqmllistmodelworkeragent_p.h2
-rw-r--r--src/qml/types/qqmlobjectmodel.cpp2
-rw-r--r--src/qml/types/qqmlobjectmodel_p.h16
-rw-r--r--src/qml/types/qqmltimer.cpp4
-rw-r--r--src/qml/types/qqmltimer_p.h6
-rw-r--r--src/qml/types/qquickworkerscript.cpp16
-rw-r--r--src/qml/types/qquickworkerscript_p.h12
-rw-r--r--src/qml/util/qqmladaptormodel.cpp4
-rw-r--r--src/qml/util/qqmlchangeset.cpp12
-rw-r--r--src/qml/util/qqmllistcompositor.cpp4
-rw-r--r--src/qml/util/qqmlpropertymap.cpp8
-rw-r--r--src/qmldebug/qqmldebugconnection.cpp60
-rw-r--r--src/qmldebug/qqmldebugconnection_p.h2
-rw-r--r--src/qmldebug/qqmlprofilerclient_p.h2
-rw-r--r--src/qmltest/qmltest.pro4
-rw-r--r--src/qmltest/quicktest.cpp13
-rw-r--r--src/qmltest/quicktestevent.cpp17
-rw-r--r--src/qmltest/quicktestevent_p.h2
-rw-r--r--src/qmltest/quicktestresult.cpp4
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp8
-rw-r--r--src/quick/accessible/qaccessiblequickview_p.h20
-rw-r--r--src/quick/designer/qqmldesignermetaobject.cpp19
-rw-r--r--src/quick/designer/qqmldesignermetaobject_p.h3
-rw-r--r--src/quick/designer/qquickdesignercustomobjectdata.cpp11
-rw-r--r--src/quick/designer/qquickdesignersupport.cpp7
-rw-r--r--src/quick/designer/qquickdesignersupportitems.cpp14
-rw-r--r--src/quick/designer/qquickdesignerwindowmanager_p.h22
-rw-r--r--src/quick/doc/snippets/qml/localstorage/dbtransaction.js68
-rw-r--r--src/quick/doc/src/concepts/input/focus.qdoc2
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc2
-rw-r--r--src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc105
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc341
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc10
-rw-r--r--src/quick/doc/src/examples.qdoc2
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc13
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp60
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp14
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h22
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h26
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h16
-rw-r--r--src/quick/items/context2d/qquickcontext2dtile_p.h8
-rw-r--r--src/quick/items/items.pri30
-rw-r--r--src/quick/items/items.qrc4
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h2
-rw-r--r--src/quick/items/qquickanchors.cpp34
-rw-r--r--src/quick/items/qquickanchors_p_p.h6
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp686
-rw-r--r--src/quick/items/qquickanimatedsprite_p.h286
-rw-r--r--src/quick/items/qquickanimatedsprite_p_p.h96
-rw-r--r--src/quick/items/qquickborderimage.cpp4
-rw-r--r--src/quick/items/qquickclipnode.cpp4
-rw-r--r--src/quick/items/qquickdrag.cpp9
-rw-r--r--src/quick/items/qquickdrag_p.h2
-rw-r--r--src/quick/items/qquickdroparea.cpp4
-rw-r--r--src/quick/items/qquickdroparea_p.h2
-rw-r--r--src/quick/items/qquickevents.cpp508
-rw-r--r--src/quick/items/qquickevents_p_p.h339
-rw-r--r--src/quick/items/qquickflickable.cpp67
-rw-r--r--src/quick/items/qquickflickable_p.h2
-rw-r--r--src/quick/items/qquickflickable_p_p.h9
-rw-r--r--src/quick/items/qquickflipable.cpp2
-rw-r--r--src/quick/items/qquickflipable_p.h2
-rw-r--r--src/quick/items/qquickframebufferobject.cpp11
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp165
-rw-r--r--src/quick/items/qquickgenericshadereffect_p.h15
-rw-r--r--src/quick/items/qquickgraphicsinfo.cpp35
-rw-r--r--src/quick/items/qquickgridview.cpp32
-rw-r--r--src/quick/items/qquickimage.cpp6
-rw-r--r--src/quick/items/qquickimagebase.cpp2
-rw-r--r--src/quick/items/qquickimplicitsizeitem.cpp13
-rw-r--r--src/quick/items/qquickitem.cpp492
-rw-r--r--src/quick/items/qquickitem.h3
-rw-r--r--src/quick/items/qquickitem_p.h43
-rw-r--r--src/quick/items/qquickitemanimation.cpp46
-rw-r--r--src/quick/items/qquickitemanimation_p_p.h4
-rw-r--r--src/quick/items/qquickitemchangelistener_p.h59
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp22
-rw-r--r--src/quick/items/qquickitemgrabresult.h7
-rw-r--r--src/quick/items/qquickitemsmodule.cpp13
-rw-r--r--src/quick/items/qquickitemview.cpp115
-rw-r--r--src/quick/items/qquickitemview_p.h2
-rw-r--r--src/quick/items/qquickitemview_p_p.h6
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp2
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h2
-rw-r--r--src/quick/items/qquicklistview.cpp72
-rw-r--r--src/quick/items/qquicklistview_p.h8
-rw-r--r--src/quick/items/qquickloader.cpp5
-rw-r--r--src/quick/items/qquickloader_p_p.h4
-rw-r--r--src/quick/items/qquickmousearea.cpp36
-rw-r--r--src/quick/items/qquickmousearea_p_p.h1
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp59
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h2
-rw-r--r--src/quick/items/qquickopenglshadereffect.cpp205
-rw-r--r--src/quick/items/qquickopenglshadereffect_p.h34
-rw-r--r--src/quick/items/qquickopenglshadereffectnode.cpp6
-rw-r--r--src/quick/items/qquickopenglshadereffectnode_p.h10
-rw-r--r--src/quick/items/qquickpainteditem.cpp2
-rw-r--r--src/quick/items/qquickpathview.cpp223
-rw-r--r--src/quick/items/qquickpathview_p.h9
-rw-r--r--src/quick/items/qquickpathview_p_p.h8
-rw-r--r--src/quick/items/qquickpincharea.cpp2
-rw-r--r--src/quick/items/qquickpositioners_p_p.h4
-rw-r--r--src/quick/items/qquickrectangle.cpp6
-rw-r--r--src/quick/items/qquickrendercontrol.cpp38
-rw-r--r--src/quick/items/qquickrepeater.cpp4
-rw-r--r--src/quick/items/qquickscreen.cpp195
-rw-r--r--src/quick/items/qquickscreen_p.h48
-rw-r--r--src/quick/items/qquickshadereffect.cpp173
-rw-r--r--src/quick/items/qquickshadereffect_p.h3
-rw-r--r--src/quick/items/qquickshadereffectmesh.cpp23
-rw-r--r--src/quick/items/qquickshadereffectmesh_p.h2
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp10
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h4
-rw-r--r--src/quick/items/qquicksprite_p.h2
-rw-r--r--src/quick/items/qquickspriteengine.cpp156
-rw-r--r--src/quick/items/qquickspriteengine_p.h48
-rw-r--r--src/quick/items/qquickspritesequence.cpp402
-rw-r--r--src/quick/items/qquickspritesequence_p.h68
-rw-r--r--src/quick/items/qquickspritesequence_p_p.h90
-rw-r--r--src/quick/items/qquickstateoperations.cpp34
-rw-r--r--src/quick/items/qquickstateoperations_p.h4
-rw-r--r--src/quick/items/qquicktext.cpp19
-rw-r--r--src/quick/items/qquicktextcontrol.cpp7
-rw-r--r--src/quick/items/qquicktextcontrol_p.h6
-rw-r--r--src/quick/items/qquicktextdocument.cpp4
-rw-r--r--src/quick/items/qquicktextdocument_p.h8
-rw-r--r--src/quick/items/qquicktextedit.cpp16
-rw-r--r--src/quick/items/qquicktextinput.cpp62
-rw-r--r--src/quick/items/qquicktextnode.cpp14
-rw-r--r--src/quick/items/qquicktextnode_p.h15
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp41
-rw-r--r--src/quick/items/qquicktextnodeengine_p.h19
-rw-r--r--src/quick/items/qquickview.cpp29
-rw-r--r--src/quick/items/qquickview_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp1306
-rw-r--r--src/quick/items/qquickwindow.h7
-rw-r--r--src/quick/items/qquickwindow_p.h101
-rw-r--r--src/quick/items/qquickwindowmodule.cpp25
-rw-r--r--src/quick/items/qquickwindowmodule_p.h5
-rw-r--r--src/quick/qtquick2.cpp43
-rw-r--r--src/quick/quick.pro2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp17
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h4
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp13
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp68
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h12
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp (renamed from src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode.cpp)42
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h (renamed from src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h)10
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp (renamed from src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp)34
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h (renamed from src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h)10
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp5
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp (renamed from src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode.cpp)91
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h145
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp132
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h27
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp70
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h18
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp49
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h4
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp37
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h14
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp6
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp139
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h92
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp991
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h118
-rw-r--r--src/quick/scenegraph/adaptations/software/software.pri20
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp19
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp21
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp5
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp10
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h6
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendererinterface.cpp88
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendererinterface.h9
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.cpp103
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.h11
-rw-r--r--src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp14
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp10
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h61
-rw-r--r--src/quick/scenegraph/qsgbasicinternalimagenode.cpp (renamed from src/quick/scenegraph/qsgbasicimagenode.cpp)28
-rw-r--r--src/quick/scenegraph/qsgbasicinternalimagenode_p.h (renamed from src/quick/scenegraph/qsgbasicimagenode_p.h)8
-rw-r--r--src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp (renamed from src/quick/scenegraph/qsgbasicrectanglenode.cpp)26
-rw-r--r--src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h (renamed from src/quick/scenegraph/qsgbasicrectanglenode_p.h)8
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp19
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h28
-rw-r--r--src/quick/scenegraph/qsgcontextplugin.cpp4
-rw-r--r--src/quick/scenegraph/qsgdefaultcontext.cpp55
-rw-r--r--src/quick/scenegraph/qsgdefaultcontext_p.h11
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp15
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h10
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp23
-rw-r--r--src/quick/scenegraph/qsgdefaultinternalimagenode.cpp (renamed from src/quick/scenegraph/qsgdefaultimagenode.cpp)22
-rw-r--r--src/quick/scenegraph/qsgdefaultinternalimagenode_p.h (renamed from src/quick/scenegraph/qsgdefaultimagenode_p.h)10
-rw-r--r--src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp (renamed from src/quick/scenegraph/qsgdefaultrectanglenode.cpp)8
-rw-r--r--src/quick/scenegraph/qsgdefaultinternalrectanglenode_p.h (renamed from src/quick/scenegraph/qsgdefaultrectanglenode_p.h)12
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp9
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext_p.h6
-rw-r--r--src/quick/scenegraph/qsgdefaultspritenode.cpp303
-rw-r--r--src/quick/scenegraph/qsgdefaultspritenode_p.h87
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp8
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp2
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/scenegraph.pri45
-rw-r--r--src/quick/scenegraph/scenegraph.qrc4
-rw-r--r--src/quick/scenegraph/shaders/sprite.frag (renamed from src/quick/items/shaders/sprite.frag)0
-rw-r--r--src/quick/scenegraph/shaders/sprite.vert (renamed from src/quick/items/shaders/sprite.vert)0
-rw-r--r--src/quick/scenegraph/shaders/sprite_core.frag (renamed from src/quick/items/shaders/sprite_core.frag)0
-rw-r--r--src/quick/scenegraph/shaders/sprite_core.vert (renamed from src/quick/items/shaders/sprite_core.vert)0
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture_p.h16
-rw-r--r--src/quick/scenegraph/util/qsgdefaultimagenode.cpp205
-rw-r--r--src/quick/scenegraph/util/qsgdefaultimagenode_p.h107
-rw-r--r--src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp136
-rw-r--r--src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h (renamed from src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h)30
-rw-r--r--src/quick/scenegraph/util/qsgdefaultpainternode.cpp5
-rw-r--r--src/quick/scenegraph/util/qsgdefaultpainternode_p.h30
-rw-r--r--src/quick/scenegraph/util/qsgdefaultrectanglenode.cpp95
-rw-r--r--src/quick/scenegraph/util/qsgdefaultrectanglenode_p.h79
-rw-r--r--src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h2
-rw-r--r--src/quick/scenegraph/util/qsgengine.cpp63
-rw-r--r--src/quick/scenegraph/util/qsgengine.h6
-rw-r--r--src/quick/scenegraph/util/qsgflatcolormaterial.cpp3
-rw-r--r--src/quick/scenegraph/util/qsgflatcolormaterial.h6
-rw-r--r--src/quick/scenegraph/util/qsgimagenode.cpp190
-rw-r--r--src/quick/scenegraph/util/qsgimagenode.h88
-rw-r--r--src/quick/scenegraph/util/qsgninepatchnode.cpp77
-rw-r--r--src/quick/scenegraph/util/qsgninepatchnode.h62
-rw-r--r--src/quick/scenegraph/util/qsgrectanglenode.cpp86
-rw-r--r--src/quick/scenegraph/util/qsgrectanglenode.h (renamed from src/qml/jsruntime/qv4debugging.cpp)36
-rw-r--r--src/quick/scenegraph/util/qsgshadersourcebuilder.cpp11
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.h4
-rw-r--r--src/quick/scenegraph/util/qsgsimplerectnode.cpp6
-rw-r--r--src/quick/scenegraph/util/qsgsimpletexturenode.cpp7
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgtexture_p.h10
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp2
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.h10
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial_p.h10
-rw-r--r--src/quick/scenegraph/util/qsgvertexcolormaterial.cpp3
-rw-r--r--src/quick/scenegraph/util/qsgvertexcolormaterial.h6
-rw-r--r--src/quick/util/qquickanimation.cpp12
-rw-r--r--src/quick/util/qquickanimation_p.h32
-rw-r--r--src/quick/util/qquickanimation_p_p.h30
-rw-r--r--src/quick/util/qquickanimationcontroller.cpp4
-rw-r--r--src/quick/util/qquickanimationcontroller_p.h4
-rw-r--r--src/quick/util/qquickanimator_p.h28
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp268
-rw-r--r--src/quick/util/qquickanimatorcontroller_p.h48
-rw-r--r--src/quick/util/qquickanimatorjob.cpp413
-rw-r--r--src/quick/util/qquickanimatorjob_p.h102
-rw-r--r--src/quick/util/qquickapplication.cpp34
-rw-r--r--src/quick/util/qquickapplication_p.h9
-rw-r--r--src/quick/util/qquickbehavior.cpp8
-rw-r--r--src/quick/util/qquickbehavior_p.h4
-rw-r--r--src/quick/util/qquickfontloader.cpp4
-rw-r--r--src/quick/util/qquickimageprovider.h4
-rw-r--r--src/quick/util/qquickpath.cpp22
-rw-r--r--src/quick/util/qquickpath_p.h39
-rw-r--r--src/quick/util/qquickpixmapcache.cpp8
-rw-r--r--src/quick/util/qquickpixmapcache_p.h8
-rw-r--r--src/quick/util/qquickprofiler.cpp9
-rw-r--r--src/quick/util/qquickprofiler_p.h104
-rw-r--r--src/quick/util/qquickpropertychanges.cpp63
-rw-r--r--src/quick/util/qquickpropertychanges_p.h6
-rw-r--r--src/quick/util/qquickshortcut.cpp2
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp14
-rw-r--r--src/quick/util/qquicksmoothedanimation_p.h8
-rw-r--r--src/quick/util/qquicksmoothedanimation_p_p.h8
-rw-r--r--src/quick/util/qquickspringanimation.cpp12
-rw-r--r--src/quick/util/qquickspringanimation_p.h4
-rw-r--r--src/quick/util/qquickstate.cpp4
-rw-r--r--src/quick/util/qquickstatechangescript_p.h6
-rw-r--r--src/quick/util/qquickstategroup_p.h4
-rw-r--r--src/quick/util/qquickstyledtext.cpp18
-rw-r--r--src/quick/util/qquickstyledtext_p.h3
-rw-r--r--src/quick/util/qquicktimeline.cpp2
-rw-r--r--src/quick/util/qquicktimeline_p_p.h8
-rw-r--r--src/quick/util/qquicktransition.cpp4
-rw-r--r--src/quick/util/qquicktransitionmanager.cpp16
-rw-r--r--src/quick/util/qquickvaluetypes.cpp72
-rw-r--r--src/quick/util/qquickvaluetypes_p.h18
-rw-r--r--src/quick/util/util.pri3
-rw-r--r--src/quickwidgets/qquickwidget.cpp206
-rw-r--r--src/quickwidgets/qquickwidget_p.h12
-rw-r--r--src/quickwidgets/quickwidgets.pro2
-rw-r--r--src/src.pro12
-rw-r--r--tests/auto/auto.pro5
-rw-r--r--tests/auto/particles/particles.pro3
-rw-r--r--tests/auto/particles/qquickage/tst_qquickage.cpp8
-rw-r--r--tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp2
-rw-r--r--tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp2
-rw-r--r--tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp4
-rw-r--r--tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp2
-rw-r--r--tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp4
-rw-r--r--tests/auto/particles/qquickfriction/tst_qquickfriction.cpp6
-rw-r--r--tests/auto/particles/qquickgravity/tst_qquickgravity.cpp2
-rw-r--r--tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp2
-rw-r--r--tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp12
-rw-r--r--tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp2
-rw-r--r--tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp4
-rw-r--r--tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp2
-rw-r--r--tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp2
-rw-r--r--tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp2
-rw-r--r--tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp2
-rw-r--r--tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp2
-rw-r--r--tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp4
-rw-r--r--tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp2
-rw-r--r--tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp2
-rw-r--r--tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp4
-rw-r--r--tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp2
-rw-r--r--tests/auto/particles/qquickwander/tst_qquickwander.cpp2
-rw-r--r--tests/auto/qml/debugger/debugger.pro4
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp7
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp41
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp4
-rw-r--r--tests/auto/qml/debugger/shared/debugutil_p.h2
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp133
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp14
-rw-r--r--tests/auto/qml/qml.pro12
-rw-r--r--tests/auto/qml/qmldiskcache/qmldiskcache.pro9
-rw-r--r--tests/auto/qml/qmldiskcache/test.qml4
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp562
-rw-r--r--tests/auto/qml/qqmlconsole/data/categorized_logging.qml65
-rw-r--r--tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp36
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml3
-rw-r--r--tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp197
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp11
-rw-r--r--tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp6
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.12.qml15
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.13.qml16
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.14.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.14.qml17
-rw-r--r--tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml2
-rw-r--r--tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/cppnamespace.qml1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp6
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h35
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp61
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp16
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp113
-rw-r--r--tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp271
-rw-r--r--tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp35
-rw-r--r--tests/auto/qml/qqmlqt/data/exit.qml7
-rw-r--r--tests/auto/qml/qqmlqt/data/timeRoundtrip.qml8
-rw-r--r--tests/auto/qml/qqmlqt/tst_qqmlqt.cpp127
-rw-r--r--tests/auto/qml/qqmlsqldatabase/data/nullvalues.js24
-rw-r--r--tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp3
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp17
-rw-r--r--tests/auto/qml/qqmltypeloader/data/MyComponent.qml11
-rw-r--r--tests/auto/qml/qqmltypeloader/data/MyComponent2.qml7
-rw-r--r--tests/auto/qml/qqmltypeloader/data/MyComponent3.qml9
-rw-r--r--tests/auto/qml/qqmltypeloader/data/trim_cache2.qml13
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp30
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/color_read.qml6
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml8
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml8
-rw-r--r--tests/auto/qml/qqmlvaluetypes/testtypes.h6
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp33
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect17
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml68
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply3
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp21
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp10
-rw-r--r--tests/auto/qml/qv4mm/qv4mm.pro8
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp58
-rw-r--r--tests/auto/qmldevtools/compile/compile.pro2
-rw-r--r--tests/auto/qmldevtools/qmldevtools.pro6
-rw-r--r--tests/auto/qmltest-blacklist/animators/Box.qml (renamed from tests/auto/qmltest/animators/Box.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_behavior.qml (renamed from tests/auto/qmltest/animators/tst_behavior.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_mixed.qml (renamed from tests/auto/qmltest/animators/tst_mixed.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_mixedparallel.qml (renamed from tests/auto/qmltest/animators/tst_mixedparallel.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_mixedsequential.qml (renamed from tests/auto/qmltest/animators/tst_mixedsequential.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_multiwindow.qml (renamed from tests/auto/qmltest/animators/tst_multiwindow.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_nested.qml (renamed from tests/auto/qmltest/animators/tst_nested.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_on.qml (renamed from tests/auto/qmltest/animators/tst_on.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_opacity.qml (renamed from tests/auto/qmltest/animators/tst_opacity.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_parallel.qml (renamed from tests/auto/qmltest/animators/tst_parallel.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_restart.qml (renamed from tests/auto/qmltest/animators/tst_restart.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_rotation.qml (renamed from tests/auto/qmltest/animators/tst_rotation.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_scale.qml (renamed from tests/auto/qmltest/animators/tst_scale.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_sequential.qml (renamed from tests/auto/qmltest/animators/tst_sequential.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_targetdestroyed.qml (renamed from tests/auto/qmltest/animators/tst_targetdestroyed.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_transformorigin.qml (renamed from tests/auto/qmltest/animators/tst_transformorigin.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_transition.qml (renamed from tests/auto/qmltest/animators/tst_transition.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_x.qml (renamed from tests/auto/qmltest/animators/tst_x.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_y.qml (renamed from tests/auto/qmltest/animators/tst_y.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/animators/tst_zeroduration.qml (renamed from tests/auto/qmltest/animators/tst_zeroduration.qml)0
-rw-r--r--tests/auto/qmltest-blacklist/item/tst_layerInPositioner.qml (renamed from tests/auto/qmltest/item/tst_layerInPositioner.qml)0
-rw-r--r--tests/auto/qmltest/BLACKLIST6
-rw-r--r--tests/auto/qmltest/events/tst_events.qml16
-rw-r--r--tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml4
-rw-r--r--tests/auto/qmltest/listview/tst_listview.qml6
-rw-r--r--tests/auto/qmltest/qmltest.pro4
-rw-r--r--tests/auto/qmltest/selftests/tst_tryVerify.qml72
-rw-r--r--tests/auto/qmltest/statemachine/tst_signaltransition.qml76
-rw-r--r--tests/auto/qmltest/text/tst_text.qml3
-rw-r--r--tests/auto/qmltest/textinput/tst_textinput.qml1
-rw-r--r--tests/auto/qmltest/window/tst_clickwindow.qml2
-rw-r--r--tests/auto/quick/drawingmodes/data/DrawingModes.qml14
-rw-r--r--tests/auto/quick/drawingmodes/drawingmodes.pro17
-rw-r--r--tests/auto/quick/drawingmodes/tst_drawingmodes.cpp340
-rw-r--r--tests/auto/quick/nokeywords/tst_nokeywords.cpp4
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/img100x100.pngbin0 -> 238 bytes
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/img50x50.pngbin0 -> 135 bytes
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml46
-rw-r--r--tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp39
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml4
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml1
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_image.qml1
-rw-r--r--tests/auto/quick/qquickflickable/data/contentXY.qml6
-rw-r--r--tests/auto/quick/qquickflickable/data/ratios_smallContent.qml19
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp49
-rw-r--r--tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp4
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp24
-rw-r--r--tests/auto/quick/qquickitem2/data/layoutmirroring_window.qml7
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp281
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml55
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml53
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml12
-rw-r--r--tests/auto/quick/qquicklistview/BLACKLIST3
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp51
-rw-r--r--tests/auto/quick/qquickloader/data/qmldir1
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp6
-rw-r--r--tests/auto/quick/qquickmousearea/data/qtbug54019.qml21
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp327
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml41
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp59
-rw-r--r--tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp2
-rw-r--r--tests/auto/quick/qquickpathview/data/qtbug37815.qml77
-rw-r--r--tests/auto/quick/qquickpathview/data/qtbug53464.qml77
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp50
-rw-r--r--tests/auto/quick/qquickpincharea/data/pinchproperties.qml2
-rw-r--r--tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp66
-rw-r--r--tests/auto/quick/qquickscreen/data/screen.qml14
-rw-r--r--tests/auto/quick/qquickscreen/tst_qquickscreen.cpp40
-rw-r--r--tests/auto/quick/qquickshadereffect/data/MyIcon.qml76
-rw-r--r--tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml61
-rw-r--r--tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp71
-rw-r--r--tests/auto/quick/qquicktext/BLACKLIST2
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp11
-rw-r--r--tests/auto/quick/qquicktextinput/data/focusOnlyOneOnPress.qml32
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp76
-rw-r--r--tests/auto/quick/qquickview/tst_qquickview.cpp33
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp7
-rw-r--r--tests/auto/quick/qquickwindow/data/windowWithScreen.qml10
-rw-r--r--tests/auto/quick/qquickwindow/qquickwindow.pro2
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp262
-rw-r--r--tests/auto/quick/quick.pro7
-rw-r--r--tests/auto/quick/rendernode/tst_rendernode.cpp16
-rw-r--r--tests/auto/quick/scenegraph/tst_scenegraph.cpp47
-rw-r--r--tests/auto/quick/touchmouse/data/touchpointdeliveryorder.qml39
-rw-r--r--tests/auto/quick/touchmouse/touchmouse.pro2
-rw-r--r--tests/auto/quick/touchmouse/tst_touchmouse.cpp188
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp36
-rw-r--r--tests/auto/shared/util.cpp11
-rw-r--r--tests/auto/shared/util.h5
-rw-r--r--tests/benchmarks/benchmarks.pro4
-rw-r--r--tests/benchmarks/particles/affectors/tst_affectors.cpp4
-rw-r--r--tests/benchmarks/particles/emission/tst_emission.cpp2
-rw-r--r--tests/benchmarks/qml/animation/tst_animation.cpp4
-rw-r--r--tests/benchmarks/qml/creation/creation.pro2
-rw-r--r--tests/benchmarks/qml/creation/tst_creation.cpp57
-rw-r--r--tests/benchmarks/qml/librarymetrics_performance/tst_librarymetrics_performance.cpp147
-rw-r--r--tests/benchmarks/qml/qml.pro6
-rw-r--r--tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro10
-rw-r--r--tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp60
-rw-r--r--tests/benchmarks/qml/qqmlimage/image.pngbin611 -> 0 bytes
-rw-r--r--tests/benchmarks/qml/qqmlimage/qqmlimage.pro11
-rw-r--r--tests/benchmarks/qml/qqmlimage/tst_qqmlimage.cpp95
-rw-r--r--tests/manual/highdpi/imageprovider.cpp2
-rw-r--r--tests/manual/nodetypes/Effects.qml39
-rw-r--r--tests/manual/qmlplugindump/tst_qmlplugindump.cpp11
-rw-r--r--tests/manual/scenegraph_lancelot/scenegrabber/main.cpp6
-rw-r--r--tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp6
m---------tests/manual/v4/test2620
-rw-r--r--tools/fdegen/fdegen.pro8
-rw-r--r--tools/fdegen/main.cpp362
-rw-r--r--tools/qml/main.cpp27
-rw-r--r--tools/qml/qml.pro2
-rw-r--r--tools/qmleasing/mainwindow.cpp3
-rw-r--r--tools/qmleasing/splineeditor.cpp21
-rw-r--r--tools/qmlimportscanner/main.cpp104
-rw-r--r--tools/qmljs/qmljs.cpp20
-rw-r--r--tools/qmllint/main.cpp9
-rw-r--r--tools/qmlmin/main.cpp2
-rw-r--r--tools/qmlplugindump/main.cpp134
-rw-r--r--tools/qmlplugindump/qmlplugindump.pro2
-rw-r--r--tools/qmlplugindump/qmlstreamwriter.cpp2
-rw-r--r--tools/qmlplugindump/qmltypereader.cpp2
-rw-r--r--tools/qmlprofiler/commandlistener.h2
-rw-r--r--tools/qmlprofiler/main.cpp6
-rw-r--r--tools/qmlprofiler/qmlprofilerapplication.cpp38
-rw-r--r--tools/qmlprofiler/qmlprofilerapplication.h11
-rw-r--r--tools/qmlprofiler/qmlprofilerdata.cpp18
-rw-r--r--tools/qmlprofiler/qmlprofilerdata.h11
-rw-r--r--tools/qmlscene/main.cpp17
-rw-r--r--tools/qmlscene/qmlscene.pro3
-rw-r--r--tools/tools.pro2
962 files changed, 31852 insertions, 17768 deletions
diff --git a/.gitignore b/.gitignore
index f33da3c8b3..da9552c8e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,12 +4,17 @@
config.tests/*/*/*
!config.tests/*/*/*[.]*
config.tests/*/*/*[.]app
+config.log
callgrind.out.*
pcviewer.cfg
*~
*.a
*.la
+*_wrapper.sh
+*_wrapper.bat
+wrapper.sh
+wrapper.bat
*.core
*.moc
*.o
@@ -284,3 +289,7 @@ src/qml/udis86_itab.h
# Generated HLSL bytecode headers
*.hlslh
+
+# Compiled QML/JS code
+*.qmlc
+*.jsc
diff --git a/.qmake.conf b/.qmake.conf
index 0957f58c52..f03d05c7ac 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,5 +1,4 @@
load(qt_build_config)
-CONFIG += qt_example_installs
CONFIG += warning_clean
-MODULE_VERSION = 5.8.0
+MODULE_VERSION = 5.9.0
diff --git a/LICENSE.GPLv3 b/LICENSE.GPLv3
index 4e49b122ae..71c4ad49c3 100644
--- a/LICENSE.GPLv3
+++ b/LICENSE.GPLv3
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 3. That license references
the General Public License version 3, that is displayed below. Other
portions of the Qt Toolkit may be licensed directly under this license.
diff --git a/LICENSE.LGPLv21 b/LICENSE.LGPLv21
index 6e18461125..dfcab5e29b 100644
--- a/LICENSE.LGPLv21
+++ b/LICENSE.LGPLv21
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 2.1, which is displayed below.
-------------------------------------------------------------------------
diff --git a/LICENSE.LGPLv3 b/LICENSE.LGPLv3
index 4d67bac0b4..6bf924cd15 100644
--- a/LICENSE.LGPLv3
+++ b/LICENSE.LGPLv3
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 3, which is displayed below.
This license makes reference to the version 3 of the GNU General
Public License, which you can find in the LICENSE.GPLv3 file.
diff --git a/bin/rename-qtdeclarative-symbols.sh b/bin/rename-qtdeclarative-symbols.sh
deleted file mode 100755
index 3b82989fa5..0000000000
--- a/bin/rename-qtdeclarative-symbols.sh
+++ /dev/null
@@ -1,642 +0,0 @@
-#!/bin/sh
-#############################################################################
-##
-## Copyright (C) 2016 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$
-##
-#############################################################################
-
-# Replaces deprecated QDeclarative symbol names with their replacements
-#
-# Changes instances in all regular files under the specified directory;
-# use on a clean source tree!
-
-if [ "$#" -lt "1" ]
-then
- echo " Usage: $0 <directory>"
- exit 1;
-fi
-
-MODIFY_DIR="$1"
-
-QML_SYMBOLS="\
- QDeclarativeAbstractBinding
- QDeclarativeAbstractBoundSignal
- QDeclarativeAbstractExpression
- QDeclarativeAccessible
- QDeclarativeAccessors
- QDeclarativeAccessorProperties
- QDeclarativeAnimationTimer
- QDeclarativeAssociationList
- QDeclarativeAttachedPropertiesFunc
- QDeclarativeBinding
- QDeclarativeBindingPrivate
- QDeclarativeBindingProfiler
- QDeclarativeBoundSignal
- QDeclarativeBoundSignalParameters
- QDeclarativeBoundSignalProxy
- QDeclarativeBuiltinFunctions
- QDeclarativeCleanup
- QDeclarativeColorValueType
- QDeclarativeCompiledData
- QDeclarativeCompiler
- QDeclarativeCompilerTypes
- QDeclarativeCompilingProfiler
- QDeclarativeComponent
- QDeclarativeComponentAttached
- QDeclarativeComponentExtension
- QDeclarativeComponentPrivate
- QDeclarativeComponent_setQmlParent
- QDeclarativeCompositeTypeData
- QDeclarativeConnectionsParser
- QDeclarativeContext
- QDeclarativeContextData
- QDeclarativeContextPrivate
- QDeclarativeCustomParser
- QDeclarativeCustomParserNode
- QDeclarativeCustomParserNodePrivate
- QDeclarativeCustomParserProperty
- QDeclarativeCustomParserPropertyPrivate
- QDeclarativeData
- QDeclarativeDataBlob
- QDeclarativeDataExtended
- QDeclarativeDataLoader
- QDeclarativeDataLoaderNetworkReplyProxy
- QDeclarativeDataLoaderThread
- QDeclarativeDateExtension
- QDeclarativeDataTest
- QDeclarativeDebug
- QDeclarativeDebugClient
- QDeclarativeDebugClientPrivate
- QDeclarativeDebugConnection
- QDeclarativeDebugConnectionPrivate
- QDeclarativeDebugContextReference
- QDeclarativeDebugData
- QDeclarativeDebugEngineReference
- QDeclarativeDebugEnginesQuery
- QDeclarativeDebugExpressionQuery
- QDeclarativeDebugFileReference
- QDeclarativeDebugger
- QDeclarativeDebuggingEnabler
- QDeclarativeDebugHelper
- QDeclarativeDebugObjectExpressionWatch
- QDeclarativeDebugObjectQuery
- QDeclarativeDebugObjectReference
- QDeclarativeDebugPropertyReference
- QDeclarativeDebugPropertyWatch
- QDeclarativeDebugQuery
- QDeclarativeDebugRootContextQuery
- QDeclarativeDebugServer
- QDeclarativeDebugServerConnection
- QDeclarativeDebugServerPrivate
- QDeclarativeDebugServerThread
- QDeclarativeDebugService
- QDeclarativeDebugServicePrivate
- QDeclarativeDebugStatesDelegate
- QDeclarativeDebugTrace
- QDeclarativeDebugWatch
- QDeclarativeDelayedError
- QDeclarativeDirComponents
- QDeclarativeDirParser
- QDeclarativeDirScripts
- QDeclarativeDOMNodeResource
- QDeclarativeEasingValueType
- QDeclarativeElement
- QDeclarativeEngine
- QDeclarativeEngineDebug
- QDeclarativeEngineDebugClient
- QDeclarativeEngineDebugService
- QDeclarativeEngineDebugPrivate
- QDeclarativeEnginePrivate
- QDeclarativeError
- QDeclarativeErrorPrivate
- QDeclarativeExpression
- QDeclarativeExpressionPrivate
- QDeclarativeExtensionInterface
- QDeclarativeExtensionPlugin
- QDeclarativeFontValueType
- QDeclarativeGraphics_DerivedObject
- QDeclarativeGuard
- QDeclarativeGuardedContextData
- QDeclarativeGuardImpl
- QDeclarativeHandlingSignalProfiler
- QDeclarativeImportDatabase
- QDeclarativeImportedNamespace
- QDeclarativeImports
- QDeclarativeImportsPrivate
- QDeclarativeIncubationController
- QDeclarativeIncubator
- QDeclarativeIncubatorController
- QDeclarativeIncubatorPrivate
- QDeclarativeIncubators
- QDeclarativeInfo
- QDeclarativeInfoPrivate
- QDeclarativeInspector
- QDeclarativeInspectorInterface
- QDeclarativeInspectorService
- QDeclarativeInstruction
- QDeclarativeInstructionData
- QDeclarativeInstructionMeta
- QDeclarativeIntegerCache
- QDeclarativeJavaScriptExpression
- QDeclarativeJavaScriptExpressionGuard
- QDeclarativeJS
- QDeclarativeJSGrammar
- QDeclarativeListProperty
- QDeclarativeListReference
- QDeclarativeListReferencePrivate
- QDeclarativeLocale
- QDeclarativeLocalStoragePlugin
- QDeclarativeMatrix4x4ValueType
- QDeclarativeMetaType
- QDeclarativeMetaTypeData
- QDeclarativeNetworkAccessManagerFactory
- QDeclarativeNotifier
- QDeclarativeNotifierEndpoint
- QDeclarativeNullableValue
- QDeclarativeNumberExtension
- QDeclarativeObjectCreatingProfiler
- QDeclarativeObjectData
- QDeclarativeObjectProperty
- QDeclarativeObserverMode
- QDeclarativeOpenMetaObject
- QDeclarativeOpenMetaObjectPrivate
- QDeclarativeOpenMetaObjectType
- QDeclarativeOpenMetaObjectTypePrivate
- QDeclarativeParser
- QDeclarativeParserStatus
- QDeclarativePointFValueType
- QDeclarativePointValueType
- QDeclarativePool
- QDeclarativePrivate
- QDeclarativeProfilerData
- QDeclarativeProfilerService
- QDeclarativeProperties
- QDeclarativeProperty
- QDeclarativePropertyCache
- QDeclarativePropertyCacheMethodArguments
- QDeclarativePropertyData
- QDeclarativePropertyMap
- QDeclarativePropertyMapMetaObject
- QDeclarativePropertyMapPrivate
- QDeclarativePropertyPrivate
- QDeclarativePropertyRawData
- QDeclarativePropertyValueInterceptor
- QDeclarativePropertyValueSource
- QDeclarativeProxyMetaObject
- QDeclarativeQmldirData
- QDeclarativeQtQuick1Module
- QDeclarativeQtQuick2Module
- QDeclarativeQtQuick2DebugStatesDelegate
- QDeclarativeQuaternionValueType
- QDeclarativeRectFValueType
- QDeclarativeRectValueType
- QDeclarativeRefCount
- QDeclarativeRefPointer
- QDeclarativeRegisterType
- QDeclarativeRewrite
- QDeclarativeScript
- QDeclarativeScriptBlob
- QDeclarativeScriptData
- QDeclarativeScriptPrivate
- QDeclarativeScriptString
- QDeclarativeScriptStringPrivate
- QDeclarativeSizeFValueType
- QDeclarativeSizeValueType
- QDeclarativeSqlDatabaseData
- QDeclarativeStringConverters
- QDeclarativeThread
- QDeclarativeThreadPrivate
- QDeclarativeTrace
- QDeclarativeType
- QDeclarativeTypeData
- QDeclarativeTypeInfo
- QDeclarativeTypeLoader
- QDeclarativeTypeModule
- QDeclarativeTypeModulePrivate
- QDeclarativeTypeModuleVersion
- QDeclarativeTypeNameCache
- QDeclarativeTypeNotAvailable
- QDeclarativeTypePrivate
- QDeclarativeTypesExtensionInterface
- QDeclarativeV8Function
- QDeclarativeV8Handle
- QDeclarativeValueType
- QDeclarativeValueTypeProxyBinding
- QDeclarativeValueTypeFactory
- QDeclarativeVector2DValueType
- QDeclarativeVector3DValueType
- QDeclarativeVector4DValueType
- QDeclarativeVME
- QDeclarativeVMEGuard
- QDeclarativeVMEMetaData
- QDeclarativeVMEMetaObject
- QDeclarativeVMEMetaObjectEndpoint
- QDeclarativeVMEVariant
- QDeclarativeVMETypes
- QDeclarativeWatcher
- QDeclarativeWatchProxy
- QDeclarativeXMLHttpRequest
- QDeclarativeXMLHttpRequestData
- QDeclarative_isFileCaseCorrect
- QDeclarative_setParent_noEvent
- QQuickProperties
- QQuickPropertyCacheMethodArguments
- QQuickPropertyData
-"
-
-QUICK_SYMBOLS="\
- QDeclarativeAbstractAnimation
- QDeclarativeAbstractAnimationAction
- QDeclarativeAbstractAnimationPrivate
- QDeclarativeAction
- QDeclarativeActionEvent
- QDeclarativeAnchors
- QDeclarativeAnimationController
- QDeclarativeAnimationControllerPrivate
- QDeclarativeAnimationGroup
- QDeclarativeAnimationGroupPrivate
- QDeclarativeAnimationPropertyUpdater
- QDeclarativeApplication
- QDeclarativeApplicationPrivate
- QDeclarativeBehavior
- QDeclarativeBehaviorPrivate
- QDeclarativeBind
- QDeclarativeBindPrivate
- QDeclarativeBulkValueAnimator
- QDeclarativeBulkValueUpdater
- QDeclarativeCachedBezier
- QDeclarativeChangeSet
- QDeclarativeColorAnimation
- QDeclarativeConnections
- QDeclarativeConnectionsPrivate
- QDeclarativeCurve
- QDeclarativeDefaultTextureFactory
- QDeclarativeFlick
- QDeclarativeFocusPanel
- QDeclarativeFolderListModel
- QDeclarativeFolderListModelPrivate
- QDeclarativeFontLoader
- QDeclarativeFontLoaderPrivate
- QDeclarativeFontObject
- QDeclarativeGestureArea
- QDeclarativeGestureAreaParser
- QDeclarativeGestureAreaPrivate
- QDeclarativeGraphics
- QDeclarativeImageProvider
- QDeclarativeImageProviderPrivate
- QDeclarativeItem
- QDeclarativeItemAccessor
- QDeclarativeItemChangeListener
- QDeclarativeItemKeyFilter
- QDeclarativeItemPrivate
- QDeclarativeListAccessor
- QDeclarativeListCompositor
- QDeclarativeListElement
- QDeclarativeListModel
- QDeclarativeListModelParser
- QDeclarativeListModelWorkerAgent
- QDeclarativeListView
- QDeclarativeNumberAnimation
- QDeclarativePackage
- QDeclarativePackageAttached
- QDeclarativePackagePrivate
- QDeclarativeParallelAnimation
- QDeclarativeParticle
- QDeclarativeParticleMotion
- QDeclarativeParticleMotionGravity
- QDeclarativeParticleMotionLinear
- QDeclarativeParticleMotionWander
- QDeclarativeParticles
- QDeclarativeParticlesPainter
- QDeclarativeParticlesPrivate
- QDeclarativePath
- QDeclarativePathArc
- QDeclarativePathAttribute
- QDeclarativePathCatmullRomCurve
- QDeclarativePathCubic
- QDeclarativePathCurve
- QDeclarativePathData
- QDeclarativePathElement
- QDeclarativePathInterpolator
- QDeclarativePathLine
- QDeclarativePathPercent
- QDeclarativePathPrivate
- QDeclarativePathQuad
- QDeclarativePathSvg
- QDeclarativePauseAnimation
- QDeclarativePauseAnimationPrivate
- QDeclarativePixmap
- QDeclarativePixmapData
- QDeclarativePixmapKey
- QDeclarativePixmapNull
- QDeclarativePixmapReader
- QDeclarativePixmapReaderThreadObject
- QDeclarativePixmapReply
- QDeclarativePixmapStore
- QDeclarativePropertyAction
- QDeclarativePropertyActionPrivate
- QDeclarativePropertyAnimation
- QDeclarativePropertyAnimationPrivate
- QDeclarativePropertyChanges
- QDeclarativePropertyChangesParser
- QDeclarativePropertyChangesPrivate
- QDeclarativeReplaceSignalHandler
- QDeclarativeRevertAction
- QDeclarativeRotationAnimation
- QDeclarativeRotationAnimationPrivate
- QDeclarativeSequentialAnimation
- QDeclarativeScriptAction
- QDeclarativeScriptActionPrivate
- QDeclarativeSetPropertyAnimationAction
- QDeclarativeSimpleAction
- QDeclarativeSmoothedAnimation
- QDeclarativeSmoothedAnimationPrivate
- QDeclarativeSpringAnimation
- QDeclarativeSpringAnimationPrivate
- QDeclarativeState
- QDeclarativeStateActions
- QDeclarativeStateChange
- QDeclarativeStateChangeScript
- QDeclarativeStateChangeScriptPrivate
- QDeclarativeStateGroup
- QDeclarativeStateGroupPrivate
- QDeclarativeStateOperation
- QDeclarativeStateOperationPrivate
- QDeclarativeStatePrivate
- QDeclarativeStyledText
- QDeclarativeStyledTextImgTag
- QDeclarativeStyledTextPrivate
- QDeclarativeSystemPalette
- QDeclarativeSystemPalettePrivate
- QDeclarativeTextureFactory
- QDeclarativeTimeLine
- QDeclarativeTimeLineCallback
- QDeclarativeTimeLineObject
- QDeclarativeTimeLinePrivate
- QDeclarativeTimeLineValue
- QDeclarativeTimeLineValueProxy
- QDeclarativeTimeLineValues
- QDeclarativeTimer
- QDeclarativeTimerPrivate
- QDeclarativeTransition
- QDeclarativeTransitionInstance
- QDeclarativeTransitionManager
- QDeclarativeTransitionManagerPrivate
- QDeclarativeTransitionPrivate
- QDeclarativeUtilModule
- QDeclarativeVector3dAnimation
- QDeclarativeView
- QDeclarativeViewInspector
- QDeclarativeViewInspectorPrivate
- QDeclarativeViewPrivate
- QDeclarativeWebView
- QDeclarativeXmlListModel
- QDeclarativeXmlListModelPrivate
- QDeclarativeXmlListModelRole
- QDeclarativeXmlListRange
- QDeclarativeXmlQueryEngine
- QDeclarativeXmlQueryResult
- QDeclarativeXmlQueryThreadObject
- QDeclarativeXmlRoleList
- QDeclarativeSvgParser
- QDeclarativeWorkerScript
- QDeclarativeWorkerScriptEngine
- QDeclarativeWorkerScriptEnginePrivate
-"
-
-QML_INCLUDE_FILES="\
- qdeclarativeaccessible.h
- qdeclarativeaccessors_p.h
- qdeclarativebinding_p.h
- qdeclarativebinding_p_p.h
- qdeclarativeboundsignal_p.h
- qdeclarativebuiltinfunctions_p.h
- qdeclarativecleanup_p.h
- qdeclarativecompiler_p.h
- qdeclarativecomponentattached_p.h
- qdeclarativecomponent.h
- qdeclarativecomponent_p.h
- qdeclarativecontext.h
- qdeclarativecontext_p.h
- qdeclarativecustomparser_p.h
- qdeclarativecustomparser_p_p.h
- qdeclarativedata_p.h
- qdeclarativedebugclient_p.h
- qdeclarativedebug.h
- qdeclarativedebughelper_p.h
- qdeclarativedebugserverconnection_p.h
- qdeclarativedebugserver_p.h
- qdeclarativedebugservice_p.h
- qdeclarativedebugservice_p_p.h
- qdeclarativedebugstatesdelegate_p.h
- qdeclarativedebugtrace_p.h
- qdeclarativedirparser_p.h
- qdeclarativeenginedebug_p.h
- qdeclarativeenginedebugservice_p.h
- qdeclarativeengine.h
- qdeclarativeengine_p.h
- qdeclarativeerror.h
- qdeclarativeexpression.h
- qdeclarativeexpression_p.h
- qdeclarativeextensioninterface.h
- qdeclarativeextensionplugin.h
- qdeclarativeglobal_p.h
- qdeclarativeguard_p.h
- qdeclarative.h
- qdeclarativeimageprovider.h
- qdeclarativeimport_p.h
- qdeclarativeincubator.h
- qdeclarativeincubator_p.h
- qdeclarativeinfo.h
- qdeclarativeinspectorinterface_p.h
- qdeclarativeinspectorprotocol.h
- qdeclarativeinspectorservice_p.h
- qdeclarativeinstruction_p.h
- qdeclarativeintegercache_p.h
- qdeclarativejsastfwd_p.h
- qdeclarativejsast_p.h
- qdeclarativejsastvisitor_p.h
- qdeclarativejsengine_p.h
- qdeclarativejsglobal_p.h
- qdeclarativejsgrammar_p.h
- qdeclarativejskeywords_p.h
- qdeclarativejslexer_p.h
- qdeclarativejsmemorypool_p.h
- qdeclarativejsparser_p.h
- qdeclarativelist.h
- qdeclarativelist_p.h
- qdeclarativelocale_p.h
- qdeclarativemetatype_p.h
- qdeclarativenetworkaccessmanagerfactory.h
- qdeclarativenotifier_p.h
- qdeclarativenullablevalue_p_p.h
- qdeclarativeopenmetaobject_p.h
- qdeclarativeparserstatus.h
- qdeclarativepool_p.h
- qdeclarativeprivate.h
- qdeclarativeprofilerservice_p.h
- qdeclarativepropertycache_p.h
- qdeclarativeproperty.h
- qdeclarativepropertymap.h
- qdeclarativeproperty_p.h
- qdeclarativepropertyvalueinterceptor_p.h
- qdeclarativepropertyvaluesource.h
- qdeclarativeproxymetaobject_p.h
- qdeclarativerefcount_p.h
- qdeclarativerewrite_p.h
- qdeclarativescript_p.h
- qdeclarativescriptstring.h
- qdeclarativescriptstring_p.h
- qdeclarativesqldatabase_p.h
- qdeclarativestringconverters_p.h
- qdeclarativethread_p.h
- qdeclarativetrace_p.h
- qdeclarativetypeloader_p.h
- qdeclarativetypenamecache_p.h
- qdeclarativetypenotavailable_p.h
- qdeclarativevaluetype_p.h
- qdeclarativevmemetaobject_p.h
- qdeclarativevme_p.h
- qdeclarativewatcher_p.h
- qdeclarativexmlhttprequest_p.h
- qdeclarativexmllistmodel_p.h
-"
-
-QUICK_INCLUDE_FILES="\
- qdeclarativeanimation_p.h
- qdeclarativeanimation_p_p.h
- qdeclarativeanimationcontroller_p.h
- qdeclarativeapplication_p.h
- qdeclarativebehavior_p.h
- qdeclarativebind_p.h
- qdeclarativechangeset_p.h
- qdeclarativeconnections_p.h
- qdeclarativefolderlistmodel.h
- qdeclarativefontloader_p.h
- qdeclarativelistaccessor_p.h
- qdeclarativelistcompositor_p.h
- qdeclarativelistmodel_p.h
- qdeclarativelistmodel_p_p.h
- qdeclarativelistmodelworkeragent_p.h
- qdeclarativepackage_p.h
- qdeclarativepathinterpolator_p.h
- qdeclarativepath_p.h
- qdeclarativepath_p_p.h
- qdeclarativepixmapcache_p.h
- qdeclarativepropertychanges_p.h
- qdeclarativesmoothedanimation_p.h
- qdeclarativesmoothedanimation_p_p.h
- qdeclarativespringanimation_p.h
- qdeclarativestategroup_p.h
- qdeclarativestateoperations_p.h
- qdeclarativestate_p.h
- qdeclarativestate_p_p.h
- qdeclarativestyledtext_p.h
- qdeclarativesvgparser_p.h
- qdeclarativesystempalette_p.h
- qdeclarativetimeline_p_p.h
- qdeclarativetimer_p.h
- qdeclarativetransitionmanager_p_p.h
- qdeclarativetransition_p.h
- qdeclarativeutilmodule_p.h
- qdeclarativeworkerscript_p.h
-"
-
-replaceMatch()
-{
- SYMBOL="$1"
- REPLACEMENT="$2"
- echo "Replacing $SYMBOL with $REPLACEMENT:"
-
- CONTAINERS=$(find "$MODIFY_DIR" ! -path ".git" -type f -print0 | xargs -0 grep -l -I "$SYMBOL")
- for CONTAINER in $CONTAINERS
- do
- echo " $CONTAINER"
- TMP_FILE="$CONTAINER.tmp"
-
- sed 's|'"$SYMBOL"'|'"$REPLACEMENT"'|g' <"$CONTAINER" >"$TMP_FILE"
- mv "$TMP_FILE" "$CONTAINER"
- done
- echo
-}
-
-for QML_SYMBOL in $QML_SYMBOLS
-do
- QML_REPLACEMENT="QQml${QML_SYMBOL#QDeclarative}"
- replaceMatch "\bQtDeclarative/$QML_SYMBOL\b" "QtQml/$QML_REPLACEMENT"
- replaceMatch "\b$QML_SYMBOL\b" "$QML_REPLACEMENT"
-done
-
-for QUICK_SYMBOL in $QUICK_SYMBOLS
-do
- QUICK_REPLACEMENT="QQuick${QUICK_SYMBOL#QDeclarative}"
- replaceMatch "\bQtDeclarative/$QUICK_SYMBOL\b" "QtQuick/$QUICK_REPLACEMENT"
- replaceMatch "\b$QUICK_SYMBOL\b" "$QUICK_REPLACEMENT"
-done
-
-for QML_INCLUDE_FILE in $QML_INCLUDE_FILES
-do
- QML_INCLUDE_REPLACEMENT="qqml${QML_INCLUDE_FILE#qdeclarative}"
- replaceMatch "\b$QML_INCLUDE_FILE\b" "$QML_INCLUDE_REPLACEMENT"
-done
-
-for QUICK_INCLUDE_FILE in $QUICK_INCLUDE_FILES
-do
- QUICK_INCLUDE_REPLACEMENT="qquick${QUICK_INCLUDE_FILE#qdeclarative}"
- replaceMatch "\b$QUICK_INCLUDE_FILE\b" "$QUICK_INCLUDE_REPLACEMENT"
-done
-
-# Various one-off replacements
-replaceMatch "\bQtDeclarative\b" "QtQml"
-replaceMatch "\basQDeclarativeContext\b" "asQQmlContext"
-replaceMatch "\basQDeclarativeContextPrivate\b" "asQQmlContextPrivate"
-
-# Replace any references to the 'declarative' module with 'qml'
-echo "Replacing module declarative with qml:"
-CONTAINERS=$(find "$MODIFY_DIR" \( -name \*\.pro -o -name \*\.pri \) -print0 | xargs -0 grep -l -I "\bdeclarative\b")
-for CONTAINER in $CONTAINERS
-do
- echo " $CONTAINER"
- TMP_FILE="$CONTAINER.tmp"
-
- # We only want to replace standalone 'declarative' and 'declarative-private' tokens
- sed 's|\([[:space:]]\+\)declarative\([[:space:]]\+\)|\1qml\2|g' <"$CONTAINER" | sed 's|\([[:space:]]\+\)declarative$|\1qml|g' | sed 's|\([[:space:]]\+\)declarative-private\([[:space:]]\+\)|\1qml-private\2|g' | sed 's|\([[:space:]]\+\)declarative-private$|\1qml-private|g' >"$TMP_FILE"
- mv "$TMP_FILE" "$CONTAINER"
-done
-echo
-
-echo "Replacements complete"
-exit 0
diff --git a/config.tests/d3d12/d3d12.pro b/config.tests/d3d12/d3d12.pro
index 24c5991a4b..451e7427b9 100644
--- a/config.tests/d3d12/d3d12.pro
+++ b/config.tests/d3d12/d3d12.pro
@@ -1,4 +1,4 @@
SOURCES = d3d12.cpp
CONFIG -= qt dylib
CONFIG += console
-LIBS += -ldxgi -ld3d12
+LIBS += -ldxgi -ld3d12 -ld3dcompiler -ldcomp
diff --git a/dist/changes-5.6.1 b/dist/changes-5.6.1
index 5a3c9b62e6..9506987cd3 100644
--- a/dist/changes-5.6.1
+++ b/dist/changes-5.6.1
@@ -4,7 +4,7 @@ compatibility (source and binary) with Qt 5.6.0.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
- http://qt-project.org/doc/qt-5.6
+ https://doc.qt.io/qt-5.6
The Qt version 5.6 series is binary compatible with the 5.5.x series.
Applications compiled for 5.5 will continue to run with 5.6.
@@ -12,7 +12,7 @@ Applications compiled for 5.5 will continue to run with 5.6.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
- http://bugreports.qt-project.org/
+ https://bugreports.qt.io/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
diff --git a/dist/changes-5.6.2 b/dist/changes-5.6.2
new file mode 100644
index 0000000000..57bae85ae4
--- /dev/null
+++ b/dist/changes-5.6.2
@@ -0,0 +1,80 @@
+Qt 5.6.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.6.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+ http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.6 series is binary compatible with the 5.5.x series.
+Applications compiled for 5.5 will continue to run with 5.6.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+ https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+QtQml
+-----
+
+ - [QTBUG-53412] Fix mapping of null JS values to null SQL values instead
+ of empty strings.
+ - [QTBUG-53794] Fix crash when using the "with" statement with an
+ expression that throws an exception.
+ - [QTBUG-54589] Fix assertion when deleting properties of JS objects
+ - Fix crash when incubating objects asynchronously with initial properties.
+ - Fix support for QJSValue parameters in QML signal handlers.
+ - Fix crash on 64-bit big endian architectures.
+ - Fix literal string assignments to QVector2D and QQuaternion properties.
+ - Fix crashes when using Component.onDestruction handlers.
+ - [QTBUG-49232] Fix assignment of values to quint8 properties.
+ - [QTBUG-48136] Fix QQmlPropertyMap emitting valueChanged when the value had
+ not actually changed, causing side effects such as causing fake binding loops.
+ - [QTBUG-55238] Work around miscompilations with Visual Studio 2015 Update 3
+ - [QTBUG-55482] Work around a crash in release mode with GCC 6 related to dead
+ store elimination
+
+QtQuick
+-------
+
+ - Fix QtQuick scenegraph waiting up to a full vsync duration before rendering
+ the first frame.
+ - ShaderEffect: Fix a crash when a ShaderEffect and an Image both share the
+ same texture via supportsAtlasTextures.
+ - [QTBUG-53726] Flickable: Fix widthRatio and heightRatio being incorrect when
+ the content is smaller than the view.
+ - [QTBUG-42928] MultiPointTouchArea: Fix touch points remaining pressed when
+ the MultiPointTouchArea is hidden or disabled.
+ - [QTBUG-53937] AnimatedSprite: Fix a potential infinite loop when changing
+ image source.
+ - [QTBUG-53263] ListView: Fix items not always rendering when inserting many
+ items into a model.
+ - [QTBUG-52901] Fixed QQuickPaintedItem not scaling correctly for high DPI when
+ using a renderTarget of FramebufferObject
+ - [QTBUG-52534] MouseArea: Fix drag.threshold when preventStealing is in use.
+ - QQuickWidget now properly repaints text on high-DPI screen changes.
+ - [QTBUG-54238] qt.scenegraph.info logging category got renamed to
+ qt.scenegraph.general.
+
+ - QQuickItem:
+ * [QTBUG-31861] Fixed issue with mouse button events being sent even
+ when they were disabled by setAcceptedMouseButtons.
+ * [QTBUG-40145] Fix multiple items gaining activeFocus incorrectly.
+
+ - Text:
+ * [QTBUG-54075] Fix positioning of inline images when using StyledText.
+ * [QTBUG-52389] Fixed clipping of glyphs that extend beyond font's em
+ square.
+ * Fix mouse presses being eaten when textFormat was PlainText. In this
+ case, the item cannot possibly make use of a press (as there are no
+ hyperlinks), but deprives other items of the opportunity to take the press.
+
+ - PathView:
+ * [QTBUG-53464] PathView: Fix items not being correctly created in some
+ circumstances.
+ * [QTBUG-37815] PathView: Fix infinite loop when creating items in some
+ circumstances.
+
diff --git a/dist/changes-5.7.0 b/dist/changes-5.7.0
new file mode 100644
index 0000000000..ac8c63b2ad
--- /dev/null
+++ b/dist/changes-5.7.0
@@ -0,0 +1,114 @@
+Qt 5.7 introduces many new features and improvements as well as bugfixes
+over the 5.6.x series. Also, there is a change in the licensing terms.
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+ http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.7 series is binary compatible with the 5.6.x series.
+Applications compiled for 5.6 will continue to run with 5.7.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+ https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Important License Changes *
+****************************************************************************
+
+ This module is no longer available under LGPLv2.1. The libraries are
+ now available under the following licenses:
+ * Commercial License
+ * GNU General Public License v2.0 (LICENSE.GPL2) and later
+ * GNU Lesser General Public License v3.0 (LICENSE.LGPL3)
+
+ The tools are now available under the following licenses:
+ * Commercial License
+ * GNU General Public License 3.0 (LICENSE.GPL3) with exceptions
+ described in The Qt Company GPL Exception 1.0 (LICENSE.GPL3-EXCEPT)
+
+****************************************************************************
+* Important Behavior Changes *
+****************************************************************************
+
+QtQuick
+-------
+
+ * [QTBUG-41833] QQuickItem::childAt was incorrectly including any child
+ whose right or bottom edge was adjacent to the point being checked,
+ as if it had width+1 and height+1. An Item with a width of 100
+ covers pixels from x=0..x=99, and likewise with height; so now,
+ calling childAt(100, 100) on its parent will not return it.
+
+ * [QTBUG-51115] TextEdit and TextInput now clear their selection when
+ becoming read-only.
+
+ * QtQuick.Layouts moved to the qtdeclarative repository.
+
+****************************************************************************
+* Library *
+****************************************************************************
+
+QtQml
+-----
+
+ - [QTBUG-52556] Made the QML Engine capable of locating QML sub-modules
+ from within a versioned parent module path. For example, QtQml.Models
+ 2.x can be either in QT_INSTALL_QML/QtQml/Models.2 or in
+ QT_INSTALL_QML/QtQml.2/Models.
+ - [QTBUG-36350] Added Connections::enabled property to allow toggling of the
+ signal handlers inside a Connections element.
+ - Enabled JIT for x86/x64 targets on Windows 10 and later.
+ - Enabled JIT for Aarch64.
+
+QtQuick
+-------
+
+ - Window:
+ * Added Window.window attached property, allowing access to the QQuickWindow
+ an Item belongs to.
+
+ - GridView & ListView:
+ * [QTBUG-17051] Added keyNavigationEnabled property to allow mouse and
+ keyboard interaction to be selectively enabled/disabled.
+ * Sticky headers or footers are now correctly positioned in the case of
+ an empty view.
+
+ - MouseArea:
+ * Added mouse.source property to enable distinguishing genuine mouse
+ events from those that are synthesized from touch or tablet events.
+
+ - PathView:
+ * Added PathView::movementDirection, which sets the direction in which items
+ move when setting currentIndex.
+
+ - QQuickItem:
+ * Added isAncestorOf() to determine if an item is the ancestor of another
+ item (i.e. the parent, or a parent further up the item tree).
+ * [QTBUG-28668] Added support for mapping item's coordinates to and from global
+ screen coordinates, in the form of Item::mapToGlobal() and
+ Item::mapFromGlobal().
+
+ - TextEdit/TextInput:
+ * [QTBUG-49503] Added TextEdit::preeditText & TextInput::preeditText,
+ which allow access to partial (uncommitted) text from an input method.
+ * [QTBUG-50428] Added TextEdit::clear() and TextInput::clear() which sets the
+ text to an empty string, but in addition, also clears partial (uncommitted)
+ text.
+
+ - Loader:
+ * [QTBUG-29789] Object creation previously started asynchronously can be
+ forced to complete synchronously by changing the "asynchronous" property
+ from true to false.
+
+Qt.labs.folderlistmodel
+-----------------------
+
+ - FolderListModel
+ * [QTBUG-45566] Added FolderListModel::caseSensitive, to control whether or
+ not filtering is applied case sensitively.
+
diff --git a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp
index 965e5152c1..d963b6d1b4 100644
--- a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp
+++ b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp
@@ -41,7 +41,7 @@
#include "pieslice.h"
PieChart::PieChart(QQuickItem *parent)
- : QQuickItem(parent)
+ : QQuickItem(parent), m_pieSlice(0)
{
}
diff --git a/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp b/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp
index ceb0041ec8..50c018e33e 100644
--- a/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp
+++ b/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp
@@ -42,7 +42,7 @@
#include <QPainter>
PieSlice::PieSlice(QQuickItem *parent)
- : QQuickPaintedItem(parent)
+ : QQuickPaintedItem(parent), m_fromAngle(0), m_angleSpan(0)
{
}
diff --git a/examples/quick/demos/demos.pro b/examples/quick/demos/demos.pro
index 9aac7bf6f7..0644b81a22 100644
--- a/examples/quick/demos/demos.pro
+++ b/examples/quick/demos/demos.pro
@@ -7,7 +7,5 @@ SUBDIRS = samegame \
photosurface \
stocqt
-qtHaveModule(xmlpatterns): SUBDIRS += rssnews
+qtHaveModule(xmlpatterns): SUBDIRS += rssnews photoviewer
-EXAMPLE_FILES = \
- photoviewer
diff --git a/examples/quick/demos/photosurface/main.cpp b/examples/quick/demos/photosurface/main.cpp
index 9456694032..b9d093df40 100644
--- a/examples/quick/demos/photosurface/main.cpp
+++ b/examples/quick/demos/photosurface/main.cpp
@@ -59,9 +59,11 @@ static QStringList imageNameFilters()
{
QStringList result;
QMimeDatabase mimeDatabase;
- foreach (const QByteArray &m, QImageReader::supportedMimeTypes()) {
- foreach (const QString &suffix, mimeDatabase.mimeTypeForName(m).suffixes())
- result.append(QStringLiteral("*.") + suffix);
+ const auto supportedMimeTypes = QImageReader::supportedMimeTypes();
+ for (const QByteArray &m : supportedMimeTypes) {
+ const auto suffixes = mimeDatabase.mimeTypeForName(m).suffixes();
+ for (const QString &suffix : suffixes)
+ result.append(QLatin1String("*.") + suffix);
}
return result;
}
diff --git a/examples/quick/demos/photoviewer/deployment.pri b/examples/quick/demos/photoviewer/deployment.pri
deleted file mode 100644
index 0d58a25c61..0000000000
--- a/examples/quick/demos/photoviewer/deployment.pri
+++ /dev/null
@@ -1,19 +0,0 @@
-android {
- x86 {
- target.path = /libs/x86
- } else: armeabi-v7a {
- target.path = /libs/armeabi-v7a
- } else {
- target.path = /libs/armeabi
- }
- export(target.path)
- INSTALLS += target
-} else:unix {
- isEmpty(target.path) {
- target.path = /opt/$${TARGET}/bin
- export(target.path)
- }
- INSTALLS += target
-}
-
-export(INSTALLS)
diff --git a/examples/quick/demos/photoviewer/photoviewer.pro b/examples/quick/demos/photoviewer/photoviewer.pro
index 704e2ce003..4bfdb86f31 100644
--- a/examples/quick/demos/photoviewer/photoviewer.pro
+++ b/examples/quick/demos/photoviewer/photoviewer.pro
@@ -15,8 +15,5 @@ TRANSLATIONS += i18n/qml_fr.ts \
RESOURCES += qml.qrc
-# Additional import path used to resolve QML modules in Qt Creator's code model
-QML_IMPORT_PATH =
-
-# Default rules for deployment.
-include(deployment.pri)
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/demos/photoviewer
+INSTALLS += target
diff --git a/examples/quick/demos/samegame/samegame.pro b/examples/quick/demos/samegame/samegame.pro
index e041dd61dd..0f01654d46 100644
--- a/examples/quick/demos/samegame/samegame.pro
+++ b/examples/quick/demos/samegame/samegame.pro
@@ -7,4 +7,4 @@ RESOURCES += samegame.qrc
target.path = $$[QT_INSTALL_EXAMPLES]/quick/demos/samegame
INSTALLS += target
-!contains(sql-drivers, sqlite): QTPLUGIN += qsqlite
+!qtConfig(sql-sqlite): QTPLUGIN += qsqlite
diff --git a/examples/quick/embeddedinwidgets/main.cpp b/examples/quick/embeddedinwidgets/main.cpp
index 96b0df7e13..91147772ba 100644
--- a/examples/quick/embeddedinwidgets/main.cpp
+++ b/examples/quick/embeddedinwidgets/main.cpp
@@ -103,7 +103,8 @@ void MainWindow::quickViewStatusChanged(QQuickView::Status status)
{
if (status == QQuickView::Error) {
QStringList errors;
- foreach (const QQmlError &error, m_quickView->errors())
+ const auto viewErrors = m_quickView->errors();
+ for (const QQmlError &error : viewErrors)
errors.append(error.toString());
statusBar()->showMessage(errors.join(QStringLiteral(", ")));
}
diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro
index b164bf4f5b..445dfb0fab 100644
--- a/examples/quick/quick.pro
+++ b/examples/quick/quick.pro
@@ -27,7 +27,7 @@ SUBDIRS = quick-accessibility \
demos
#OpenGL Support Required
-contains(QT_CONFIG, opengl(es1|es2)?) {
+qtConfig(opengl(es1|es2)?) {
SUBDIRS += \
textureprovider \
rendercontrol
diff --git a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
index 078d8e7e03..ea6c7f2f9a 100644
--- a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
+++ b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
@@ -40,6 +40,7 @@
#include "mainwindow.h"
#include "fbitem.h"
+#include <QCoreApplication>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QRadioButton>
diff --git a/examples/quick/quickwidgets/quickwidget/customgl.qml b/examples/quick/quickwidgets/quickwidget/customgl.qml
new file mode 100644
index 0000000000..81e33e1ac9
--- /dev/null
+++ b/examples/quick/quickwidgets/quickwidget/customgl.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.0
+import QuickWidgetExample 1.0
+
+Rectangle {
+ color: "lightGray"
+
+ FbItem {
+ anchors.fill: parent
+ anchors.margins: 10
+ }
+
+ Text {
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.margins: 15
+ text: "QQuickFramebufferObject with animated clear color"
+ color: "white"
+ }
+}
diff --git a/examples/quick/quickwidgets/quickwidget/fbitem.cpp b/examples/quick/quickwidgets/quickwidget/fbitem.cpp
new file mode 100644
index 0000000000..fc2a4ea7ad
--- /dev/null
+++ b/examples/quick/quickwidgets/quickwidget/fbitem.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "fbitem.h"
+#include <QtGui/QOpenGLFramebufferObject>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+#include <QtCore/QDebug>
+
+#ifndef QT_NO_OPENGL
+class FbRenderer : public QQuickFramebufferObject::Renderer
+{
+public:
+ FbRenderer() : c(0), dir(1) { }
+
+ // The lifetime of the FBO and this class depends on how QQuickWidget
+ // manages the scenegraph and context when it comes to showing and hiding
+ // the widget. The actual behavior is proven by the debug prints.
+ ~FbRenderer() {
+ qDebug("FbRenderer destroyed");
+ }
+
+ void render() {
+ QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
+ f->glClearColor(c, 0, 0, 1);
+ f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ c += 0.01f * dir;
+ if (c >= 1.0f || c <= 0.0f)
+ dir *= -1;
+ update();
+ }
+
+ QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) {
+ qDebug() << "Creating FBO" << size;
+ QOpenGLFramebufferObjectFormat format;
+ format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ return new QOpenGLFramebufferObject(size, format);
+ }
+
+private:
+ float c;
+ int dir;
+};
+#endif
+
+QQuickFramebufferObject::Renderer *FbItem::createRenderer() const
+{
+#ifndef QT_NO_OPENGL
+ return new FbRenderer;
+#else
+ return nullptr;
+#endif
+}
diff --git a/examples/quick/quickwidgets/quickwidget/fbitem.h b/examples/quick/quickwidgets/quickwidget/fbitem.h
new file mode 100644
index 0000000000..59280eb3b8
--- /dev/null
+++ b/examples/quick/quickwidgets/quickwidget/fbitem.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FBITEM_H
+#define FBITEM_H
+
+#include <QtQuick/QQuickFramebufferObject>
+
+class FbItem : public QQuickFramebufferObject
+{
+ Q_OBJECT
+public:
+ Renderer *createRenderer() const;
+};
+
+#endif
diff --git a/examples/quick/quickwidgets/quickwidget/main.cpp b/examples/quick/quickwidgets/quickwidget/main.cpp
index 65258d958e..590f29ed29 100644
--- a/examples/quick/quickwidgets/quickwidget/main.cpp
+++ b/examples/quick/quickwidgets/quickwidget/main.cpp
@@ -41,6 +41,7 @@
#include <QQuickWidget>
#include <QQmlError>
#include <QtWidgets>
+#include "fbitem.h"
class MainWindow : public QMainWindow {
Q_OBJECT
@@ -52,6 +53,7 @@ private slots:
void sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message);
void grabToFile();
void renderToFile();
+ void createQuickWidgetsInTabs(QMdiArea *mdiArea);
private:
QQuickWidget *m_quickWidget;
@@ -74,7 +76,7 @@ MainWindow::MainWindow()
QLCDNumber *lcd = new QLCDNumber;
lcd->display(1337);
lcd->setMinimumSize(250,100);
- centralWidget ->addSubWindow(lcd);
+ centralWidget->addSubWindow(lcd);
QUrl source("qrc:quickwidget/rotatingsquare.qml");
@@ -86,21 +88,50 @@ MainWindow::MainWindow()
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView );
m_quickWidget->setSource(source);
- centralWidget ->addSubWindow(m_quickWidget);
+ centralWidget->addSubWindow(m_quickWidget);
setCentralWidget(centralWidget);
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
- fileMenu->addAction(tr("Grab to imFage"), this, &MainWindow::grabToFile);
+ fileMenu->addAction(tr("Grab to image"), this, &MainWindow::grabToFile);
fileMenu->addAction(tr("Render to pixmap"), this, &MainWindow::renderToFile);
fileMenu->addAction(tr("Quit"), qApp, &QCoreApplication::quit);
+
+ QMenu *windowMenu = menuBar()->addMenu(tr("&Window"));
+ windowMenu->addAction(tr("Add tab widget"), this,
+ [this, centralWidget] { createQuickWidgetsInTabs(centralWidget); });
+}
+
+void MainWindow::createQuickWidgetsInTabs(QMdiArea *mdiArea)
+{
+ QTabWidget *tabWidget = new QTabWidget;
+
+ const QSize size(400, 400);
+
+ QQuickWidget *w = new QQuickWidget;
+ w->resize(size);
+ w->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ w->setSource(QUrl("qrc:quickwidget/rotatingsquaretab.qml"));
+
+ tabWidget->addTab(w, tr("Plain Quick content"));
+
+ w = new QQuickWidget;
+ w->resize(size);
+ w->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ w->setSource(QUrl("qrc:quickwidget/customgl.qml"));
+
+ tabWidget->addTab(w, tr("Custom OpenGL drawing"));
+
+ mdiArea->addSubWindow(tabWidget);
+ tabWidget->show();
}
void MainWindow::quickWidgetStatusChanged(QQuickWidget::Status status)
{
if (status == QQuickWidget::Error) {
QStringList errors;
- foreach (const QQmlError &error, m_quickWidget->errors())
+ const auto widgetErrors = m_quickWidget->errors();
+ for (const QQmlError &error : widgetErrors)
errors.append(error.toString());
statusBar()->showMessage(errors.join(QStringLiteral(", ")));
}
@@ -139,6 +170,8 @@ int main(int argc, char **argv)
{
QApplication app(argc, argv);
+ qmlRegisterType<FbItem>("QuickWidgetExample", 1, 0, "FbItem");
+
MainWindow mainWindow;
mainWindow.show();
diff --git a/examples/quick/quickwidgets/quickwidget/quickwidget.pro b/examples/quick/quickwidgets/quickwidget/quickwidget.pro
index 04fb5541a7..5be006f7fa 100644
--- a/examples/quick/quickwidgets/quickwidget/quickwidget.pro
+++ b/examples/quick/quickwidgets/quickwidget/quickwidget.pro
@@ -3,7 +3,8 @@ QT += core gui quick widgets quickwidgets
TARGET = quickwidget
TEMPLATE = app
-SOURCES += main.cpp
+SOURCES += main.cpp fbitem.cpp
+HEADERS += fbitem.h
RESOURCES += quickwidget.qrc
diff --git a/examples/quick/quickwidgets/quickwidget/quickwidget.qrc b/examples/quick/quickwidgets/quickwidget/quickwidget.qrc
index c073b7b80d..85a49b75ca 100644
--- a/examples/quick/quickwidgets/quickwidget/quickwidget.qrc
+++ b/examples/quick/quickwidgets/quickwidget/quickwidget.qrc
@@ -1,5 +1,7 @@
<RCC>
<qresource prefix="/quickwidget">
<file>rotatingsquare.qml</file>
+ <file>rotatingsquaretab.qml</file>
+ <file>customgl.qml</file>
</qresource>
</RCC>
diff --git a/examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml b/examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml
new file mode 100644
index 0000000000..51c17b9ffb
--- /dev/null
+++ b/examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.0
+
+Rectangle {
+ gradient: Gradient {
+ GradientStop { position: 0; color: "steelblue" }
+ GradientStop { position: 1; color: "black" }
+ }
+
+ Rectangle {
+ property int d: 100
+ id: square
+ width: d
+ height: d
+ anchors.centerIn: parent
+ color: "green"
+ NumberAnimation on rotation { from: 360; to: 0; duration: 4000; loops: Animation.Infinite; }
+ }
+
+ Text {
+ anchors.centerIn: parent
+ text: "Qt Quick running in a tab widget"
+ color: "purple"
+ font.bold: true
+ font.pointSize: 14
+ }
+}
diff --git a/examples/quick/rendercontrol/window_multithreaded.cpp b/examples/quick/rendercontrol/window_multithreaded.cpp
index 4df3488ab3..013ee7c208 100644
--- a/examples/quick/rendercontrol/window_multithreaded.cpp
+++ b/examples/quick/rendercontrol/window_multithreaded.cpp
@@ -356,16 +356,16 @@ void WindowMultiThreaded::run()
disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &WindowMultiThreaded::run);
if (m_qmlComponent->isError()) {
- QList<QQmlError> errorList = m_qmlComponent->errors();
- foreach (const QQmlError &error, errorList)
+ const QList<QQmlError> errorList = m_qmlComponent->errors();
+ for (const QQmlError &error : errorList)
qWarning() << error.url() << error.line() << error;
return;
}
QObject *rootObject = m_qmlComponent->create();
if (m_qmlComponent->isError()) {
- QList<QQmlError> errorList = m_qmlComponent->errors();
- foreach (const QQmlError &error, errorList)
+ const QList<QQmlError> errorList = m_qmlComponent->errors();
+ for (const QQmlError &error : errorList)
qWarning() << error.url() << error.line() << error;
return;
}
diff --git a/examples/quick/rendercontrol/window_singlethreaded.cpp b/examples/quick/rendercontrol/window_singlethreaded.cpp
index 45f2635ca4..ef8f2fed43 100644
--- a/examples/quick/rendercontrol/window_singlethreaded.cpp
+++ b/examples/quick/rendercontrol/window_singlethreaded.cpp
@@ -209,16 +209,16 @@ void WindowSingleThreaded::run()
disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &WindowSingleThreaded::run);
if (m_qmlComponent->isError()) {
- QList<QQmlError> errorList = m_qmlComponent->errors();
- foreach (const QQmlError &error, errorList)
+ const QList<QQmlError> errorList = m_qmlComponent->errors();
+ for (const QQmlError &error : errorList)
qWarning() << error.url() << error.line() << error;
return;
}
QObject *rootObject = m_qmlComponent->create();
if (m_qmlComponent->isError()) {
- QList<QQmlError> errorList = m_qmlComponent->errors();
- foreach (const QQmlError &error, errorList)
+ const QList<QQmlError> errorList = m_qmlComponent->errors();
+ for (const QQmlError &error : errorList)
qWarning() << error.url() << error.line() << error;
return;
}
diff --git a/examples/quick/scenegraph/graph/linenode.cpp b/examples/quick/scenegraph/graph/linenode.cpp
index 473be7da17..992e2d44c9 100644
--- a/examples/quick/scenegraph/graph/linenode.cpp
+++ b/examples/quick/scenegraph/graph/linenode.cpp
@@ -56,7 +56,7 @@ class LineShader : public QSGSimpleMaterialShader<LineMaterial>
QSG_DECLARE_SIMPLE_SHADER(LineShader, LineMaterial)
public:
- LineShader() {
+ LineShader() : id_color(-1), id_spread(-1), id_size(-1) {
setShaderSourceFile(QOpenGLShader::Vertex, ":/scenegraph/graph/shaders/line.vsh");
setShaderSourceFile(QOpenGLShader::Fragment, ":/scenegraph/graph/shaders/line.fsh");
}
diff --git a/examples/quick/scenegraph/graph/noisynode.cpp b/examples/quick/scenegraph/graph/noisynode.cpp
index bc273cf632..834151599b 100644
--- a/examples/quick/scenegraph/graph/noisynode.cpp
+++ b/examples/quick/scenegraph/graph/noisynode.cpp
@@ -61,7 +61,7 @@ class NoisyShader : public QSGSimpleMaterialShader<NoisyMaterial>
QSG_DECLARE_SIMPLE_SHADER(NoisyShader, NoisyMaterial)
public:
- NoisyShader() {
+ NoisyShader() : id_color(-1), id_texture(-1), id_textureSize(-1) {
setShaderSourceFile(QOpenGLShader::Vertex, ":/scenegraph/graph/shaders/noisy.vsh");
setShaderSourceFile(QOpenGLShader::Fragment, ":/scenegraph/graph/shaders/noisy.fsh");
}
diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.cpp b/examples/quick/scenegraph/rendernode/customrenderitem.cpp
index 433f3c5a1e..2465f4cbc7 100644
--- a/examples/quick/scenegraph/rendernode/customrenderitem.cpp
+++ b/examples/quick/scenegraph/rendernode/customrenderitem.cpp
@@ -44,6 +44,7 @@
#include "openglrenderer.h"
#include "d3d12renderer.h"
+#include "softwarerenderer.h"
CustomRenderItem::CustomRenderItem(QQuickItem *parent)
: QQuickItem(parent)
@@ -70,6 +71,10 @@ QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
n = new D3D12RenderNode(this);
break;
#endif
+ case QSGRendererInterface::Software:
+ n = new SoftwareRenderNode(this);
+ break;
+
default:
return nullptr;
}
diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
index bc03720407..d35f82a76a 100644
--- a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
+++ b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
@@ -78,7 +78,7 @@ void D3D12RenderNode::releaseResources()
void D3D12RenderNode::init()
{
QSGRendererInterface *rif = m_item->window()->rendererInterface();
- m_device = static_cast<ID3D12Device *>(rif->getResource(QSGRendererInterface::Device));
+ m_device = static_cast<ID3D12Device *>(rif->getResource(m_item->window(), QSGRendererInterface::Device));
Q_ASSERT(m_device);
D3D12_ROOT_PARAMETER rootParameter;
@@ -153,7 +153,20 @@ void D3D12RenderNode::init()
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; // not in use due to !DepthEnable, but this would be the correct format otherwise
- psoDesc.SampleDesc.Count = 1;
+ // We are rendering on the default render target so if the QuickWindow/View
+ // has requested samples > 0 then we have to follow suit.
+ const uint samples = qMax(1, m_item->window()->format().samples());
+ psoDesc.SampleDesc.Count = samples;
+ if (samples > 1) {
+ D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
+ msaaInfo.Format = psoDesc.RTVFormats[0];
+ msaaInfo.SampleCount = samples;
+ if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo, sizeof(msaaInfo)))) {
+ if (msaaInfo.NumQualityLevels > 0)
+ psoDesc.SampleDesc.Quality = msaaInfo.NumQualityLevels - 1;
+ }
+ }
+
if (FAILED(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)))) {
qWarning("Failed to create graphics pipeline state");
return;
@@ -222,7 +235,7 @@ void D3D12RenderNode::render(const RenderState *state)
init();
QSGRendererInterface *rif = m_item->window()->rendererInterface();
- ID3D12GraphicsCommandList *commandList = static_cast<ID3D12GraphicsCommandList *>(rif->getResource(QSGRendererInterface::CommandList));
+ ID3D12GraphicsCommandList *commandList = static_cast<ID3D12GraphicsCommandList *>(rif->getResource(m_item->window(), QSGRendererInterface::CommandList));
Q_ASSERT(commandList);
const int msize = 16 * sizeof(float);
@@ -257,4 +270,14 @@ void D3D12RenderNode::render(const RenderState *state)
// No need to reimplement changedStates() because no relevant commands are
// added to the command list in render().
+QSGRenderNode::RenderingFlags D3D12RenderNode::flags() const
+{
+ return BoundedRectRendering | DepthAwareRendering;
+}
+
+QRectF D3D12RenderNode::rect() const
+{
+ return QRect(0, 0, m_item->width(), m_item->height());
+}
+
#endif // HAS_D3D12
diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.h b/examples/quick/scenegraph/rendernode/d3d12renderer.h
index a81db0f398..f13a1d451c 100644
--- a/examples/quick/scenegraph/rendernode/d3d12renderer.h
+++ b/examples/quick/scenegraph/rendernode/d3d12renderer.h
@@ -60,6 +60,8 @@ public:
void render(const RenderState *state) override;
void releaseResources() override;
+ RenderingFlags flags() const override;
+ QRectF rect() const override;
private:
void init();
diff --git a/examples/quick/scenegraph/rendernode/main.cpp b/examples/quick/scenegraph/rendernode/main.cpp
index 9128cdc5be..3e1714313e 100644
--- a/examples/quick/scenegraph/rendernode/main.cpp
+++ b/examples/quick/scenegraph/rendernode/main.cpp
@@ -49,6 +49,13 @@ int main(int argc, char **argv)
qmlRegisterType<CustomRenderItem>("SceneGraphRendering", 2, 0, "CustomRenderItem");
QQuickView view;
+
+ if (QCoreApplication::arguments().contains(QStringLiteral("--multisample"))) {
+ QSurfaceFormat fmt;
+ fmt.setSamples(4);
+ view.setFormat(fmt);
+ }
+
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:///scenegraph/rendernode/main.qml"));
view.resize(1024, 768);
diff --git a/examples/quick/scenegraph/rendernode/main.qml b/examples/quick/scenegraph/rendernode/main.qml
index a91656dfaa..7c8d82181f 100644
--- a/examples/quick/scenegraph/rendernode/main.qml
+++ b/examples/quick/scenegraph/rendernode/main.qml
@@ -90,7 +90,10 @@ Item {
anchors.margins: 20
wrapMode: Text.WordWrap
property int api: GraphicsInfo.api
- text: "Custom rendering via the graphics API " + (api === GraphicsInfo.OpenGL ? "OpenGL" : (api === GraphicsInfo.Direct3D12 ? "Direct3D 12" : ""))
+ text: "Custom rendering via the graphics API "
+ + (api === GraphicsInfo.OpenGL ? "OpenGL"
+ : api === GraphicsInfo.Direct3D12 ? "Direct3D 12"
+ : api === GraphicsInfo.Software ? "Software" : "")
color: "yellow"
}
}
diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.cpp b/examples/quick/scenegraph/rendernode/openglrenderer.cpp
index 3eff70cb42..3de864b7b9 100644
--- a/examples/quick/scenegraph/rendernode/openglrenderer.cpp
+++ b/examples/quick/scenegraph/rendernode/openglrenderer.cpp
@@ -97,8 +97,6 @@ void OpenGLRenderNode::init()
const int VERTEX_SIZE = 6 * sizeof(GLfloat);
- // A fully featured renderer should also take inheritedOpacity() into account
- // and blend, but ignore that for now.
static GLfloat colors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
@@ -140,6 +138,8 @@ void OpenGLRenderNode::render(const RenderState *state)
m_program->enableAttributeArray(0);
m_program->enableAttributeArray(1);
+ // Note that clipping (scissor or stencil) is ignored in this example.
+
f->glEnable(GL_BLEND);
f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
@@ -151,4 +151,14 @@ QSGRenderNode::StateFlags OpenGLRenderNode::changedStates() const
return BlendState;
}
+QSGRenderNode::RenderingFlags OpenGLRenderNode::flags() const
+{
+ return BoundedRectRendering | DepthAwareRendering;
+}
+
+QRectF OpenGLRenderNode::rect() const
+{
+ return QRect(0, 0, m_item->width(), m_item->height());
+}
+
#endif // QT_NO_OPENGL
diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.h b/examples/quick/scenegraph/rendernode/openglrenderer.h
index 28d528e617..92cc2bc72b 100644
--- a/examples/quick/scenegraph/rendernode/openglrenderer.h
+++ b/examples/quick/scenegraph/rendernode/openglrenderer.h
@@ -45,6 +45,8 @@
#ifndef QT_NO_OPENGL
+QT_BEGIN_NAMESPACE
+
class QQuickItem;
class QOpenGLShaderProgram;
class QOpenGLBuffer;
@@ -58,6 +60,8 @@ public:
void render(const RenderState *state) override;
void releaseResources() override;
StateFlags changedStates() const override;
+ RenderingFlags flags() const override;
+ QRectF rect() const override;
private:
void init();
@@ -69,6 +73,8 @@ private:
QOpenGLBuffer *m_vbo = nullptr;
};
+QT_END_NAMESPACE
+
#endif // QT_NO_OPENGL
#endif
diff --git a/examples/quick/scenegraph/rendernode/rendernode.pro b/examples/quick/scenegraph/rendernode/rendernode.pro
index d7ae715a7d..851d5927bd 100644
--- a/examples/quick/scenegraph/rendernode/rendernode.pro
+++ b/examples/quick/scenegraph/rendernode/rendernode.pro
@@ -1,10 +1,12 @@
QT += qml quick
HEADERS += customrenderitem.h \
- openglrenderer.h
+ openglrenderer.h \
+ softwarerenderer.h
SOURCES += customrenderitem.cpp \
openglrenderer.cpp \
+ softwarerenderer.cpp \
main.cpp
RESOURCES += rendernode.qrc
diff --git a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp
new file mode 100644
index 0000000000..06e406874a
--- /dev/null
+++ b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "softwarerenderer.h"
+#include <QQuickItem>
+#include <QQuickWindow>
+#include <QSGRendererInterface>
+#include <QPainter>
+
+SoftwareRenderNode::SoftwareRenderNode(QQuickItem *item)
+ : m_item(item)
+{
+}
+
+SoftwareRenderNode::~SoftwareRenderNode()
+{
+ releaseResources();
+}
+
+void SoftwareRenderNode::releaseResources()
+{
+}
+
+void SoftwareRenderNode::render(const RenderState *renderState)
+{
+ QSGRendererInterface *rif = m_item->window()->rendererInterface();
+ QPainter *p = static_cast<QPainter *>(rif->getResource(m_item->window(), QSGRendererInterface::Painter));
+ Q_ASSERT(p);
+
+ p->setTransform(matrix()->toTransform());
+ p->setOpacity(inheritedOpacity());
+ const QRegion *clipRegion = renderState->clipRegion();
+ if (clipRegion && !clipRegion->isEmpty())
+ p->setClipRegion(*clipRegion, Qt::IntersectClip);
+
+ const QPointF p0(m_item->width() - 1, m_item->height() - 1);
+ const QPointF p1(0, 0);
+ const QPointF p2(0, m_item->height() - 1);
+ QPainterPath path(p0);
+ path.lineTo(p1);
+ path.lineTo(p2);
+ path.closeSubpath();
+
+ QLinearGradient gradient(QPointF(0, 0), QPointF(m_item->width(), m_item->height()));
+ gradient.setColorAt(0, Qt::green);
+ gradient.setColorAt(1, Qt::red);
+
+ p->fillPath(path, gradient);
+}
+
+QSGRenderNode::StateFlags SoftwareRenderNode::changedStates() const
+{
+ return 0;
+}
+
+QSGRenderNode::RenderingFlags SoftwareRenderNode::flags() const
+{
+ return BoundedRectRendering;
+}
+
+QRectF SoftwareRenderNode::rect() const
+{
+ return QRect(0, 0, m_item->width(), m_item->height());
+}
diff --git a/examples/quick/scenegraph/rendernode/softwarerenderer.h b/examples/quick/scenegraph/rendernode/softwarerenderer.h
new file mode 100644
index 0000000000..e91ca92d88
--- /dev/null
+++ b/examples/quick/scenegraph/rendernode/softwarerenderer.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SOFTWARERENDERER_H
+#define SOFTWARERENDERER_H
+
+#include <qsgrendernode.h>
+#include <QQuickItem>
+
+class SoftwareRenderNode : public QSGRenderNode
+{
+public:
+ SoftwareRenderNode(QQuickItem *item);
+ ~SoftwareRenderNode();
+
+ void render(const RenderState *state) override;
+ void releaseResources() override;
+ StateFlags changedStates() const override;
+ RenderingFlags flags() const override;
+ QRectF rect() const override;
+
+private:
+ QQuickItem *m_item;
+};
+
+#endif
diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro
index 1015d7be3d..e13e8198b0 100644
--- a/examples/quick/scenegraph/scenegraph.pro
+++ b/examples/quick/scenegraph/scenegraph.pro
@@ -1,6 +1,6 @@
TEMPLATE = subdirs
-contains(QT_CONFIG, opengl(es1|es2)?) {
+qtConfig(opengl(es1|es2)?) {
SUBDIRS += \
graph \
simplematerial \
diff --git a/examples/quick/scenegraph/sgengine/window.cpp b/examples/quick/scenegraph/sgengine/window.cpp
index 2e4a70d2af..759bbf1fcd 100644
--- a/examples/quick/scenegraph/sgengine/window.cpp
+++ b/examples/quick/scenegraph/sgengine/window.cpp
@@ -187,7 +187,7 @@ void Window::update()
void Window::sync()
{
QList<QSharedPointer<Item> > validItems;
- foreach (QSharedPointer<Item> item, m_items) {
+ for (QSharedPointer<Item> item : qAsConst(m_items)) {
if (!item->isDone()) {
validItems.append(item);
item->sync();
diff --git a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc
index 278f154781..d6eb711929 100644
--- a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc
+++ b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc
@@ -102,8 +102,8 @@
state and we use it to update the shader program with the current
color. The previous state is passed in as a second parameter so
that the user can update only that which has changed. In our
- usecase, where all the colors are different, the updateState will
- be called once for every node.
+ use case, where all the colors are different, the updateState()
+ function will be called once for every node.
\snippet scenegraph/simplematerial/simplematerial.cpp 7
diff --git a/examples/quick/scenegraph/textureinthread/main.cpp b/examples/quick/scenegraph/textureinthread/main.cpp
index 22550cd22b..61d1c5e6dc 100644
--- a/examples/quick/scenegraph/textureinthread/main.cpp
+++ b/examples/quick/scenegraph/textureinthread/main.cpp
@@ -82,7 +82,7 @@ int main(int argc, char **argv)
// As the render threads make use of our QGuiApplication object
// to clean up gracefully, wait for them to finish before
// QGuiApp is taken off the heap.
- foreach (QThread *t, ThreadRenderer::threads) {
+ for (QThread *t : qAsConst(ThreadRenderer::threads)) {
t->wait();
delete t;
}
diff --git a/examples/quick/shadereffects/content/shaders/+hlsl/blur.frag b/examples/quick/shadereffects/content/shaders/+hlsl/blur.frag
new file mode 100644
index 0000000000..481a238d2a
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+hlsl/blur.frag
@@ -0,0 +1,18 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ float2 delta;
+};
+
+Texture2D source : register(t0);
+SamplerState sourceSampler : register(s0);
+
+float4 main(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
+{
+ return (0.0538 * source.Sample(sourceSampler, coord - 3.182 * delta)
+ + 0.3229 * source.Sample(sourceSampler, coord - 1.364 * delta)
+ + 0.2466 * source.Sample(sourceSampler, coord)
+ + 0.3229 * source.Sample(sourceSampler, coord + 1.364 * delta)
+ + 0.0538 * source.Sample(sourceSampler, coord + 3.182 * delta)) * qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/+hlsl/colorize.frag b/examples/quick/shadereffects/content/shaders/+hlsl/colorize.frag
new file mode 100644
index 0000000000..d6e65b6b10
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+hlsl/colorize.frag
@@ -0,0 +1,17 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ float4 tint;
+};
+
+Texture2D source : register(t0);
+SamplerState sourceSampler : register(s0);
+
+float4 main(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
+{
+ float4 c = source.Sample(sourceSampler, coord);
+ float lo = min(min(c.x, c.y), c.z);
+ float hi = max(max(c.x, c.y), c.z);
+ return float4(lerp(float3(lo, lo, lo), float3(hi, hi, hi), tint.xyz), c.w) * qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/+hlsl/genie.vert b/examples/quick/shadereffects/content/shaders/+hlsl/genie.vert
new file mode 100644
index 0000000000..40876e7996
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+hlsl/genie.vert
@@ -0,0 +1,31 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ float bend;
+ float minimize;
+ float side;
+ float width;
+ float height;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+PSInput main(float4 position : POSITION, float2 coord : TEXCOORD0)
+{
+ PSInput result;
+ result.coord = coord;
+
+ float4 pos = position;
+ pos.y = lerp(position.y, height, minimize);
+ float t = pos.y / height;
+ t = (3.0 - 2.0 * t) * t * t;
+ pos.x = lerp(position.x, side * width, t * bend);
+ result.position = mul(qt_Matrix, pos);
+
+ return result;
+}
diff --git a/examples/quick/shadereffects/content/shaders/+hlsl/outline.frag b/examples/quick/shadereffects/content/shaders/+hlsl/outline.frag
new file mode 100644
index 0000000000..b6e7e51f35
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+hlsl/outline.frag
@@ -0,0 +1,21 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ float2 delta;
+};
+
+Texture2D source : register(t0);
+SamplerState sourceSampler : register(s0);
+
+float4 main(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
+{
+ float4 tl = source.Sample(sourceSampler, coord - delta);
+ float4 tr = source.Sample(sourceSampler, coord + float2(delta.x, -delta.y));
+ float4 bl = source.Sample(sourceSampler, coord - float2(delta.x, -delta.y));
+ float4 br = source.Sample(sourceSampler, coord + delta);
+ float4 gx = (tl + bl) - (tr + br);
+ float4 gy = (tl + tr) - (bl + br);
+ return float4(0.0, 0.0, 0.0,
+ clamp(dot(sqrt(gx * gx + gy * gy), float4(1.0, 1.0, 1.0, 1.0)), 0.0, 1.0) * qt_Opacity);
+}
diff --git a/examples/quick/shadereffects/content/shaders/+hlsl/shadow.frag b/examples/quick/shadereffects/content/shaders/+hlsl/shadow.frag
new file mode 100644
index 0000000000..a86a25e007
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+hlsl/shadow.frag
@@ -0,0 +1,20 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ float2 offset;
+ float2 delta;
+ float darkness;
+};
+
+Texture2D source : register(t0);
+SamplerState sourceSampler : register(s0);
+Texture2D shadow : register(t1);
+SamplerState shadowSampler : register(s1);
+
+float4 main(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
+{
+ float4 fg = source.Sample(sourceSampler, coord);
+ float4 bg = shadow.Sample(shadowSampler, coord + delta);
+ return (fg + float4(0.0, 0.0, 0.0, darkness * bg.a) * (1.0 - fg.a)) * qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/+hlsl/wobble.frag b/examples/quick/shadereffects/content/shaders/+hlsl/wobble.frag
new file mode 100644
index 0000000000..c28612a2fd
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+hlsl/wobble.frag
@@ -0,0 +1,17 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ float amplitude;
+ float frequency;
+ float time;
+};
+
+Texture2D source : register(t0);
+SamplerState sourceSampler : register(s0);
+
+float4 main(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
+{
+ float2 p = sin(time + frequency * coord);
+ return source.Sample(sourceSampler, coord + amplitude * float2(p.y, -p.x)) * qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/blur.frag b/examples/quick/shadereffects/content/shaders/blur.frag
new file mode 100644
index 0000000000..9173945eed
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/blur.frag
@@ -0,0 +1,14 @@
+uniform lowp float qt_Opacity;
+uniform sampler2D source;
+uniform highp vec2 delta;
+
+varying highp vec2 qt_TexCoord0;
+
+void main()
+{
+ gl_FragColor =(0.0538 * texture2D(source, qt_TexCoord0 - 3.182 * delta)
+ + 0.3229 * texture2D(source, qt_TexCoord0 - 1.364 * delta)
+ + 0.2466 * texture2D(source, qt_TexCoord0)
+ + 0.3229 * texture2D(source, qt_TexCoord0 + 1.364 * delta)
+ + 0.0538 * texture2D(source, qt_TexCoord0 + 3.182 * delta)) * qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/colorize.frag b/examples/quick/shadereffects/content/shaders/colorize.frag
new file mode 100644
index 0000000000..1219ef2460
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/colorize.frag
@@ -0,0 +1,12 @@
+uniform sampler2D source;
+uniform lowp vec4 tint;
+uniform lowp float qt_Opacity;
+
+varying highp vec2 qt_TexCoord0;
+
+void main() {
+ lowp vec4 c = texture2D(source, qt_TexCoord0);
+ lowp float lo = min(min(c.x, c.y), c.z);
+ lowp float hi = max(max(c.x, c.y), c.z);
+ gl_FragColor = qt_Opacity * vec4(mix(vec3(lo), vec3(hi), tint.xyz), c.w);
+}
diff --git a/examples/quick/shadereffects/content/shaders/genie.vert b/examples/quick/shadereffects/content/shaders/genie.vert
new file mode 100644
index 0000000000..3ce371819f
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/genie.vert
@@ -0,0 +1,21 @@
+attribute highp vec4 qt_Vertex;
+attribute highp vec2 qt_MultiTexCoord0;
+
+uniform highp mat4 qt_Matrix;
+uniform highp float bend;
+uniform highp float minimize;
+uniform highp float side;
+uniform highp float width;
+uniform highp float height;
+
+varying highp vec2 qt_TexCoord0;
+
+void main() {
+ qt_TexCoord0 = qt_MultiTexCoord0;
+ highp vec4 pos = qt_Vertex;
+ pos.y = mix(qt_Vertex.y, height, minimize);
+ highp float t = pos.y / height;
+ t = (3. - 2. * t) * t * t;
+ pos.x = mix(qt_Vertex.x, side * width, t * bend);
+ gl_Position = qt_Matrix * pos;
+}
diff --git a/examples/quick/shadereffects/content/shaders/outline.frag b/examples/quick/shadereffects/content/shaders/outline.frag
new file mode 100644
index 0000000000..9b46719873
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/outline.frag
@@ -0,0 +1,16 @@
+uniform sampler2D source;
+uniform highp vec2 delta;
+uniform highp float qt_Opacity;
+
+varying highp vec2 qt_TexCoord0;
+
+void main() {
+ lowp vec4 tl = texture2D(source, qt_TexCoord0 - delta);
+ lowp vec4 tr = texture2D(source, qt_TexCoord0 + vec2(delta.x, -delta.y));
+ lowp vec4 bl = texture2D(source, qt_TexCoord0 - vec2(delta.x, -delta.y));
+ lowp vec4 br = texture2D(source, qt_TexCoord0 + delta);
+ mediump vec4 gx = (tl + bl) - (tr + br);
+ mediump vec4 gy = (tl + tr) - (bl + br);
+ gl_FragColor.xyz = vec3(0.);
+ gl_FragColor.w = clamp(dot(sqrt(gx * gx + gy * gy), vec4(1.)), 0., 1.) * qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/shadow.frag b/examples/quick/shadereffects/content/shaders/shadow.frag
new file mode 100644
index 0000000000..8650ee4f4c
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/shadow.frag
@@ -0,0 +1,14 @@
+uniform lowp float qt_Opacity;
+uniform highp vec2 offset;
+uniform sampler2D source;
+uniform sampler2D shadow;
+uniform highp float darkness;
+uniform highp vec2 delta;
+
+varying highp vec2 qt_TexCoord0;
+
+void main() {
+ lowp vec4 fg = texture2D(source, qt_TexCoord0);
+ lowp vec4 bg = texture2D(shadow, qt_TexCoord0 + delta);
+ gl_FragColor = (fg + vec4(0., 0., 0., darkness * bg.a) * (1. - fg.a)) * qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/wobble.frag b/examples/quick/shadereffects/content/shaders/wobble.frag
new file mode 100644
index 0000000000..fedbb68254
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/wobble.frag
@@ -0,0 +1,13 @@
+uniform lowp float qt_Opacity;
+uniform highp float amplitude;
+uniform highp float frequency;
+uniform highp float time;
+uniform sampler2D source;
+
+varying highp vec2 qt_TexCoord0;
+
+void main()
+{
+ highp vec2 p = sin(time + frequency * qt_TexCoord0);
+ gl_FragColor = texture2D(source, qt_TexCoord0 + amplitude * vec2(p.y, -p.x)) * qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/doc/src/shadereffects.qdoc b/examples/quick/shadereffects/doc/src/shadereffects.qdoc
index dc2a2681f5..7b1d68ebb5 100644
--- a/examples/quick/shadereffects/doc/src/shadereffects.qdoc
+++ b/examples/quick/shadereffects/doc/src/shadereffects.qdoc
@@ -51,6 +51,21 @@
shader:
\snippet shadereffects/shadereffects.qml fragment
+ In order to support multiple graphics APIs, not just OpenGL, the shader
+ source is not embedded into QML. Instead, file selectors are used to select
+ the correct variant at runtime. Based on the Qt Quick backend in use, Qt
+ will automatically select either \c{shaders/wobble.frag} with the GLSL
+ source code or \c{shaders/+hlsl/wobble.frag} with the HLSL source code.
+
+ \note For simplicity shader source code is used in all variants of the
+ files. However, with the Direct3D backend of Qt Quick pre-compiled shaders
+ are also supported. For example, try the following commands in the
+ \c{content/shaders/+hlsl} directory: \c{move wobble.frag wobble.frag.src}
+ followed by \c{fxc /E main /T ps_5_0 /Fo wobble.frag wobble.frag.src}. Now
+ \c wobble.frag contains Direct3D bytecode and that is what gets shipped
+ with the application instead of the shader source. Further changes are not
+ necessary, the application will function like before.
+
You can use any custom property on the ShaderEffect in your shader. This
makes animated shader code very easy:
\snippet shadereffects/shadereffects.qml properties
diff --git a/examples/quick/shadereffects/shadereffects.qml b/examples/quick/shadereffects/shadereffects.qml
index 926394ed0f..0c24a7bbf2 100644
--- a/examples/quick/shadereffects/shadereffects.qml
+++ b/examples/quick/shadereffects/shadereffects.qml
@@ -101,7 +101,7 @@ Rectangle {
height: 140
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
- font.pixelSize: 120
+ font.pixelSize: 118
font.family: "Times"
color: "blue"
text: "Qt"
@@ -128,17 +128,7 @@ Rectangle {
property real time: 0
NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 600 }
//! [fragment]
- fragmentShader:
- "uniform lowp float qt_Opacity;" +
- "uniform highp float amplitude;" +
- "uniform highp float frequency;" +
- "uniform highp float time;" +
- "uniform sampler2D source;" +
- "varying highp vec2 qt_TexCoord0;" +
- "void main() {" +
- " highp vec2 p = sin(time + frequency * qt_TexCoord0);" +
- " gl_FragColor = texture2D(source, qt_TexCoord0 + amplitude * vec2(p.y, -p.x)) * qt_Opacity;" +
- "}"
+ fragmentShader: "qrc:shadereffects/content/shaders/wobble.frag"
//! [fragment]
Slider {
id: wobbleSlider
@@ -163,32 +153,10 @@ Rectangle {
height: theItem.height
property variant delta: Qt.size(1.0 / width, 0.0)
property variant source: theSource
- fragmentShader: "
- uniform lowp float qt_Opacity;
- uniform sampler2D source;
- uniform highp vec2 delta;
- varying highp vec2 qt_TexCoord0;
- void main() {
- gl_FragColor =(0.0538 * texture2D(source, qt_TexCoord0 - 3.182 * delta)
- + 0.3229 * texture2D(source, qt_TexCoord0 - 1.364 * delta)
- + 0.2466 * texture2D(source, qt_TexCoord0)
- + 0.3229 * texture2D(source, qt_TexCoord0 + 1.364 * delta)
- + 0.0538 * texture2D(source, qt_TexCoord0 + 3.182 * delta)) * qt_Opacity;
- }"
+ fragmentShader: "qrc:shadereffects/content/shaders/blur.frag"
}
}
- fragmentShader: "
- uniform lowp float qt_Opacity;
- uniform sampler2D source;
- uniform highp vec2 delta;
- varying highp vec2 qt_TexCoord0;
- void main() {
- gl_FragColor =(0.0538 * texture2D(source, qt_TexCoord0 - 3.182 * delta)
- + 0.3229 * texture2D(source, qt_TexCoord0 - 1.364 * delta)
- + 0.2466 * texture2D(source, qt_TexCoord0)
- + 0.3229 * texture2D(source, qt_TexCoord0 + 1.364 * delta)
- + 0.0538 * texture2D(source, qt_TexCoord0 + 3.182 * delta)) * qt_Opacity;
- }"
+ fragmentShader: "qrc:shadereffects/content/shaders/blur.frag"
}
}
property real angle: 0
@@ -196,19 +164,7 @@ Rectangle {
NumberAnimation on angle { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 6000 }
property variant delta: Qt.size(offset.x / width, offset.y / height)
property real darkness: shadowSlider.value
- fragmentShader: "
- uniform lowp float qt_Opacity;
- uniform highp vec2 offset;
- uniform sampler2D source;
- uniform sampler2D shadow;
- uniform highp float darkness;
- uniform highp vec2 delta;
- varying highp vec2 qt_TexCoord0;
- void main() {
- lowp vec4 fg = texture2D(source, qt_TexCoord0);
- lowp vec4 bg = texture2D(shadow, qt_TexCoord0 + delta);
- gl_FragColor = (fg + vec4(0., 0., 0., darkness * bg.a) * (1. - fg.a)) * qt_Opacity;
- }"
+ fragmentShader: "qrc:shadereffects/content/shaders/shadow.frag"
Slider {
id: shadowSlider
anchors.left: parent.left
@@ -222,38 +178,14 @@ Rectangle {
height: 160
property variant source: theSource
property variant delta: Qt.size(0.5 / width, 0.5 / height)
- fragmentShader: "
- uniform sampler2D source;
- uniform highp vec2 delta;
- uniform highp float qt_Opacity;
- varying highp vec2 qt_TexCoord0;
- void main() {
- lowp vec4 tl = texture2D(source, qt_TexCoord0 - delta);
- lowp vec4 tr = texture2D(source, qt_TexCoord0 + vec2(delta.x, -delta.y));
- lowp vec4 bl = texture2D(source, qt_TexCoord0 - vec2(delta.x, -delta.y));
- lowp vec4 br = texture2D(source, qt_TexCoord0 + delta);
- mediump vec4 gx = (tl + bl) - (tr + br);
- mediump vec4 gy = (tl + tr) - (bl + br);
- gl_FragColor.xyz = vec3(0.);
- gl_FragColor.w = clamp(dot(sqrt(gx * gx + gy * gy), vec4(1.)), 0., 1.) * qt_Opacity;
- }"
+ fragmentShader: "qrc:shadereffects/content/shaders/outline.frag"
}
ShaderEffect {
width: 160
height: 160
property variant source: theSource
property color tint: root.sliderToColor(colorizeSlider.value)
- fragmentShader: "
- uniform sampler2D source;
- uniform lowp vec4 tint;
- uniform lowp float qt_Opacity;
- varying highp vec2 qt_TexCoord0;
- void main() {
- lowp vec4 c = texture2D(source, qt_TexCoord0);
- lowp float lo = min(min(c.x, c.y), c.z);
- lowp float hi = max(max(c.x, c.y), c.z);
- gl_FragColor = qt_Opacity * vec4(mix(vec3(lo), vec3(hi), tint.xyz), c.w);
- }"
+ fragmentShader: "qrc:shadereffects/content/shaders/colorize.frag"
Slider {
id: colorizeSlider
anchors.left: parent.left
@@ -288,25 +220,7 @@ Rectangle {
//! [properties]
//! [vertex]
mesh: Qt.size(10, 10)
- vertexShader: "
- uniform highp mat4 qt_Matrix;
- uniform highp float bend;
- uniform highp float minimize;
- uniform highp float side;
- uniform highp float width;
- uniform highp float height;
- attribute highp vec4 qt_Vertex;
- attribute highp vec2 qt_MultiTexCoord0;
- varying highp vec2 qt_TexCoord0;
- void main() {
- qt_TexCoord0 = qt_MultiTexCoord0;
- highp vec4 pos = qt_Vertex;
- pos.y = mix(qt_Vertex.y, height, minimize);
- highp float t = pos.y / height;
- t = (3. - 2. * t) * t * t;
- pos.x = mix(qt_Vertex.x, side * width, t * bend);
- gl_Position = qt_Matrix * pos;
- }"
+ vertexShader: "qrc:shadereffects/content/shaders/genie.vert"
//! [vertex]
Slider {
id: genieSlider
diff --git a/examples/quick/shadereffects/shadereffects.qrc b/examples/quick/shadereffects/shadereffects.qrc
index ff296a0155..e66b98a6df 100644
--- a/examples/quick/shadereffects/shadereffects.qrc
+++ b/examples/quick/shadereffects/shadereffects.qrc
@@ -4,5 +4,17 @@
<file>content/face-smile.png</file>
<file>content/qt-logo.png</file>
<file>content/Slider.qml</file>
+ <file>content/shaders/wobble.frag</file>
+ <file>content/shaders/+hlsl/wobble.frag</file>
+ <file>content/shaders/blur.frag</file>
+ <file>content/shaders/+hlsl/blur.frag</file>
+ <file>content/shaders/shadow.frag</file>
+ <file>content/shaders/+hlsl/shadow.frag</file>
+ <file>content/shaders/outline.frag</file>
+ <file>content/shaders/+hlsl/outline.frag</file>
+ <file>content/shaders/colorize.frag</file>
+ <file>content/shaders/+hlsl/colorize.frag</file>
+ <file>content/shaders/genie.vert</file>
+ <file>content/shaders/+hlsl/genie.vert</file>
</qresource>
</RCC>
diff --git a/examples/quick/shared/Label.qml b/examples/quick/shared/Label.qml
new file mode 100644
index 0000000000..ea4bef5415
--- /dev/null
+++ b/examples/quick/shared/Label.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.0
+
+Text {
+ SystemPalette { id: palette }
+ color: palette.text
+}
diff --git a/examples/quick/shared/quick_shared.qrc b/examples/quick/shared/quick_shared.qrc
index ea7e0fdd89..21f393a64d 100644
--- a/examples/quick/shared/quick_shared.qrc
+++ b/examples/quick/shared/quick_shared.qrc
@@ -4,6 +4,7 @@
<file>SimpleLauncherDelegate.qml</file>
<file>Button.qml</file>
<file>CheckBox.qml</file>
+ <file>Label.qml</file>
<file>TextField.qml</file>
<file>images/back.png</file>
<file>images/next.png</file>
diff --git a/examples/quick/shared/shared.qrc b/examples/quick/shared/shared.qrc
index 7e0c66c34b..89b3ff757e 100644
--- a/examples/quick/shared/shared.qrc
+++ b/examples/quick/shared/shared.qrc
@@ -6,6 +6,7 @@
<file>Slider.qml</file>
<file>images/slider_handle.png</file>
<file>CheckBox.qml</file>
+ <file>Label.qml</file>
<file>TabSet.qml</file>
<file>TextField.qml</file>
<file>images/back.png</file>
diff --git a/examples/quick/textureprovider/etcprovider.cpp b/examples/quick/textureprovider/etcprovider.cpp
index c713cf1ffd..de8eb12366 100644
--- a/examples/quick/textureprovider/etcprovider.cpp
+++ b/examples/quick/textureprovider/etcprovider.cpp
@@ -98,7 +98,7 @@ unsigned short getPaddedHeight(ETCHeader *pHeader)
EtcTexture::EtcTexture()
: m_texture_id(0), m_uploaded(false)
{
-
+ initializeOpenGLFunctions();
}
EtcTexture::~EtcTexture()
@@ -109,8 +109,10 @@ EtcTexture::~EtcTexture()
int EtcTexture::textureId() const
{
- if (m_texture_id == 0)
- glGenTextures(1, &const_cast<EtcTexture *>(this)->m_texture_id);
+ if (m_texture_id == 0) {
+ EtcTexture *texture = const_cast<EtcTexture*>(this);
+ texture->glGenTextures(1, &texture->m_texture_id);
+ }
return m_texture_id;
}
diff --git a/examples/quick/textureprovider/etcprovider.h b/examples/quick/textureprovider/etcprovider.h
index 75903963e4..44d5d6f53e 100644
--- a/examples/quick/textureprovider/etcprovider.h
+++ b/examples/quick/textureprovider/etcprovider.h
@@ -51,7 +51,7 @@
#ifndef ETCPROVIDER_H
#define ETCPROVIDER_H
-#include <qopengl.h>
+#include <QOpenGLFunctions>
#include <QQuickImageProvider>
#include <QtQuick/QSGTexture>
#include <QUrl>
@@ -71,7 +71,7 @@ private:
QUrl m_baseUrl;
};
-class EtcTexture : public QSGTexture
+class EtcTexture : public QSGTexture, protected QOpenGLFunctions
{
Q_OBJECT
public:
diff --git a/examples/quick/window/AllScreens.qml b/examples/quick/window/AllScreens.qml
new file mode 100644
index 0000000000..83a6c5f958
--- /dev/null
+++ b/examples/quick/window/AllScreens.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.3
+import QtQuick.Window 2.3
+import "../shared" as Shared
+
+Column {
+ id: root
+ spacing: 8
+
+ Shared.Label {
+ text: "Total number of screens: " + screenInfo.count
+ font.bold: true
+ }
+
+ Flow {
+ spacing: 12
+ width: parent.width
+
+ Repeater {
+ id: screenInfo
+ model: Qt.application.screens
+ Shared.Label {
+ lineHeight: 1.5
+ text: name + "\n" + virtualX + ", " + virtualY + " " + modelData.width + "x" + modelData.height
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ var screens = Qt.application.screens;
+ for (var i = 0; i < screens.length; ++i)
+ console.log("screen " + screens[i].name + " has geometry " +
+ screens[i].virtualX + ", " + screens[i].virtualY + " " +
+ screens[i].width + "x" + screens[i].height)
+ }
+}
diff --git a/examples/quick/window/ScreenInfo.qml b/examples/quick/window/CurrentScreen.qml
index ee0a31c794..c65baab1f4 100644
--- a/examples/quick/window/ScreenInfo.qml
+++ b/examples/quick/window/CurrentScreen.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -40,6 +40,7 @@
import QtQuick 2.3
import QtQuick.Window 2.1
+import "../shared" as Shared
Item {
id: root
@@ -70,32 +71,35 @@ Item {
y: spacing
//! [screen]
- Text {
+ Shared.Label {
text: "Screen \"" + Screen.name + "\":"
font.bold: true
}
Item { width: 1; height: 1 } // spacer
- Text { text: "dimensions" }
- Text { text: Screen.width + "x" + Screen.height }
+ Shared.Label { text: "dimensions" }
+ Shared.Label { text: Screen.width + "x" + Screen.height }
- Text { text: "pixel density" }
- Text { text: Screen.pixelDensity.toFixed(2) + " dots/mm (" + (Screen.pixelDensity * 25.4).toFixed(2) + " dots/inch)" }
+ Shared.Label { text: "pixel density" }
+ Shared.Label { text: Screen.pixelDensity.toFixed(2) + " dots/mm (" + (Screen.pixelDensity * 25.4).toFixed(2) + " dots/inch)" }
- Text { text: "logical pixel density" }
- Text { text: Screen.logicalPixelDensity.toFixed(2) + " dots/mm (" + (Screen.logicalPixelDensity * 25.4).toFixed(2) + " dots/inch)" }
+ Shared.Label { text: "logical pixel density" }
+ Shared.Label { text: Screen.logicalPixelDensity.toFixed(2) + " dots/mm (" + (Screen.logicalPixelDensity * 25.4).toFixed(2) + " dots/inch)" }
- Text { text: "device pixel ratio" }
- Text { text: Screen.devicePixelRatio.toFixed(2) }
+ Shared.Label { text: "device pixel ratio" }
+ Shared.Label { text: Screen.devicePixelRatio.toFixed(2) }
- Text { text: "available virtual desktop" }
- Text { text: Screen.desktopAvailableWidth + "x" + Screen.desktopAvailableHeight }
+ Shared.Label { text: "available virtual desktop" }
+ Shared.Label { text: Screen.desktopAvailableWidth + "x" + Screen.desktopAvailableHeight }
- Text { text: "orientation" }
- Text { text: orientationToString(Screen.orientation) + " (" + Screen.orientation + ")" }
+ Shared.Label { text: "position in virtual desktop" }
+ Shared.Label { text: Screen.virtualX + ", " + Screen.virtualY }
- Text { text: "primary orientation" }
- Text { text: orientationToString(Screen.primaryOrientation) + " (" + Screen.primaryOrientation + ")" }
+ Shared.Label { text: "orientation" }
+ Shared.Label { text: orientationToString(Screen.orientation) + " (" + Screen.orientation + ")" }
+
+ Shared.Label { text: "primary orientation" }
+ Shared.Label { text: orientationToString(Screen.primaryOrientation) + " (" + Screen.primaryOrientation + ")" }
//! [screen]
}
}
diff --git a/examples/quick/window/Splash.qml b/examples/quick/window/Splash.qml
index 083c3babc8..3baf207992 100644
--- a/examples/quick/window/Splash.qml
+++ b/examples/quick/window/Splash.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
diff --git a/examples/quick/window/doc/src/window.qdoc b/examples/quick/window/doc/src/window.qdoc
index 5cd51beceb..2028b31383 100644
--- a/examples/quick/window/doc/src/window.qdoc
+++ b/examples/quick/window/doc/src/window.qdoc
@@ -73,7 +73,7 @@
\l Screen has several properties which are generally useful to
applications which need to rotate some content when the screen orientation
changes, to position windows on the screen or to convert real units to
- logical pixel units. ScreenInfo.qml (which is displayed inline in
+ logical pixel units. CurrentScreen.qml (which is displayed inline in
window.qml, or can be run by itself with qmlscene) simply displays the
property values, while the splash screen uses them to center the window on
the screen.
diff --git a/examples/quick/window/main.cpp b/examples/quick/window/main.cpp
index bacf52af15..ee8855cbc8 100644
--- a/examples/quick/window/main.cpp
+++ b/examples/quick/window/main.cpp
@@ -49,7 +49,8 @@
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
- foreach (QScreen * screen, QGuiApplication::screens())
+ const auto screens = QGuiApplication::screens();
+ for (QScreen *screen : screens)
screen->setOrientationUpdateMask(Qt::LandscapeOrientation | Qt::PortraitOrientation |
Qt::InvertedLandscapeOrientation | Qt::InvertedPortraitOrientation);
QQmlEngine engine;
diff --git a/examples/quick/window/window.qml b/examples/quick/window/window.qml
index d50bce61b3..d27ab3d0a3 100644
--- a/examples/quick/window/window.qml
+++ b/examples/quick/window/window.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -39,7 +39,7 @@
****************************************************************************/
import QtQuick 2.0
-import QtQuick.Window 2.1
+import QtQuick.Window 2.3
import "../shared" as Shared
QtObject {
@@ -47,7 +47,7 @@ QtObject {
property SystemPalette palette: SystemPalette { }
property var controlWindow: Window {
- width: visibilityLabel.implicitWidth * 1.2
+ width: col.implicitWidth + defaultSpacing * 2
height: col.implicitHeight + defaultSpacing * 2
color: palette.window
title: "Control Window"
@@ -57,7 +57,7 @@ QtObject {
anchors.margins: defaultSpacing
spacing: defaultSpacing
property real cellWidth: col.width / 3 - spacing
- Text { text: "Control the second window:" }
+ Shared.Label { text: "Control the second window:" }
Grid {
id: grid
columns: 3
@@ -121,18 +121,23 @@ QtObject {
}
return "unknown";
}
- Text {
+ Shared.Label {
id: visibilityLabel
text: "second window is " + (testWindow.visible ? "visible" : "invisible") +
" and has visibility " + parent.visibilityToString(testWindow.visibility)
}
Rectangle {
- id: horizontalRule
- color: "black"
+ color: palette.text
width: parent.width
height: 1
}
- ScreenInfo { }
+ CurrentScreen { }
+ Rectangle {
+ color: palette.text
+ width: parent.width
+ height: 1
+ }
+ AllScreens { width: parent.width }
}
}
@@ -145,7 +150,7 @@ QtObject {
Rectangle {
anchors.fill: parent
anchors.margins: defaultSpacing
- Text {
+ Shared.Label {
anchors.centerIn: parent
text: "Second Window"
}
diff --git a/examples/quick/window/window.qrc b/examples/quick/window/window.qrc
index dc211bdaaf..89d1de1b1f 100644
--- a/examples/quick/window/window.qrc
+++ b/examples/quick/window/window.qrc
@@ -2,6 +2,7 @@
<qresource prefix="/window">
<file>window.qml</file>
<file>Splash.qml</file>
- <file>ScreenInfo.qml</file>
+ <file>CurrentScreen.qml</file>
+ <file>AllScreens.qml</file>
</qresource>
</RCC>
diff --git a/src/3rdparty/masm/LICENSE b/src/3rdparty/masm/LICENSE
new file mode 100644
index 0000000000..3ab4db6d84
--- /dev/null
+++ b/src/3rdparty/masm/LICENSE
@@ -0,0 +1,22 @@
+Copyright (C) 2012 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. 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.
+
+THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri
index b5480babc6..fa0d3d3c55 100644
--- a/src/3rdparty/masm/masm-defs.pri
+++ b/src/3rdparty/masm/masm-defs.pri
@@ -24,7 +24,8 @@ INCLUDEPATH += $$PWD
disassembler {
if(isEqual(QT_ARCH, "i386")|isEqual(QT_ARCH, "x86_64")): DEFINES += WTF_USE_UDIS86=1
- if(isEqual(QT_ARCH, "arm")): DEFINES += WTF_USE_ARMV7_DISASSEMBLER=1 WTF_USE_ARM64_DISASSEMBLER=1
+ if(isEqual(QT_ARCH, "arm")): DEFINES += WTF_USE_ARMV7_DISASSEMBLER=1
+ if(isEqual(QT_ARCH, "arm64")): DEFINES += WTF_USE_ARM64_DISASSEMBLER=1
if(isEqual(QT_ARCH, "mips")): DEFINES += WTF_USE_MIPS32_DISASSEMBLER=1
} else {
DEFINES += WTF_USE_UDIS86=0
diff --git a/src/3rdparty/masm/qt_attribution.json b/src/3rdparty/masm/qt_attribution.json
new file mode 100644
index 0000000000..c53f1a4bc5
--- /dev/null
+++ b/src/3rdparty/masm/qt_attribution.json
@@ -0,0 +1,23 @@
+{
+ "Id": "masm",
+ "Name": "JavaScriptCore Macro Assembler",
+ "QDocModule": "qtqml",
+ "QtUsage": "Used in Qt QML.",
+
+ "License": "BSD 2-clause \"Simplified\" License",
+ "LicenseId": "BSD-2-Clause",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (C) 2003-2015 Apple Inc. All rights reserved.
+Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved. (http://www.torchmobile.com/)
+Copyright (C) 2009, 2010 University of Szeged
+Copyright (C) 2009-2011 STMicroelectronics. All rights reserved.
+Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
+Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
+Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
+Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved.
+Copyright (C) 2011 Google Inc. All rights reserved.
+Copyright (C) 2013 Samsung Electronics. All rights reserved.
+Copyright (C) 2015 Cisco Systems, Inc. All rights reserved.
+Copyright (c) 2002-2009 Vivek Thampi"
+}
diff --git a/src/3rdparty/masm/wtf/MathExtras.h b/src/3rdparty/masm/wtf/MathExtras.h
index 9ded0ab736..9c38af6b16 100644
--- a/src/3rdparty/masm/wtf/MathExtras.h
+++ b/src/3rdparty/masm/wtf/MathExtras.h
@@ -43,7 +43,7 @@
#include <machine/ieee.h>
#endif
-#if OS(QNX)
+#if OS(QNX) && defined(_CPPLIB_VER)
// FIXME: Look into a way to have cmath import its functions into both the standard and global
// namespace. For now, we include math.h since the QNX cmath header only imports its functions
// into the standard namespace.
@@ -106,7 +106,7 @@ inline bool isinf(double x) { return !finite(x) && !isnand(x); }
#endif
-#if OS(OPENBSD)
+#if OS(OPENBSD) && __cplusplus < 201103L
namespace std {
diff --git a/src/3rdparty/masm/wtf/StdLibExtras.h b/src/3rdparty/masm/wtf/StdLibExtras.h
index 605f98ec82..f0d792ed52 100644
--- a/src/3rdparty/masm/wtf/StdLibExtras.h
+++ b/src/3rdparty/masm/wtf/StdLibExtras.h
@@ -166,7 +166,7 @@ template<typename T> char (&ArrayLengthHelperFunction(T (&)[0]))[0];
// Efficient implementation that takes advantage of powers of two.
inline size_t roundUpToMultipleOf(size_t divisor, size_t x)
{
- ASSERT(divisor && !(divisor & (divisor - 1)));
+ Q_ASSERT(divisor && !(divisor & (divisor - 1)));
size_t remainderMask = divisor - 1;
return (x + remainderMask) & ~remainderMask;
}
diff --git a/src/3rdparty/masm/yarr/YarrJIT.cpp b/src/3rdparty/masm/yarr/YarrJIT.cpp
index 5664c585b9..d8211ec4b2 100644
--- a/src/3rdparty/masm/yarr/YarrJIT.cpp
+++ b/src/3rdparty/masm/yarr/YarrJIT.cpp
@@ -338,17 +338,31 @@ class YarrGenerator : private MacroAssembler {
jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
}
+ unsigned alignCallFrameSizeInBytes(unsigned callFrameSize)
+ {
+ callFrameSize *= sizeof(void*);
+ if (callFrameSize / sizeof(void*) != m_pattern.m_body->m_callFrameSize)
+ CRASH();
+ // Originally, the code was:
+// callFrameSize = (callFrameSize + 0x3f) & ~0x3f;
+ // However, 64 bytes is a bit surprising. The biggest "alignment" requirement is on Aarch64, where:
+ // "SP mod 16 = 0. The stack must be quad-word aligned." (IHI0055B_aapcs64.pdf)
+ callFrameSize = (callFrameSize + 0xf) & ~0xf;
+ if (!callFrameSize)
+ CRASH();
+ return callFrameSize;
+ }
void initCallFrame()
{
unsigned callFrameSize = m_pattern.m_body->m_callFrameSize;
if (callFrameSize)
- subPtr(Imm32(callFrameSize * sizeof(void*)), stackPointerRegister);
+ subPtr(Imm32(alignCallFrameSizeInBytes(callFrameSize)), stackPointerRegister);
}
void removeCallFrame()
{
unsigned callFrameSize = m_pattern.m_body->m_callFrameSize;
if (callFrameSize)
- addPtr(Imm32(callFrameSize * sizeof(void*)), stackPointerRegister);
+ addPtr(Imm32(alignCallFrameSizeInBytes(callFrameSize)), stackPointerRegister);
}
// Used to record subpatters, should only be called if compileMode is IncludeSubpatterns.
@@ -2565,6 +2579,10 @@ class YarrGenerator : private MacroAssembler {
if (compileMode == IncludeSubpatterns)
loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
#endif
+#elif CPU(ARM64)
+ // The ABI doesn't guarantee the upper bits are zero on unsigned arguments, so clear them ourselves.
+ zeroExtend32ToPtr(index, index);
+ zeroExtend32ToPtr(length, length);
#elif CPU(ARM)
push(ARMRegisters::r4);
push(ARMRegisters::r5);
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes
index cca1c20d54..88e3ac6634 100644
--- a/src/imports/builtins/builtins.qmltypes
+++ b/src/imports/builtins/builtins.qmltypes
@@ -198,9 +198,7 @@ Module {
"MacWindowToolBarButtonHint": 268435456,
"BypassGraphicsProxyWidget": 536870912,
"NoDropShadowWindowHint": 1073741824,
- "WindowFullscreenButtonHint": -2147483648,
- "WindowOkButtonHint": 524288,
- "WindowCancelButtonHint": 1048576
+ "WindowFullscreenButtonHint": -2147483648
}
}
Enum {
@@ -243,9 +241,7 @@ Module {
"MacWindowToolBarButtonHint": 268435456,
"BypassGraphicsProxyWidget": 536870912,
"NoDropShadowWindowHint": 1073741824,
- "WindowFullscreenButtonHint": -2147483648,
- "WindowOkButtonHint": 524288,
- "WindowCancelButtonHint": 1048576
+ "WindowFullscreenButtonHint": -2147483648
}
}
Enum {
@@ -422,6 +418,7 @@ Module {
"AA_DontShowIconsInMenus": 2,
"AA_NativeWindows": 3,
"AA_DontCreateNativeWidgetSiblings": 4,
+ "AA_PluginApplication": 5,
"AA_MacPluginApplication": 5,
"AA_DontUseNativeMenuBar": 6,
"AA_MacDontSwapCtrlAndMeta": 7,
@@ -438,7 +435,12 @@ Module {
"AA_SetPalette": 19,
"AA_EnableHighDpiScaling": 20,
"AA_DisableHighDpiScaling": 21,
- "AA_AttributeCount": 22
+ "AA_UseStyleSheetPropagationInWidgetStyles": 22,
+ "AA_DontUseNativeDialogs": 23,
+ "AA_SynthesizeMouseForUnhandledTabletEvents": 24,
+ "AA_CompressHighFrequencyEvents": 25,
+ "AA_DontCheckOpenGLContextThreadAffinity": 26,
+ "AA_AttributeCount": 27
}
}
Enum {
@@ -1274,8 +1276,10 @@ Module {
"ImTextBeforeCursor": 2048,
"ImTextAfterCursor": 4096,
"ImEnterKeyType": 8192,
+ "ImAnchorRectangle": 16384,
+ "ImInputItemClipRectangle": 32768,
"ImPlatformData": -2147483648,
- "ImQueryInput": 186,
+ "ImQueryInput": 16570,
"ImQueryAll": -1
}
}
@@ -1297,8 +1301,10 @@ Module {
"ImTextBeforeCursor": 2048,
"ImTextAfterCursor": 4096,
"ImEnterKeyType": 8192,
+ "ImAnchorRectangle": 16384,
+ "ImInputItemClipRectangle": 32768,
"ImPlatformData": -2147483648,
- "ImQueryInput": 186,
+ "ImQueryInput": 16570,
"ImQueryAll": -1
}
}
@@ -1579,6 +1585,7 @@ Module {
Enum {
name: "ScrollPhase"
values: {
+ "NoScrollPhase": 0,
"ScrollBegin": 1,
"ScrollUpdate": 2,
"ScrollEnd": 3
diff --git a/src/imports/folderlistmodel/fileinfothread.cpp b/src/imports/folderlistmodel/fileinfothread.cpp
index 5d911eec1e..0b62935f87 100644
--- a/src/imports/folderlistmodel/fileinfothread.cpp
+++ b/src/imports/folderlistmodel/fileinfothread.cpp
@@ -260,14 +260,13 @@ void FileInfoThread::getFileInfos(const QString &path)
sortFlags = sortFlags | QDir::DirsFirst;
QDir currentDir(path, QString(), sortFlags);
- QFileInfoList fileInfoList;
QList<FileProperty> filePropertyList;
- fileInfoList = currentDir.entryInfoList(nameFilters, filter, sortFlags);
+ const QFileInfoList fileInfoList = currentDir.entryInfoList(nameFilters, filter, sortFlags);
if (!fileInfoList.isEmpty()) {
filePropertyList.reserve(fileInfoList.count());
- foreach (const QFileInfo &info, fileInfoList) {
+ for (const QFileInfo &info : fileInfoList) {
//qDebug() << "Adding file : " << info.fileName() << "to list ";
filePropertyList << FileProperty(info);
}
diff --git a/src/imports/folderlistmodel/fileinfothread_p.h b/src/imports/folderlistmodel/fileinfothread_p.h
index 8a154f264e..56058fd6be 100644
--- a/src/imports/folderlistmodel/fileinfothread_p.h
+++ b/src/imports/folderlistmodel/fileinfothread_p.h
@@ -94,7 +94,7 @@ public Q_SLOTS:
#endif
protected:
- void run();
+ void run() override;
void getFileInfos(const QString &path);
void findChangeRange(const QList<FileProperty> &list, int &fromIndex, int &toIndex);
diff --git a/src/imports/folderlistmodel/fileproperty_p.h b/src/imports/folderlistmodel/fileproperty_p.h
index f385cdfdb4..48be4a3d85 100644
--- a/src/imports/folderlistmodel/fileproperty_p.h
+++ b/src/imports/folderlistmodel/fileproperty_p.h
@@ -57,17 +57,17 @@
class FileProperty
{
public:
- FileProperty(const QFileInfo &info)
+ FileProperty(const QFileInfo &info) :
+ mFileName(info.fileName()),
+ mFilePath(info.filePath()),
+ mBaseName(info.baseName()),
+ mSuffix(info.completeSuffix()),
+ mSize(info.size()),
+ mIsDir(info.isDir()),
+ mIsFile(info.isFile()),
+ mLastModified(info.lastModified()),
+ mLastRead(info.lastRead())
{
- mFileName = info.fileName();
- mFilePath = info.filePath();
- mBaseName = info.baseName();
- mSize = info.size();
- mSuffix = info.completeSuffix();
- mIsDir = info.isDir();
- mIsFile = info.isFile();
- mLastModified = info.lastModified();
- mLastRead = info.lastRead();
}
~FileProperty()
{}
diff --git a/src/imports/folderlistmodel/plugins.qmltypes b/src/imports/folderlistmodel/plugins.qmltypes
index 02127c63cb..e77b633932 100644
--- a/src/imports/folderlistmodel/plugins.qmltypes
+++ b/src/imports/folderlistmodel/plugins.qmltypes
@@ -4,284 +4,20 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable Qt.labs.folderlistmodel 2.1'
+// 'qmlplugindump -nonrelocatable Qt.labs.folderlistmodel 2.2'
Module {
- dependencies: []
- Component {
- name: "QAbstractItemModel"
- prototype: "QObject"
- Enum {
- name: "LayoutChangeHint"
- values: {
- "NoLayoutChangeHint": 0,
- "VerticalSortHint": 1,
- "HorizontalSortHint": 2
- }
- }
- Signal {
- name: "dataChanged"
- Parameter { name: "topLeft"; type: "QModelIndex" }
- Parameter { name: "bottomRight"; type: "QModelIndex" }
- Parameter { name: "roles"; type: "QVector<int>" }
- }
- Signal {
- name: "dataChanged"
- Parameter { name: "topLeft"; type: "QModelIndex" }
- Parameter { name: "bottomRight"; type: "QModelIndex" }
- }
- Signal {
- name: "headerDataChanged"
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "layoutChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
- }
- Signal {
- name: "layoutChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- }
- Signal { name: "layoutChanged" }
- Signal {
- name: "layoutAboutToBeChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
- }
- Signal {
- name: "layoutAboutToBeChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- }
- Signal { name: "layoutAboutToBeChanged" }
- Signal {
- name: "rowsAboutToBeInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsAboutToBeRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal { name: "modelAboutToBeReset" }
- Signal { name: "modelReset" }
- Signal {
- name: "rowsAboutToBeMoved"
- Parameter { name: "sourceParent"; type: "QModelIndex" }
- Parameter { name: "sourceStart"; type: "int" }
- Parameter { name: "sourceEnd"; type: "int" }
- Parameter { name: "destinationParent"; type: "QModelIndex" }
- Parameter { name: "destinationRow"; type: "int" }
- }
- Signal {
- name: "rowsMoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "start"; type: "int" }
- Parameter { name: "end"; type: "int" }
- Parameter { name: "destination"; type: "QModelIndex" }
- Parameter { name: "row"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeMoved"
- Parameter { name: "sourceParent"; type: "QModelIndex" }
- Parameter { name: "sourceStart"; type: "int" }
- Parameter { name: "sourceEnd"; type: "int" }
- Parameter { name: "destinationParent"; type: "QModelIndex" }
- Parameter { name: "destinationColumn"; type: "int" }
- }
- Signal {
- name: "columnsMoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "start"; type: "int" }
- Parameter { name: "end"; type: "int" }
- Parameter { name: "destination"; type: "QModelIndex" }
- Parameter { name: "column"; type: "int" }
- }
- Method { name: "submit"; type: "bool" }
- Method { name: "revert" }
- Method {
- name: "hasIndex"
- type: "bool"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "hasIndex"
- type: "bool"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- }
- Method {
- name: "index"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "index"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- }
- Method {
- name: "parent"
- type: "QModelIndex"
- Parameter { name: "child"; type: "QModelIndex" }
- }
- Method {
- name: "sibling"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "idx"; type: "QModelIndex" }
- }
- Method {
- name: "rowCount"
- type: "int"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "rowCount"; type: "int" }
- Method {
- name: "columnCount"
- type: "int"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "columnCount"; type: "int" }
- Method {
- name: "hasChildren"
- type: "bool"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "hasChildren"; type: "bool" }
- Method {
- name: "data"
- type: "QVariant"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "data"
- type: "QVariant"
- Parameter { name: "index"; type: "QModelIndex" }
- }
- Method {
- name: "setData"
- type: "bool"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "setData"
- type: "bool"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "value"; type: "QVariant" }
- }
- Method {
- name: "headerData"
- type: "QVariant"
- Parameter { name: "section"; type: "int" }
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "headerData"
- type: "QVariant"
- Parameter { name: "section"; type: "int" }
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- }
- Method {
- name: "fetchMore"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "canFetchMore"
- type: "bool"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "flags"
- type: "Qt::ItemFlags"
- Parameter { name: "index"; type: "QModelIndex" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "hits"; type: "int" }
- Parameter { name: "flags"; type: "Qt::MatchFlags" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "hits"; type: "int" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- }
- }
- Component { name: "QAbstractListModel"; prototype: "QAbstractItemModel" }
+ dependencies: ["QtQuick 2.8"]
Component {
name: "QQuickFolderListModel"
prototype: "QAbstractListModel"
exports: [
"Qt.labs.folderlistmodel/FolderListModel 1.0",
"Qt.labs.folderlistmodel/FolderListModel 2.0",
- "Qt.labs.folderlistmodel/FolderListModel 2.1"
+ "Qt.labs.folderlistmodel/FolderListModel 2.1",
+ "Qt.labs.folderlistmodel/FolderListModel 2.2"
]
- exportMetaObjectRevisions: [0, 0, 1]
+ exportMetaObjectRevisions: [0, 0, 1, 2]
Enum {
name: "SortField"
values: {
@@ -304,6 +40,7 @@ Module {
Property { name: "showDotAndDotDot"; type: "bool" }
Property { name: "showHidden"; revision: 1; type: "bool" }
Property { name: "showOnlyReadable"; type: "bool" }
+ Property { name: "caseSensitive"; revision: 2; type: "bool" }
Property { name: "count"; type: "int"; isReadonly: true }
Signal { name: "rowCountChanged" }
Signal { name: "countChanged"; revision: 1 }
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index 66af37c40c..1c94fddecf 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -491,10 +491,11 @@ QUrl QQuickFolderListModel::parentFolder() const
return QUrl();
localFile = dir.path();
} else {
- const int pos = d->currentDir.path().lastIndexOf(QLatin1Char('/'));
+ const QString path = d->currentDir.path();
+ const int pos = path.lastIndexOf(QLatin1Char('/'));
if (pos <= 0)
return QUrl();
- localFile = d->currentDir.path().left(pos);
+ localFile = path.left(pos);
}
return QUrl::fromLocalFile(localFile);
}
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.h b/src/imports/folderlistmodel/qquickfolderlistmodel.h
index aae6df452d..dee73dff3e 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.h
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.h
@@ -94,10 +94,10 @@ public:
FileUrlRole = Qt::UserRole + 9
};
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
- virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
- virtual QHash<int, QByteArray> roleNames() const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
//![abslistmodel]
//![count]
@@ -144,8 +144,8 @@ public:
Q_INVOKABLE int indexOf(const QUrl &file) const;
//![parserstatus]
- virtual void classBegin();
- virtual void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
//![parserstatus]
int roleFromString(const QString &roleName) const;
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index 9e3cdf3f42..affc1db2c0 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -16,10 +16,8 @@ qtHaveModule(quick) {
window \
testlib
- contains(QT_CONFIG, opengl(es1|es2)?) {
- SUBDIRS += \
- particles
- }
+ qtConfig(opengl(es1|es2)?): \
+ SUBDIRS += particles
}
qtHaveModule(xmlpatterns) : SUBDIRS += xmllistmodel
diff --git a/src/imports/layouts/plugins.qmltypes b/src/imports/layouts/plugins.qmltypes
index b130215b62..afb563391d 100644
--- a/src/imports/layouts/plugins.qmltypes
+++ b/src/imports/layouts/plugins.qmltypes
@@ -4,10 +4,10 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQuick.Layouts 1.2'
+// 'qmlplugindump -nonrelocatable QtQuick.Layouts 1.3'
Module {
- dependencies: []
+ dependencies: ["QtQuick 2.8"]
Component {
name: "QQuickColumnLayout"
defaultProperty: "data"
diff --git a/src/imports/layouts/qquickgridlayoutengine_p.h b/src/imports/layouts/qquickgridlayoutengine_p.h
index 86f56a5af4..2810e2e5d0 100644
--- a/src/imports/layouts/qquickgridlayoutengine_p.h
+++ b/src/imports/layouts/qquickgridlayoutengine_p.h
@@ -67,7 +67,7 @@ public:
: QGridLayoutItem(row, column, rowSpan, columnSpan, alignment), m_item(item), sizeHintCacheDirty(true), useFallbackToWidthOrHeight(true) {}
- QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const override
{
Q_UNUSED(constraint); // Quick Layouts does not support constraint atm
return effectiveSizeHints()[which];
@@ -99,12 +99,12 @@ public:
sizeHintCacheDirty = true;
}
- QLayoutPolicy::Policy sizePolicy(Qt::Orientation orientation) const
+ QLayoutPolicy::Policy sizePolicy(Qt::Orientation orientation) const override
{
return QQuickLayout::effectiveSizePolicy_helper(m_item, orientation, attachedLayoutObject(m_item, false));
}
- void setGeometry(const QRectF &rect)
+ void setGeometry(const QRectF &rect) override
{
QQuickLayoutAttached *info = attachedLayoutObject(m_item, false);
const QRectF r = info ? rect.marginsRemoved(info->qMargins()) : rect;
diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp
index abc8f97cec..07ada75a5f 100644
--- a/src/imports/layouts/qquicklayout.cpp
+++ b/src/imports/layouts/qquicklayout.cpp
@@ -698,6 +698,10 @@ QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent)
QQuickLayout::~QQuickLayout()
{
d_func()->m_isReady = false;
+
+ const auto childItems = d_func()->childItems;
+ for (QQuickItem *child : childItems)
+ QQuickItemPrivate::get(child)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder);
}
QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object)
@@ -754,27 +758,22 @@ bool QQuickLayout::shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&in
d->m_ignoredItems << child;
return ignoreItem;
}
-struct QQuickItemPublic : public QQuickItem {
- static bool isCompleted(QQuickItem *item) {
- return static_cast<QQuickItemPublic*>(item)->isComponentComplete();
- }
-};
void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
{
if (change == ItemChildAddedChange) {
QQuickItem *item = value.item;
- QObject::connect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem()));
- QObject::connect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem()));
- QObject::connect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem()));
+ qmlobject_connect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ qmlobject_connect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::SiblingOrder);
if (isReady())
updateLayoutItems();
} else if (change == ItemChildRemovedChange) {
QQuickItem *item = value.item;
- QObject::disconnect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem()));
- QObject::disconnect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem()));
- QObject::disconnect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder);
if (isReady())
updateLayoutItems();
diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp
index 0b4a1968d7..fdf8479133 100644
--- a/src/imports/layouts/qquicklinearlayout.cpp
+++ b/src/imports/layouts/qquicklinearlayout.cpp
@@ -333,10 +333,10 @@ QQuickGridLayoutBase::~QQuickGridLayoutBase()
*/
for (int i = 0; i < itemCount(); ++i) {
QQuickItem *item = itemAt(i);
- QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed()));
- QObject::disconnect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged()));
- QObject::disconnect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem()));
- QObject::disconnect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickGridLayoutBase, SLOT(invalidateSenderItem()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickGridLayoutBase, SLOT(invalidateSenderItem()));
}
delete d->styleInfo;
}
@@ -465,13 +465,13 @@ void QQuickGridLayoutBase::itemChange(ItemChange change, const ItemChangeData &v
if (change == ItemChildAddedChange) {
quickLayoutDebug() << "ItemChildAddedChange";
QQuickItem *item = value.item;
- QObject::connect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed()));
- QObject::connect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged()));
+ qmlobject_connect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
+ qmlobject_connect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
} else if (change == ItemChildRemovedChange) {
quickLayoutDebug() << "ItemChildRemovedChange";
QQuickItem *item = value.item;
- QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed()));
- QObject::disconnect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
}
QQuickLayout::itemChange(change, value);
diff --git a/src/imports/layouts/qquicklinearlayout_p.h b/src/imports/layouts/qquicklinearlayout_p.h
index 86404f8d79..ca8b867824 100644
--- a/src/imports/layouts/qquicklinearlayout_p.h
+++ b/src/imports/layouts/qquicklinearlayout_p.h
@@ -158,7 +158,7 @@ public:
Flow flow() const;
void setFlow(Flow flow);
- void insertLayoutItems();
+ void insertLayoutItems() override;
signals:
void columnSpacingChanged();
@@ -200,7 +200,7 @@ public:
qreal spacing() const;
void setSpacing(qreal spacing);
- void insertLayoutItems();
+ void insertLayoutItems() override;
signals:
void spacingChanged();
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 3fd36f3f0d..4d7f7c9467 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -270,6 +270,15 @@ static ReturnedValue qmlsqldatabase_rows_item(CallContext *ctx)
return qmlsqldatabase_rows_index(r, scope.engine, ctx->argc() ? ctx->args()[0].toUInt32() : 0);
}
+static QVariant toSqlVariant(QV4::ExecutionEngine *engine, const QV4::ScopedValue &value)
+{
+ // toVariant() maps a null JS value to QVariant(VoidStar), but the SQL module
+ // expects a null variant. (this is because of QTBUG-40880)
+ if (value->isNull())
+ return QVariant();
+ return engine->toVariant(value, /*typehint*/-1);
+}
+
static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx)
{
QV4::Scope scope(ctx);
@@ -300,8 +309,9 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx)
ScopedArrayObject array(scope, values);
quint32 size = array->getLength();
QV4::ScopedValue v(scope);
- for (quint32 ii = 0; ii < size; ++ii)
- query.bindValue(ii, scope.engine->toVariant((v = array->getIndexed(ii)), -1));
+ for (quint32 ii = 0; ii < size; ++ii) {
+ query.bindValue(ii, toSqlVariant(scope.engine, (v = array->getIndexed(ii))));
+ }
} else if (values->as<Object>()) {
ScopedObject object(scope, values);
ObjectIterator it(scope, object, ObjectIterator::WithProtoChain|ObjectIterator::EnumerableOnly);
@@ -311,7 +321,7 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx)
key = it.nextPropertyName(val);
if (key->isNull())
break;
- QVariant v = scope.engine->toVariant(val, -1);
+ QVariant v = toSqlVariant(scope.engine, val);
if (key->isString()) {
query.bindValue(key->stringValue()->toQString(), v);
} else {
@@ -320,7 +330,7 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx)
}
}
} else {
- query.bindValue(0, scope.engine->toVariant(values, -1));
+ query.bindValue(0, toSqlVariant(scope.engine, values));
}
}
if (query.exec()) {
@@ -416,7 +426,7 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
callData->args[0] = w;
TransactionRollback rollbackOnException(&db, &w->d()->inTransaction);
- callback->call(callData);
+ callback->call(scope, callData);
rollbackOnException.clear();
if (!db.commit()) {
db.rollback();
@@ -464,7 +474,7 @@ static ReturnedValue qmlsqldatabase_transaction_shared(CallContext *ctx, bool re
callData->thisObject = scope.engine->globalObject;
callData->args[0] = w;
TransactionRollback rollbackOnException(&db, &w->d()->inTransaction);
- callback->call(callData);
+ callback->call(scope, callData);
rollbackOnException.clear();
if (!db.commit())
@@ -575,9 +585,9 @@ import QtQuick.LocalStorage 2.0 as Sql
db = Sql.openDatabaseSync(identifier, version, description, estimated_size, callback(db))
\endcode
The above code returns the database identified by \e identifier. If the database does not already exist, it
-is created, and the function \e callback is called with the database as a parameter. \e description
-and \e estimated_size are written to the INI file (described below), but are otherwise currently
-unused.
+is created, and the function \e callback is called with the database as a parameter. \e identifier is the
+name of the physical file (with or without full path) containing the database. \e description and
+\e estimated_size are written to the INI file (described below), but are currently unused.
May throw exception with code property SQLException.DATABASE_ERR, or SQLException.VERSION_ERR.
@@ -585,7 +595,7 @@ When a database is first created, an INI file is also created specifying its cha
\table
\header \li \b {Key} \li \b {Value}
-\row \li Name \li The name of the database passed to \c openDatabase()
+\row \li Identifier \li The name of the database passed to \c openDatabase()
\row \li Version \li The version of the database passed to \c openDatabase()
\row \li Description \li The description of the database passed to \c openDatabase()
\row \li EstimatedSize \li The estimated size (in bytes) of the database passed to \c openDatabase()
@@ -605,12 +615,19 @@ you can call \e executeSql on \e tx to upgrade the database.
May throw exception with code property SQLException.DATABASE_ERR or SQLException.UNKNOWN_ERR.
+See example below.
+
+\snippet qml/localstorage/dbtransaction.js 2
+
\section3 db.transaction(callback(tx))
This method creates a read/write transaction and passed to \e callback. In this function,
you can call \e executeSql on \e tx to read and modify the database.
If the callback throws exceptions, the transaction is rolled back.
+Below you will find an example of a database transaction which catches exceptions.
+
+\snippet qml/localstorage/dbtransaction.js 0
\section3 db.readTransaction(callback(tx))
@@ -633,6 +650,9 @@ It returns a results object, with the following properties:
May throw exception with code property SQLException.DATABASE_ERR, SQLException.SYNTAX_ERR, or SQLException.UNKNOWN_ERR.
+See below for an example:
+
+\snippet qml/localstorage/dbtransaction.js 1
\section1 Method Documentation
@@ -735,7 +755,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
ScopedCallData callData(scope, 1);
callData->thisObject = scope.engine->globalObject;
callData->args[0] = db;
- dbcreationCallback->call(callData);
+ dbcreationCallback->call(scope, callData);
}
args->setReturnValue(db.asReturnedValue());
@@ -763,7 +783,7 @@ public:
}
void registerTypes(const char *uri) Q_DECL_OVERRIDE
{
- Q_ASSERT(QLatin1String(uri) == "QtQuick.LocalStorage");
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.LocalStorage"));
qmlRegisterSingletonType<QQuickLocalStorage>(uri, 2, 0, "LocalStorage", module_api_factory);
}
};
diff --git a/src/imports/localstorage/plugins.qmltypes b/src/imports/localstorage/plugins.qmltypes
index 7d81cdf6f4..dee81a78d0 100644
--- a/src/imports/localstorage/plugins.qmltypes
+++ b/src/imports/localstorage/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQuick.LocalStorage 2.0'
+// 'qmlplugindump -nonrelocatable -noforceqtquick QtQuick.LocalStorage 2.0'
Module {
dependencies: []
diff --git a/src/imports/models/plugins.qmltypes b/src/imports/models/plugins.qmltypes
index 0bd52a13fd..aa06a2a709 100644
--- a/src/imports/models/plugins.qmltypes
+++ b/src/imports/models/plugins.qmltypes
@@ -7,272 +7,7 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable QtQml.Models 2.3'
Module {
- dependencies: []
- Component {
- name: "QAbstractItemModel"
- prototype: "QObject"
- Enum {
- name: "LayoutChangeHint"
- values: {
- "NoLayoutChangeHint": 0,
- "VerticalSortHint": 1,
- "HorizontalSortHint": 2
- }
- }
- Signal {
- name: "dataChanged"
- Parameter { name: "topLeft"; type: "QModelIndex" }
- Parameter { name: "bottomRight"; type: "QModelIndex" }
- Parameter { name: "roles"; type: "QVector<int>" }
- }
- Signal {
- name: "dataChanged"
- Parameter { name: "topLeft"; type: "QModelIndex" }
- Parameter { name: "bottomRight"; type: "QModelIndex" }
- }
- Signal {
- name: "headerDataChanged"
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "layoutChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
- }
- Signal {
- name: "layoutChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- }
- Signal { name: "layoutChanged" }
- Signal {
- name: "layoutAboutToBeChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
- }
- Signal {
- name: "layoutAboutToBeChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- }
- Signal { name: "layoutAboutToBeChanged" }
- Signal {
- name: "rowsAboutToBeInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsAboutToBeRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal { name: "modelAboutToBeReset" }
- Signal { name: "modelReset" }
- Signal {
- name: "rowsAboutToBeMoved"
- Parameter { name: "sourceParent"; type: "QModelIndex" }
- Parameter { name: "sourceStart"; type: "int" }
- Parameter { name: "sourceEnd"; type: "int" }
- Parameter { name: "destinationParent"; type: "QModelIndex" }
- Parameter { name: "destinationRow"; type: "int" }
- }
- Signal {
- name: "rowsMoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "start"; type: "int" }
- Parameter { name: "end"; type: "int" }
- Parameter { name: "destination"; type: "QModelIndex" }
- Parameter { name: "row"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeMoved"
- Parameter { name: "sourceParent"; type: "QModelIndex" }
- Parameter { name: "sourceStart"; type: "int" }
- Parameter { name: "sourceEnd"; type: "int" }
- Parameter { name: "destinationParent"; type: "QModelIndex" }
- Parameter { name: "destinationColumn"; type: "int" }
- }
- Signal {
- name: "columnsMoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "start"; type: "int" }
- Parameter { name: "end"; type: "int" }
- Parameter { name: "destination"; type: "QModelIndex" }
- Parameter { name: "column"; type: "int" }
- }
- Method { name: "submit"; type: "bool" }
- Method { name: "revert" }
- Method {
- name: "hasIndex"
- type: "bool"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "hasIndex"
- type: "bool"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- }
- Method {
- name: "index"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "index"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- }
- Method {
- name: "parent"
- type: "QModelIndex"
- Parameter { name: "child"; type: "QModelIndex" }
- }
- Method {
- name: "sibling"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "idx"; type: "QModelIndex" }
- }
- Method {
- name: "rowCount"
- type: "int"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "rowCount"; type: "int" }
- Method {
- name: "columnCount"
- type: "int"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "columnCount"; type: "int" }
- Method {
- name: "hasChildren"
- type: "bool"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "hasChildren"; type: "bool" }
- Method {
- name: "data"
- type: "QVariant"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "data"
- type: "QVariant"
- Parameter { name: "index"; type: "QModelIndex" }
- }
- Method {
- name: "setData"
- type: "bool"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "setData"
- type: "bool"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "value"; type: "QVariant" }
- }
- Method {
- name: "headerData"
- type: "QVariant"
- Parameter { name: "section"; type: "int" }
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "headerData"
- type: "QVariant"
- Parameter { name: "section"; type: "int" }
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- }
- Method {
- name: "fetchMore"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "canFetchMore"
- type: "bool"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "flags"
- type: "Qt::ItemFlags"
- Parameter { name: "index"; type: "QModelIndex" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "hits"; type: "int" }
- Parameter { name: "flags"; type: "Qt::MatchFlags" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "hits"; type: "int" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- }
- }
- Component { name: "QAbstractListModel"; prototype: "QAbstractItemModel" }
+ dependencies: ["QtQuick 2.8"]
Component {
name: "QItemSelectionModel"
prototype: "QObject"
@@ -384,203 +119,4 @@ Module {
}
Method { name: "selectedColumns"; type: "QModelIndexList" }
}
- Component {
- name: "QQmlDelegateModel"
- defaultProperty: "delegate"
- prototype: "QQmlInstanceModel"
- exports: ["QtQml.Models/DelegateModel 2.1"]
- exportMetaObjectRevisions: [0]
- attachedType: "QQmlDelegateModelAttached"
- Property { name: "model"; type: "QVariant" }
- Property { name: "delegate"; type: "QQmlComponent"; isPointer: true }
- Property { name: "filterOnGroup"; type: "string" }
- Property { name: "items"; type: "QQmlDelegateModelGroup"; isReadonly: true; isPointer: true }
- Property {
- name: "persistedItems"
- type: "QQmlDelegateModelGroup"
- isReadonly: true
- isPointer: true
- }
- Property { name: "groups"; type: "QQmlDelegateModelGroup"; isList: true; isReadonly: true }
- Property { name: "parts"; type: "QObject"; isReadonly: true; isPointer: true }
- Property { name: "rootIndex"; type: "QVariant" }
- Signal { name: "filterGroupChanged" }
- Signal { name: "defaultGroupsChanged" }
- Method {
- name: "modelIndex"
- type: "QVariant"
- Parameter { name: "idx"; type: "int" }
- }
- Method { name: "parentModelIndex"; type: "QVariant" }
- }
- Component {
- name: "QQmlDelegateModelAttached"
- prototype: "QObject"
- Property { name: "model"; type: "QQmlDelegateModel"; isReadonly: true; isPointer: true }
- Property { name: "groups"; type: "QStringList" }
- Property { name: "isUnresolved"; type: "bool"; isReadonly: true }
- Signal { name: "unresolvedChanged" }
- }
- Component {
- name: "QQmlDelegateModelGroup"
- prototype: "QObject"
- exports: ["QtQml.Models/DelegateModelGroup 2.1"]
- exportMetaObjectRevisions: [0]
- Property { name: "count"; type: "int"; isReadonly: true }
- Property { name: "name"; type: "string" }
- Property { name: "includeByDefault"; type: "bool" }
- Signal { name: "defaultIncludeChanged" }
- Signal {
- name: "changed"
- Parameter { name: "removed"; type: "QQmlV4Handle" }
- Parameter { name: "inserted"; type: "QQmlV4Handle" }
- }
- Method {
- name: "insert"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "create"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "resolve"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "remove"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "addGroups"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "removeGroups"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "setGroups"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "move"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "get"
- type: "QQmlV4Handle"
- Parameter { name: "index"; type: "int" }
- }
- }
- Component { name: "QQmlDelegateModelParts"; prototype: "QObject" }
- Component {
- name: "QQmlListElement"
- prototype: "QObject"
- exports: ["QtQml.Models/ListElement 2.1"]
- exportMetaObjectRevisions: [0]
- }
- Component {
- name: "QQmlListModel"
- prototype: "QAbstractListModel"
- exports: ["QtQml.Models/ListModel 2.1"]
- exportMetaObjectRevisions: [0]
- Property { name: "count"; type: "int"; isReadonly: true }
- Property { name: "dynamicRoles"; type: "bool" }
- Method { name: "clear" }
- Method {
- name: "remove"
- Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "append"
- Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "insert"
- Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "get"
- type: "QQmlV4Handle"
- Parameter { name: "index"; type: "int" }
- }
- Method {
- name: "set"
- Parameter { name: "index"; type: "int" }
- Parameter { type: "QQmlV4Handle" }
- }
- Method {
- name: "setProperty"
- Parameter { name: "index"; type: "int" }
- Parameter { name: "property"; type: "string" }
- Parameter { name: "value"; type: "QVariant" }
- }
- Method {
- name: "move"
- Parameter { name: "from"; type: "int" }
- Parameter { name: "to"; type: "int" }
- Parameter { name: "count"; type: "int" }
- }
- Method { name: "sync" }
- }
- Component {
- name: "QQmlObjectModel"
- defaultProperty: "children"
- prototype: "QQmlInstanceModel"
- exports: [
- "QtQml.Models/ObjectModel 2.1",
- "QtQml.Models/ObjectModel 2.3"
- ]
- exportMetaObjectRevisions: [0, 3]
- attachedType: "QQmlObjectModelAttached"
- Property { name: "children"; type: "QObject"; isList: true; isReadonly: true }
- Method { name: "clear"; revision: 3 }
- Method {
- name: "get"
- revision: 3
- type: "QObject*"
- Parameter { name: "index"; type: "int" }
- }
- Method {
- name: "append"
- revision: 3
- Parameter { name: "object"; type: "QObject"; isPointer: true }
- }
- Method {
- name: "insert"
- revision: 3
- Parameter { name: "index"; type: "int" }
- Parameter { name: "object"; type: "QObject"; isPointer: true }
- }
- Method {
- name: "move"
- revision: 3
- Parameter { name: "from"; type: "int" }
- Parameter { name: "to"; type: "int" }
- Parameter { name: "n"; type: "int" }
- }
- Method {
- name: "move"
- revision: 3
- Parameter { name: "from"; type: "int" }
- Parameter { name: "to"; type: "int" }
- }
- Method {
- name: "remove"
- revision: 3
- Parameter { name: "index"; type: "int" }
- Parameter { name: "n"; type: "int" }
- }
- Method {
- name: "remove"
- revision: 3
- Parameter { name: "index"; type: "int" }
- }
- }
- Component {
- name: "QQmlObjectModelAttached"
- prototype: "QObject"
- Property { name: "index"; type: "int"; isReadonly: true }
- }
}
diff --git a/src/imports/particles/plugins.qmltypes b/src/imports/particles/plugins.qmltypes
index ce78392610..5c4bd01980 100644
--- a/src/imports/particles/plugins.qmltypes
+++ b/src/imports/particles/plugins.qmltypes
@@ -7,7 +7,7 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable QtQuick.Particles 2.0'
Module {
- dependencies: []
+ dependencies: ["QtQuick 2.8"]
Component {
name: "QQuickAgeAffector"
defaultProperty: "data"
@@ -492,160 +492,6 @@ Module {
}
}
Component {
- name: "QQuickItem"
- defaultProperty: "data"
- prototype: "QObject"
- Enum {
- name: "TransformOrigin"
- values: {
- "TopLeft": 0,
- "Top": 1,
- "TopRight": 2,
- "Left": 3,
- "Center": 4,
- "Right": 5,
- "BottomLeft": 6,
- "Bottom": 7,
- "BottomRight": 8
- }
- }
- Property { name: "parent"; type: "QQuickItem"; isPointer: true }
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "resources"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true }
- Property { name: "x"; type: "double" }
- Property { name: "y"; type: "double" }
- Property { name: "z"; type: "double" }
- Property { name: "width"; type: "double" }
- Property { name: "height"; type: "double" }
- Property { name: "opacity"; type: "double" }
- Property { name: "enabled"; type: "bool" }
- Property { name: "visible"; type: "bool" }
- Property { name: "visibleChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
- Property { name: "states"; type: "QQuickState"; isList: true; isReadonly: true }
- Property { name: "transitions"; type: "QQuickTransition"; isList: true; isReadonly: true }
- Property { name: "state"; type: "string" }
- Property { name: "childrenRect"; type: "QRectF"; isReadonly: true }
- Property { name: "anchors"; type: "QQuickAnchors"; isReadonly: true; isPointer: true }
- Property { name: "left"; type: "QQuickAnchorLine"; isReadonly: true }
- Property { name: "right"; type: "QQuickAnchorLine"; isReadonly: true }
- Property { name: "horizontalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
- Property { name: "top"; type: "QQuickAnchorLine"; isReadonly: true }
- Property { name: "bottom"; type: "QQuickAnchorLine"; isReadonly: true }
- Property { name: "verticalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
- Property { name: "baseline"; type: "QQuickAnchorLine"; isReadonly: true }
- Property { name: "baselineOffset"; type: "double" }
- Property { name: "clip"; type: "bool" }
- Property { name: "focus"; type: "bool" }
- Property { name: "activeFocus"; type: "bool"; isReadonly: true }
- Property { name: "activeFocusOnTab"; revision: 1; type: "bool" }
- Property { name: "rotation"; type: "double" }
- Property { name: "scale"; type: "double" }
- Property { name: "transformOrigin"; type: "TransformOrigin" }
- Property { name: "transformOriginPoint"; type: "QPointF"; isReadonly: true }
- Property { name: "transform"; type: "QQuickTransform"; isList: true; isReadonly: true }
- Property { name: "smooth"; type: "bool" }
- Property { name: "antialiasing"; type: "bool" }
- Property { name: "implicitWidth"; type: "double" }
- Property { name: "implicitHeight"; type: "double" }
- Property { name: "layer"; type: "QQuickItemLayer"; isReadonly: true; isPointer: true }
- Signal {
- name: "childrenRectChanged"
- Parameter { type: "QRectF" }
- }
- Signal {
- name: "baselineOffsetChanged"
- Parameter { type: "double" }
- }
- Signal {
- name: "stateChanged"
- Parameter { type: "string" }
- }
- Signal {
- name: "focusChanged"
- Parameter { type: "bool" }
- }
- Signal {
- name: "activeFocusChanged"
- Parameter { type: "bool" }
- }
- Signal {
- name: "activeFocusOnTabChanged"
- revision: 1
- Parameter { type: "bool" }
- }
- Signal {
- name: "parentChanged"
- Parameter { type: "QQuickItem"; isPointer: true }
- }
- Signal {
- name: "transformOriginChanged"
- Parameter { type: "TransformOrigin" }
- }
- Signal {
- name: "smoothChanged"
- Parameter { type: "bool" }
- }
- Signal {
- name: "antialiasingChanged"
- Parameter { type: "bool" }
- }
- Signal {
- name: "clipChanged"
- Parameter { type: "bool" }
- }
- Signal {
- name: "windowChanged"
- revision: 1
- Parameter { name: "window"; type: "QQuickWindow"; isPointer: true }
- }
- Method { name: "update" }
- Method {
- name: "grabToImage"
- revision: 2
- type: "bool"
- Parameter { name: "callback"; type: "QJSValue" }
- Parameter { name: "targetSize"; type: "QSize" }
- }
- Method {
- name: "grabToImage"
- revision: 2
- type: "bool"
- Parameter { name: "callback"; type: "QJSValue" }
- }
- Method {
- name: "contains"
- type: "bool"
- Parameter { name: "point"; type: "QPointF" }
- }
- Method {
- name: "mapFromItem"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method {
- name: "mapToItem"
- Parameter { type: "QQmlV4Function"; isPointer: true }
- }
- Method { name: "forceActiveFocus" }
- Method {
- name: "forceActiveFocus"
- Parameter { name: "reason"; type: "Qt::FocusReason" }
- }
- Method {
- name: "nextItemInFocusChain"
- revision: 1
- type: "QQuickItem*"
- Parameter { name: "forward"; type: "bool" }
- }
- Method { name: "nextItemInFocusChain"; revision: 1; type: "QQuickItem*" }
- Method {
- name: "childAt"
- type: "QQuickItem*"
- Parameter { name: "x"; type: "double" }
- Parameter { name: "y"; type: "double" }
- }
- }
- Component {
name: "QQuickItemParticle"
defaultProperty: "data"
prototype: "QQuickParticlePainter"
@@ -1151,56 +997,6 @@ Module {
}
}
Component {
- name: "QQuickStochasticState"
- prototype: "QObject"
- Property { name: "duration"; type: "int" }
- Property { name: "durationVariation"; type: "int" }
- Property { name: "randomStart"; type: "bool" }
- Property { name: "to"; type: "QVariantMap" }
- Property { name: "name"; type: "string" }
- Signal {
- name: "durationChanged"
- Parameter { name: "arg"; type: "int" }
- }
- Signal {
- name: "nameChanged"
- Parameter { name: "arg"; type: "string" }
- }
- Signal {
- name: "toChanged"
- Parameter { name: "arg"; type: "QVariantMap" }
- }
- Signal {
- name: "durationVariationChanged"
- Parameter { name: "arg"; type: "int" }
- }
- Signal { name: "entered" }
- Signal {
- name: "randomStartChanged"
- Parameter { name: "arg"; type: "bool" }
- }
- Method {
- name: "setDuration"
- Parameter { name: "arg"; type: "int" }
- }
- Method {
- name: "setName"
- Parameter { name: "arg"; type: "string" }
- }
- Method {
- name: "setTo"
- Parameter { name: "arg"; type: "QVariantMap" }
- }
- Method {
- name: "setDurationVariation"
- Parameter { name: "arg"; type: "int" }
- }
- Method {
- name: "setRandomStart"
- Parameter { name: "arg"; type: "bool" }
- }
- }
- Component {
name: "QQuickTargetDirection"
prototype: "QQuickDirection"
exports: ["QtQuick.Particles/TargetDirection 2.0"]
diff --git a/src/imports/qtqml/plugins.qmltypes b/src/imports/qtqml/plugins.qmltypes
index 864aca1f32..82333627a0 100644
--- a/src/imports/qtqml/plugins.qmltypes
+++ b/src/imports/qtqml/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQml 2.2'
+// 'qmlplugindump -nonrelocatable -noforceqtquick QtQml 2.3'
Module {
dependencies: []
@@ -27,12 +27,13 @@ Module {
Component {
name: "QQmlBind"
prototype: "QObject"
- exports: ["QtQml/Binding 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQml/Binding 2.0", "QtQml/Binding 2.8"]
+ exportMetaObjectRevisions: [0, 8]
Property { name: "target"; type: "QObject"; isPointer: true }
Property { name: "property"; type: "string" }
Property { name: "value"; type: "QVariant" }
Property { name: "when"; type: "bool" }
+ Property { name: "delayed"; revision: 8; type: "bool" }
}
Component {
name: "QQmlComponent"
@@ -92,10 +93,12 @@ Module {
Component {
name: "QQmlConnections"
prototype: "QObject"
- exports: ["QtQml/Connections 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQml/Connections 2.0", "QtQml/Connections 2.3"]
+ exportMetaObjectRevisions: [0, 1]
Property { name: "target"; type: "QObject"; isPointer: true }
+ Property { name: "enabled"; type: "bool" }
Property { name: "ignoreUnknownSignals"; type: "bool" }
+ Signal { name: "enabledChanged"; revision: 1 }
}
Component {
name: "QQmlInstanceModel"
@@ -193,6 +196,13 @@ Module {
}
}
Component {
+ name: "QQmlLoggingCategory"
+ prototype: "QObject"
+ exports: ["QtQml/LoggingCategory 2.8"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "name"; type: "string" }
+ }
+ Component {
name: "QQmlTimer"
prototype: "QObject"
exports: ["QtQml/Timer 2.0"]
@@ -215,6 +225,7 @@ Module {
Property { name: "button"; type: "int"; isReadonly: true }
Property { name: "buttons"; type: "int"; isReadonly: true }
Property { name: "modifiers"; type: "int"; isReadonly: true }
+ Property { name: "source"; revision: 7; type: "int"; isReadonly: true }
Property { name: "wasHeld"; type: "bool"; isReadonly: true }
Property { name: "isClick"; type: "bool"; isReadonly: true }
Property { name: "accepted"; type: "bool" }
diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp
index e56027c1bb..d16467a5bb 100644
--- a/src/imports/qtquick2/plugin.cpp
+++ b/src/imports/qtquick2/plugin.cpp
@@ -61,13 +61,17 @@ public:
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick"));
Q_UNUSED(uri);
+ moduleDefined = true;
QQmlQtQuick2Module::defineModule();
}
~QtQuick2Plugin()
{
- QQmlQtQuick2Module::undefineModule();
+ if (moduleDefined)
+ QQmlQtQuick2Module::undefineModule();
}
+
+ bool moduleDefined = false;
};
//![class decl]
diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes
index c3a14254f3..441cd743aa 100644
--- a/src/imports/qtquick2/plugins.qmltypes
+++ b/src/imports/qtquick2/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQuick 2.6'
+// 'qmlplugindump -nonrelocatable -noforceqtquick QtQuick 2.8'
Module {
dependencies: []
@@ -318,7 +318,9 @@ Module {
}
}
Property { name: "cursorRectangle"; type: "QRectF"; isReadonly: true }
+ Property { name: "anchorRectangle"; type: "QRectF"; isReadonly: true }
Property { name: "keyboardRectangle"; type: "QRectF"; isReadonly: true }
+ Property { name: "inputItemClipRectangle"; type: "QRectF"; isReadonly: true }
Property { name: "visible"; type: "bool"; isReadonly: true }
Property { name: "animating"; type: "bool"; isReadonly: true }
Property { name: "locale"; type: "QLocale"; isReadonly: true }
@@ -1156,6 +1158,7 @@ Module {
Property { name: "layoutDirection"; type: "Qt::LayoutDirection"; isReadonly: true }
Property { name: "supportsMultipleWindows"; type: "bool"; isReadonly: true }
Property { name: "state"; type: "Qt::ApplicationState"; isReadonly: true }
+ Property { name: "font"; type: "QFont"; isReadonly: true }
Signal {
name: "stateChanged"
Parameter { name: "state"; type: "Qt::ApplicationState" }
@@ -1213,6 +1216,24 @@ Module {
Property { name: "sourceSize"; type: "QSize"; isReadonly: true }
}
Component {
+ name: "QQuickBorderImageMesh"
+ prototype: "QQuickShaderEffectMesh"
+ exports: ["QtQuick/BorderImageMesh 2.8"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "TileMode"
+ values: {
+ "Stretch": 0,
+ "Repeat": 1,
+ "Round": 2
+ }
+ }
+ Property { name: "border"; type: "QQuickScaleGrid"; isReadonly: true; isPointer: true }
+ Property { name: "size"; type: "QSize" }
+ Property { name: "horizontalTileMode"; type: "TileMode" }
+ Property { name: "verticalTileMode"; type: "TileMode" }
+ }
+ Component {
name: "QQuickCanvasItem"
defaultProperty: "data"
prototype: "QQuickItem"
@@ -1378,6 +1399,7 @@ Module {
Property { name: "source"; type: "QObject"; isPointer: true }
Property { name: "target"; type: "QObject"; isReadonly: true; isPointer: true }
Property { name: "hotSpot"; type: "QPointF" }
+ Property { name: "imageSource"; revision: 8; type: "QUrl" }
Property { name: "keys"; type: "QStringList" }
Property { name: "mimeData"; type: "QVariantMap" }
Property { name: "supportedActions"; type: "Qt::DropActions" }
@@ -1497,7 +1519,8 @@ Module {
"AutoFlickDirection": 0,
"HorizontalFlick": 1,
"VerticalFlick": 2,
- "HorizontalAndVerticalFlick": 3
+ "HorizontalAndVerticalFlick": 3,
+ "AutoFlickIfNeeded": 12
}
}
Property { name: "contentWidth"; type: "double" }
@@ -1780,6 +1803,69 @@ Module {
Property { name: "color"; type: "QColor" }
}
Component {
+ name: "QQuickGraphicsInfo"
+ prototype: "QObject"
+ exports: ["QtQuick/GraphicsInfo 2.8"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "GraphicsApi"
+ values: {
+ "Unknown": 0,
+ "Software": 1,
+ "OpenGL": 2,
+ "Direct3D12": 3
+ }
+ }
+ Enum {
+ name: "ShaderType"
+ values: {
+ "UnknownShadingLanguage": 0,
+ "GLSL": 1,
+ "HLSL": 2
+ }
+ }
+ Enum {
+ name: "ShaderCompilationType"
+ values: {
+ "RuntimeCompilation": 1,
+ "OfflineCompilation": 2
+ }
+ }
+ Enum {
+ name: "ShaderSourceType"
+ values: {
+ "ShaderSourceString": 1,
+ "ShaderSourceFile": 2,
+ "ShaderByteCode": 4
+ }
+ }
+ Enum {
+ name: "OpenGLContextProfile"
+ values: {
+ "OpenGLNoProfile": 0,
+ "OpenGLCoreProfile": 1,
+ "OpenGLCompatibilityProfile": 2
+ }
+ }
+ Enum {
+ name: "RenderableType"
+ values: {
+ "SurfaceFormatUnspecified": 0,
+ "SurfaceFormatOpenGL": 1,
+ "SurfaceFormatOpenGLES": 2
+ }
+ }
+ Property { name: "api"; type: "GraphicsApi"; isReadonly: true }
+ Property { name: "shaderType"; type: "ShaderType"; isReadonly: true }
+ Property { name: "shaderCompilationType"; type: "ShaderCompilationType"; isReadonly: true }
+ Property { name: "shaderSourceType"; type: "ShaderSourceType"; isReadonly: true }
+ Property { name: "majorVersion"; type: "int"; isReadonly: true }
+ Property { name: "minorVersion"; type: "int"; isReadonly: true }
+ Property { name: "profile"; type: "OpenGLContextProfile"; isReadonly: true }
+ Property { name: "renderableType"; type: "RenderableType"; isReadonly: true }
+ }
+ Component {
name: "QQuickGrid"
defaultProperty: "data"
prototype: "QQuickBasePositioner"
@@ -1850,8 +1936,12 @@ Module {
name: "QQuickGridView"
defaultProperty: "data"
prototype: "QQuickItemView"
- exports: ["QtQuick/GridView 2.0", "QtQuick/GridView 2.1"]
- exportMetaObjectRevisions: [0, 1]
+ exports: [
+ "QtQuick/GridView 2.0",
+ "QtQuick/GridView 2.1",
+ "QtQuick/GridView 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 7]
attachedType: "QQuickGridViewAttached"
Enum {
name: "Flow"
@@ -2120,6 +2210,18 @@ Module {
Parameter { name: "point"; type: "QPointF" }
}
Method {
+ name: "mapToGlobal"
+ revision: 7
+ type: "QPointF"
+ Parameter { name: "point"; type: "QPointF" }
+ }
+ Method {
+ name: "mapFromGlobal"
+ revision: 7
+ type: "QPointF"
+ Parameter { name: "point"; type: "QPointF" }
+ }
+ Method {
name: "mapFromItem"
Parameter { type: "QQmlV4Function"; isPointer: true }
}
@@ -2260,6 +2362,7 @@ Module {
Property { name: "currentIndex"; type: "int" }
Property { name: "currentItem"; type: "QQuickItem"; isReadonly: true; isPointer: true }
Property { name: "keyNavigationWraps"; type: "bool" }
+ Property { name: "keyNavigationEnabled"; revision: 7; type: "bool" }
Property { name: "cacheBuffer"; type: "int" }
Property { name: "displayMarginBeginning"; revision: 2; type: "int" }
Property { name: "displayMarginEnd"; revision: 2; type: "int" }
@@ -2285,6 +2388,7 @@ Module {
Property { name: "preferredHighlightBegin"; type: "double" }
Property { name: "preferredHighlightEnd"; type: "double" }
Property { name: "highlightMoveDuration"; type: "int" }
+ Signal { name: "keyNavigationEnabledChanged"; revision: 7 }
Signal { name: "populateTransitionChanged" }
Signal { name: "addTransitionChanged" }
Signal { name: "addDisplacedTransitionChanged" }
@@ -2559,9 +2663,10 @@ Module {
exports: [
"QtQuick/ListView 2.0",
"QtQuick/ListView 2.1",
- "QtQuick/ListView 2.4"
+ "QtQuick/ListView 2.4",
+ "QtQuick/ListView 2.7"
]
- exportMetaObjectRevisions: [0, 1, 2]
+ exportMetaObjectRevisions: [0, 1, 2, 7]
attachedType: "QQuickListViewAttached"
Enum {
name: "Orientation"
@@ -3014,8 +3119,8 @@ Module {
name: "QQuickPathView"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/PathView 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/PathView 2.0", "QtQuick/PathView 2.7"]
+ exportMetaObjectRevisions: [0, 7]
attachedType: "QQuickPathViewAttached"
Enum {
name: "HighlightRangeMode"
@@ -3034,6 +3139,14 @@ Module {
}
}
Enum {
+ name: "MovementDirection"
+ values: {
+ "Shortest": 0,
+ "Negative": 1,
+ "Positive": 2
+ }
+ }
+ Enum {
name: "PositionMode"
values: {
"Beginning": 0,
@@ -3065,10 +3178,12 @@ Module {
Property { name: "delegate"; type: "QQmlComponent"; isPointer: true }
Property { name: "pathItemCount"; type: "int" }
Property { name: "snapMode"; type: "SnapMode" }
+ Property { name: "movementDirection"; revision: 7; type: "MovementDirection" }
Property { name: "cacheItemCount"; type: "int" }
Signal { name: "snapPositionChanged" }
Signal { name: "movementStarted" }
Signal { name: "movementEnded" }
+ Signal { name: "movementDirectionChanged"; revision: 7 }
Signal { name: "flickStarted" }
Signal { name: "flickEnded" }
Signal { name: "dragStarted" }
@@ -3942,23 +4057,23 @@ Module {
}
Signal {
name: "styleChanged"
- Parameter { name: "style"; type: "TextStyle" }
+ Parameter { name: "style"; type: "QQuickText::TextStyle" }
}
Signal {
name: "horizontalAlignmentChanged"
- Parameter { name: "alignment"; type: "HAlignment" }
+ Parameter { name: "alignment"; type: "QQuickText::HAlignment" }
}
Signal {
name: "verticalAlignmentChanged"
- Parameter { name: "alignment"; type: "VAlignment" }
+ Parameter { name: "alignment"; type: "QQuickText::VAlignment" }
}
Signal {
name: "textFormatChanged"
- Parameter { name: "textFormat"; type: "TextFormat" }
+ Parameter { name: "textFormat"; type: "QQuickText::TextFormat" }
}
Signal {
name: "elideModeChanged"
- Parameter { name: "mode"; type: "TextElideMode" }
+ Parameter { name: "mode"; type: "QQuickText::TextElideMode" }
}
Signal { name: "contentSizeChanged" }
Signal {
@@ -3997,9 +4112,10 @@ Module {
"QtQuick/TextEdit 2.1",
"QtQuick/TextEdit 2.2",
"QtQuick/TextEdit 2.3",
- "QtQuick/TextEdit 2.6"
+ "QtQuick/TextEdit 2.6",
+ "QtQuick/TextEdit 2.7"
]
- exportMetaObjectRevisions: [0, 1, 2, 3, 6]
+ exportMetaObjectRevisions: [0, 1, 2, 3, 6, 7]
Enum {
name: "HAlignment"
values: {
@@ -4070,6 +4186,7 @@ Module {
Property { name: "cursorPosition"; type: "int" }
Property { name: "cursorRectangle"; type: "QRectF"; isReadonly: true }
Property { name: "cursorDelegate"; type: "QQmlComponent"; isPointer: true }
+ Property { name: "overwriteMode"; type: "bool" }
Property { name: "selectionStart"; type: "int"; isReadonly: true }
Property { name: "selectionEnd"; type: "int"; isReadonly: true }
Property { name: "selectedText"; type: "string"; isReadonly: true }
@@ -4099,6 +4216,8 @@ Module {
Property { name: "leftPadding"; revision: 6; type: "double" }
Property { name: "rightPadding"; revision: 6; type: "double" }
Property { name: "bottomPadding"; revision: 6; type: "double" }
+ Property { name: "preeditText"; revision: 7; type: "string"; isReadonly: true }
+ Signal { name: "preeditTextChanged"; revision: 7 }
Signal { name: "contentSizeChanged" }
Signal {
name: "colorChanged"
@@ -4118,15 +4237,15 @@ Module {
}
Signal {
name: "horizontalAlignmentChanged"
- Parameter { name: "alignment"; type: "HAlignment" }
+ Parameter { name: "alignment"; type: "QQuickTextEdit::HAlignment" }
}
Signal {
name: "verticalAlignmentChanged"
- Parameter { name: "alignment"; type: "VAlignment" }
+ Parameter { name: "alignment"; type: "QQuickTextEdit::VAlignment" }
}
Signal {
name: "textFormatChanged"
- Parameter { name: "textFormat"; type: "TextFormat" }
+ Parameter { name: "textFormat"; type: "QQuickTextEdit::TextFormat" }
}
Signal {
name: "readOnlyChanged"
@@ -4137,6 +4256,10 @@ Module {
Parameter { name: "isCursorVisible"; type: "bool" }
}
Signal {
+ name: "overwriteModeChanged"
+ Parameter { name: "overwriteMode"; type: "bool" }
+ }
+ Signal {
name: "activeFocusOnPressChanged"
Parameter { name: "activeFocusOnPressed"; type: "bool" }
}
@@ -4159,7 +4282,7 @@ Module {
}
Signal {
name: "mouseSelectionModeChanged"
- Parameter { name: "mode"; type: "SelectionMode" }
+ Parameter { name: "mode"; type: "QQuickTextEdit::SelectionMode" }
}
Signal {
name: "linkActivated"
@@ -4210,6 +4333,7 @@ Module {
revision: 2
Parameter { name: "text"; type: "string" }
}
+ Method { name: "clear"; revision: 7 }
Method {
name: "inputMethodQuery"
revision: 4
@@ -4265,9 +4389,10 @@ Module {
"QtQuick/TextInput 2.0",
"QtQuick/TextInput 2.2",
"QtQuick/TextInput 2.4",
- "QtQuick/TextInput 2.6"
+ "QtQuick/TextInput 2.6",
+ "QtQuick/TextInput 2.7"
]
- exportMetaObjectRevisions: [0, 2, 3, 6]
+ exportMetaObjectRevisions: [0, 2, 3, 6, 7]
Enum {
name: "EchoMode"
values: {
@@ -4339,6 +4464,7 @@ Module {
Property { name: "cursorPosition"; type: "int" }
Property { name: "cursorRectangle"; type: "QRectF"; isReadonly: true }
Property { name: "cursorDelegate"; type: "QQmlComponent"; isPointer: true }
+ Property { name: "overwriteMode"; type: "bool" }
Property { name: "selectionStart"; type: "int"; isReadonly: true }
Property { name: "selectionEnd"; type: "int"; isReadonly: true }
Property { name: "selectedText"; type: "string"; isReadonly: true }
@@ -4352,6 +4478,7 @@ Module {
Property { name: "passwordCharacter"; type: "string" }
Property { name: "passwordMaskDelay"; revision: 3; type: "int" }
Property { name: "displayText"; type: "string"; isReadonly: true }
+ Property { name: "preeditText"; revision: 7; type: "string"; isReadonly: true }
Property { name: "autoScroll"; type: "bool" }
Property { name: "selectByMouse"; type: "bool" }
Property { name: "mouseSelectionMode"; type: "SelectionMode" }
@@ -4376,11 +4503,11 @@ Module {
}
Signal {
name: "horizontalAlignmentChanged"
- Parameter { name: "alignment"; type: "HAlignment" }
+ Parameter { name: "alignment"; type: "QQuickTextInput::HAlignment" }
}
Signal {
name: "verticalAlignmentChanged"
- Parameter { name: "alignment"; type: "VAlignment" }
+ Parameter { name: "alignment"; type: "QQuickTextInput::VAlignment" }
}
Signal {
name: "readOnlyChanged"
@@ -4391,6 +4518,10 @@ Module {
Parameter { name: "isCursorVisible"; type: "bool" }
}
Signal {
+ name: "overwriteModeChanged"
+ Parameter { name: "overwriteMode"; type: "bool" }
+ }
+ Signal {
name: "maximumLengthChanged"
Parameter { name: "maximumLength"; type: "int" }
}
@@ -4400,13 +4531,14 @@ Module {
}
Signal {
name: "echoModeChanged"
- Parameter { name: "echoMode"; type: "EchoMode" }
+ Parameter { name: "echoMode"; type: "QQuickTextInput::EchoMode" }
}
Signal {
name: "passwordMaskDelayChanged"
revision: 3
Parameter { name: "delay"; type: "int" }
}
+ Signal { name: "preeditTextChanged"; revision: 7 }
Signal {
name: "activeFocusOnPressChanged"
Parameter { name: "activeFocusOnPress"; type: "bool" }
@@ -4421,7 +4553,7 @@ Module {
}
Signal {
name: "mouseSelectionModeChanged"
- Parameter { name: "mode"; type: "SelectionMode" }
+ Parameter { name: "mode"; type: "QQuickTextInput::SelectionMode" }
}
Signal { name: "contentSizeChanged" }
Signal { name: "paddingChanged"; revision: 6 }
@@ -4463,6 +4595,7 @@ Module {
revision: 3
Parameter { name: "position"; type: "int" }
}
+ Method { name: "clear"; revision: 7 }
Method {
name: "positionAt"
Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
@@ -4628,7 +4761,7 @@ Module {
Property { name: "pixelDelta"; type: "QPoint"; isReadonly: true }
Property { name: "buttons"; type: "int"; isReadonly: true }
Property { name: "modifiers"; type: "int"; isReadonly: true }
- Property { name: "inverted"; type: "bool" }
+ Property { name: "inverted"; type: "bool"; isReadonly: true }
Property { name: "accepted"; type: "bool" }
}
Component {
diff --git a/src/imports/settings/plugins.qmltypes b/src/imports/settings/plugins.qmltypes
index eaa310edc9..40d8746525 100644
--- a/src/imports/settings/plugins.qmltypes
+++ b/src/imports/settings/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable Qt.labs.settings 1.0'
+// 'qmlplugindump -nonrelocatable -noforceqtquick Qt.labs.settings 1.0'
Module {
dependencies: []
diff --git a/src/imports/settings/qqmlsettings.cpp b/src/imports/settings/qqmlsettings.cpp
index bc097e4575..cd6fcbc718 100644
--- a/src/imports/settings/qqmlsettings.cpp
+++ b/src/imports/settings/qqmlsettings.cpp
@@ -214,7 +214,7 @@ QT_BEGIN_NAMESPACE
instance, even if they are referring to the same setting in the same category.
The information is stored in the system registry on Windows, and in XML
- preferences files on OS X. On other Unix systems, in the absence of a
+ preferences files on \macos. On other Unix systems, in the absence of a
standard, INI text files are used. See \l QSettings documentation for
more details.
diff --git a/src/imports/settings/qqmlsettings_p.h b/src/imports/settings/qqmlsettings_p.h
index 0ed55579dd..ce942d7564 100644
--- a/src/imports/settings/qqmlsettings_p.h
+++ b/src/imports/settings/qqmlsettings_p.h
@@ -74,10 +74,10 @@ public:
void setCategory(const QString &category);
protected:
- void timerEvent(QTimerEvent *event);
+ void timerEvent(QTimerEvent *event) override;
- void classBegin();
- void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
private:
Q_DISABLE_COPY(QQmlSettings)
diff --git a/src/imports/statemachine/plugins.qmltypes b/src/imports/statemachine/plugins.qmltypes
index c4b453b9e4..0fe9b63e03 100644
--- a/src/imports/statemachine/plugins.qmltypes
+++ b/src/imports/statemachine/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQml.StateMachine 1.0'
+// 'qmlplugindump -nonrelocatable -noforceqtquick QtQml.StateMachine 1.0'
Module {
dependencies: []
diff --git a/src/imports/statemachine/signaltransition.cpp b/src/imports/statemachine/signaltransition.cpp
index 4153c70fd0..2e6381fc08 100644
--- a/src/imports/statemachine/signaltransition.cpp
+++ b/src/imports/statemachine/signaltransition.cpp
@@ -78,8 +78,9 @@ bool SignalTransition::eventTest(QEvent *event)
// Set arguments as context properties
int count = e->arguments().count();
QMetaMethod metaMethod = e->sender()->metaObject()->method(e->signalIndex());
+ const auto parameterNames = metaMethod.parameterNames();
for (int i = 0; i < count; i++)
- context.setContextProperty(metaMethod.parameterNames()[i], QVariant::fromValue(e->arguments().at(i)));
+ context.setContextProperty(parameterNames[i], QVariant::fromValue(e->arguments().at(i)));
QQmlExpression expr(m_guard, &context, this);
QVariant result = expr.evaluate();
@@ -111,15 +112,27 @@ void SignalTransition::setSignal(const QJSValue &signal)
QV4::ExecutionEngine *jsEngine = QV8Engine::getV4(QQmlEngine::contextForObject(this)->engine());
QV4::Scope scope(jsEngine);
- QV4::Scoped<QV4::QObjectMethod> qobjectSignal(scope, QJSValuePrivate::convertedToValue(jsEngine, m_signal));
- Q_ASSERT(qobjectSignal);
-
- QObject *sender = qobjectSignal->object();
- Q_ASSERT(sender);
- QMetaMethod metaMethod = sender->metaObject()->method(qobjectSignal->methodIndex());
+ QObject *sender;
+ QMetaMethod signalMethod;
+
+ QV4::ScopedValue value(scope, QJSValuePrivate::convertedToValue(jsEngine, m_signal));
+
+ // Did we get the "slot" that can be used to invoke the signal?
+ if (QV4::QObjectMethod *signalSlot = value->as<QV4::QObjectMethod>()) {
+ sender = signalSlot->object();
+ Q_ASSERT(sender);
+ signalMethod = sender->metaObject()->method(signalSlot->methodIndex());
+ } else if (QV4::QmlSignalHandler *signalObject = value->as<QV4::QmlSignalHandler>()) { // or did we get the signal object (the one with the connect()/disconnect() functions) ?
+ sender = signalObject->object();
+ Q_ASSERT(sender);
+ signalMethod = sender->metaObject()->method(signalObject->signalIndex());
+ } else {
+ qmlInfo(this) << tr("Specified signal does not exist.");
+ return;
+ }
QSignalTransition::setSenderObject(sender);
- QSignalTransition::setSignal(metaMethod.methodSignature());
+ QSignalTransition::setSignal(signalMethod.methodSignature());
connectTriggered();
}
@@ -178,7 +191,7 @@ void SignalTransitionParser::verifyBindings(const QV4::CompiledData::Unit *qmlUn
QString propName = qmlUnit->stringAt(binding->propertyNameIndex);
- if (propName != QStringLiteral("onTriggered")) {
+ if (propName != QLatin1String("onTriggered")) {
error(props.at(ii), SignalTransition::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
return;
}
diff --git a/src/imports/statemachine/signaltransition.h b/src/imports/statemachine/signaltransition.h
index 4a246e165f..c6512e2b19 100644
--- a/src/imports/statemachine/signaltransition.h
+++ b/src/imports/statemachine/signaltransition.h
@@ -48,7 +48,6 @@
#include <QtQml/qqmlparserstatus.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlboundsignalexpressionpointer_p.h>
-#include <private/qqmlcompiler_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/imports/statemachine/state.h b/src/imports/statemachine/state.h
index 73e4ecda6b..8e8cefab19 100644
--- a/src/imports/statemachine/state.h
+++ b/src/imports/statemachine/state.h
@@ -58,8 +58,8 @@ class State : public QState, public QQmlParserStatus
public:
explicit State(QState *parent = 0);
- void classBegin() {}
- void componentComplete();
+ void classBegin() override {}
+ void componentComplete() override;
QQmlListProperty<QObject> children();
diff --git a/src/imports/statemachine/statemachine.h b/src/imports/statemachine/statemachine.h
index 59a810f387..cb0ab43f8b 100644
--- a/src/imports/statemachine/statemachine.h
+++ b/src/imports/statemachine/statemachine.h
@@ -62,8 +62,8 @@ class StateMachine : public QStateMachine, public QQmlParserStatus
public:
explicit StateMachine(QObject *parent = 0);
- void classBegin() {}
- void componentComplete();
+ void classBegin() override {}
+ void componentComplete() override;
QQmlListProperty<QObject> children();
bool isRunning() const;
diff --git a/src/imports/statemachine/timeouttransition.h b/src/imports/statemachine/timeouttransition.h
index 5d71e86bb4..0e5f5377e3 100644
--- a/src/imports/statemachine/timeouttransition.h
+++ b/src/imports/statemachine/timeouttransition.h
@@ -59,8 +59,8 @@ public:
int timeout() const;
void setTimeout(int timeout);
- void classBegin() {}
- void componentComplete();
+ void classBegin() override {}
+ void componentComplete() override;
Q_SIGNALS:
void timeoutChanged();
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index 046ce507d4..683200a259 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -394,6 +394,73 @@ Item {
throw new Error("QtQuickTest::fail")
}
+ /*!
+ \since 5.8
+ \qmlmethod TestCase::tryVerify(function, timeout = 5000, message = "")
+
+ Fails the current test case if \a function does not evaluate to
+ \c true before the specified \a timeout (in milliseconds) has elapsed.
+ The function is evaluated multiple times until the timeout is
+ reached. An optional \a message is displayed upon failure.
+
+ This function is intended for testing applications where a condition
+ changes based on asynchronous events. Use verify() for testing
+ synchronous condition changes, and tryCompare() for testing
+ asynchronous property changes.
+
+ For example, in the code below, it's not possible to use tryCompare(),
+ because the \c currentItem property might be \c null for a short period
+ of time:
+
+ \code
+ tryCompare(listView.currentItem, "text", "Hello");
+ \endcode
+
+ Instead, we can use tryVerify() to first check that \c currentItem
+ isn't \c null, and then use a regular compare afterwards:
+
+ \code
+ tryVerify(function(){ return listView.currentItem })
+ compare(listView.currentItem.text, "Hello")
+ \endcode
+
+ \sa verify(), compare(), tryCompare(), SignalSpy::wait()
+ */
+ function tryVerify(expressionFunction, timeout, msg) {
+ if (!expressionFunction || !(expressionFunction instanceof Function)) {
+ qtest_results.fail("First argument must be a function", util.callerFile(), util.callerLine())
+ throw new Error("QtQuickTest::fail")
+ }
+
+ if (timeout && typeof(timeout) !== "number") {
+ qtest_results.fail("timeout argument must be a number", util.callerFile(), util.callerLine())
+ throw new Error("QtQuickTest::fail")
+ }
+
+ if (msg && typeof(msg) !== "string") {
+ qtest_results.fail("message argument must be a string", util.callerFile(), util.callerLine())
+ throw new Error("QtQuickTest::fail")
+ }
+
+ if (!timeout)
+ timeout = 5000
+
+ if (msg === undefined)
+ msg = "function returned false"
+
+ if (!expressionFunction())
+ wait(0)
+
+ var i = 0
+ while (i < timeout && !expressionFunction()) {
+ wait(50)
+ i += 50
+ }
+
+ if (!qtest_results.verify(expressionFunction(), msg, util.callerFile(), util.callerLine()))
+ throw new Error("QtQuickTest::fail")
+ }
+
/*! \internal */
// Determine what is o.
// Discussions and reference: http://philrathe.com/articles/equiv
@@ -711,6 +778,11 @@ Item {
\sa compare(), SignalSpy::wait()
*/
function tryCompare(obj, prop, value, timeout, msg) {
+ if (arguments.length == 1 || (typeof(prop) != "string" && typeof(prop) != "number")) {
+ qtest_results.fail("A property name as string or index is required for tryCompare",
+ util.callerFile(), util.callerLine())
+ throw new Error("QtQuickTest::fail")
+ }
if (arguments.length == 2) {
qtest_results.fail("A value is required for tryCompare",
util.callerFile(), util.callerLine())
@@ -1053,6 +1125,7 @@ Item {
modifiers = Qt.NoModifier
if (delay == undefined)
delay = -1
+ var moveDelay = Math.max(1, delay === -1 ? qtest_events.defaultMouseDelay : delay)
// Divide dx and dy to have intermediate mouseMove while dragging
// Fractions of dx/dy need be superior to the dragThreshold
@@ -1066,12 +1139,12 @@ Item {
mousePress(item, x, y, button, modifiers, delay)
//trigger dragging
- mouseMove(item, x + util.dragThreshold + 1, y + util.dragThreshold + 1, delay, button)
+ mouseMove(item, x + util.dragThreshold + 1, y + util.dragThreshold + 1, moveDelay, button)
if (ddx > 0 || ddy > 0) {
- mouseMove(item, x + ddx, y + ddy, delay, button)
- mouseMove(item, x + 2*ddx, y + 2*ddy, delay, button)
+ mouseMove(item, x + ddx, y + ddy, moveDelay, button)
+ mouseMove(item, x + 2*ddx, y + 2*ddy, moveDelay, button)
}
- mouseMove(item, x + dx, y + dy, delay, button)
+ mouseMove(item, x + dx, y + dy, moveDelay, button)
mouseRelease(item, x + dx, y + dy, button, modifiers, delay)
}
diff --git a/src/imports/testlib/plugins.qmltypes b/src/imports/testlib/plugins.qmltypes
index 2beb38a940..563778e55e 100644
--- a/src/imports/testlib/plugins.qmltypes
+++ b/src/imports/testlib/plugins.qmltypes
@@ -4,15 +4,16 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtTest 1.0'
+// 'qmlplugindump -nonrelocatable -noforceqtquick QtTest 1.1'
Module {
- dependencies: []
+ dependencies: ["QtQuick 2.0"]
Component {
name: "QuickTestEvent"
prototype: "QObject"
exports: ["QtTest/TestEvent 1.0"]
exportMetaObjectRevisions: [0]
+ Property { name: "defaultMouseDelay"; type: "int"; isReadonly: true }
Method {
name: "keyPress"
type: "bool"
diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes
index 8c21271614..6a8dbfa024 100644
--- a/src/imports/window/plugins.qmltypes
+++ b/src/imports/window/plugins.qmltypes
@@ -7,7 +7,20 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable QtQuick.Window 2.2'
Module {
- dependencies: []
+ dependencies: ["QtQuick 2.8"]
+ Component {
+ name: "QQuickRootItem"
+ defaultProperty: "data"
+ prototype: "QQuickItem"
+ Method {
+ name: "setWidth"
+ Parameter { name: "w"; type: "int" }
+ }
+ Method {
+ name: "setHeight"
+ Parameter { name: "h"; type: "int" }
+ }
+ }
Component {
name: "QQuickScreen"
prototype: "QObject"
@@ -102,6 +115,7 @@ Module {
Property { name: "contentItem"; type: "QQuickItem"; isReadonly: true; isPointer: true }
Property { name: "width"; type: "int"; isReadonly: true }
Property { name: "height"; type: "int"; isReadonly: true }
+ Property { name: "window"; type: "QQuickWindow"; isReadonly: true; isPointer: true }
}
Component {
name: "QQuickWindowQmlImpl"
diff --git a/src/imports/xmllistmodel/plugins.qmltypes b/src/imports/xmllistmodel/plugins.qmltypes
index d098d11409..cc675d5f83 100644
--- a/src/imports/xmllistmodel/plugins.qmltypes
+++ b/src/imports/xmllistmodel/plugins.qmltypes
@@ -7,272 +7,7 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable QtQuick.XmlListModel 2.0'
Module {
- dependencies: []
- Component {
- name: "QAbstractItemModel"
- prototype: "QObject"
- Enum {
- name: "LayoutChangeHint"
- values: {
- "NoLayoutChangeHint": 0,
- "VerticalSortHint": 1,
- "HorizontalSortHint": 2
- }
- }
- Signal {
- name: "dataChanged"
- Parameter { name: "topLeft"; type: "QModelIndex" }
- Parameter { name: "bottomRight"; type: "QModelIndex" }
- Parameter { name: "roles"; type: "QVector<int>" }
- }
- Signal {
- name: "dataChanged"
- Parameter { name: "topLeft"; type: "QModelIndex" }
- Parameter { name: "bottomRight"; type: "QModelIndex" }
- }
- Signal {
- name: "headerDataChanged"
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "layoutChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
- }
- Signal {
- name: "layoutChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- }
- Signal { name: "layoutChanged" }
- Signal {
- name: "layoutAboutToBeChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
- }
- Signal {
- name: "layoutAboutToBeChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- }
- Signal { name: "layoutAboutToBeChanged" }
- Signal {
- name: "rowsAboutToBeInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsAboutToBeRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal { name: "modelAboutToBeReset" }
- Signal { name: "modelReset" }
- Signal {
- name: "rowsAboutToBeMoved"
- Parameter { name: "sourceParent"; type: "QModelIndex" }
- Parameter { name: "sourceStart"; type: "int" }
- Parameter { name: "sourceEnd"; type: "int" }
- Parameter { name: "destinationParent"; type: "QModelIndex" }
- Parameter { name: "destinationRow"; type: "int" }
- }
- Signal {
- name: "rowsMoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "start"; type: "int" }
- Parameter { name: "end"; type: "int" }
- Parameter { name: "destination"; type: "QModelIndex" }
- Parameter { name: "row"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeMoved"
- Parameter { name: "sourceParent"; type: "QModelIndex" }
- Parameter { name: "sourceStart"; type: "int" }
- Parameter { name: "sourceEnd"; type: "int" }
- Parameter { name: "destinationParent"; type: "QModelIndex" }
- Parameter { name: "destinationColumn"; type: "int" }
- }
- Signal {
- name: "columnsMoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "start"; type: "int" }
- Parameter { name: "end"; type: "int" }
- Parameter { name: "destination"; type: "QModelIndex" }
- Parameter { name: "column"; type: "int" }
- }
- Method { name: "submit"; type: "bool" }
- Method { name: "revert" }
- Method {
- name: "hasIndex"
- type: "bool"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "hasIndex"
- type: "bool"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- }
- Method {
- name: "index"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "index"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- }
- Method {
- name: "parent"
- type: "QModelIndex"
- Parameter { name: "child"; type: "QModelIndex" }
- }
- Method {
- name: "sibling"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "idx"; type: "QModelIndex" }
- }
- Method {
- name: "rowCount"
- type: "int"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "rowCount"; type: "int" }
- Method {
- name: "columnCount"
- type: "int"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "columnCount"; type: "int" }
- Method {
- name: "hasChildren"
- type: "bool"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "hasChildren"; type: "bool" }
- Method {
- name: "data"
- type: "QVariant"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "data"
- type: "QVariant"
- Parameter { name: "index"; type: "QModelIndex" }
- }
- Method {
- name: "setData"
- type: "bool"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "setData"
- type: "bool"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "value"; type: "QVariant" }
- }
- Method {
- name: "headerData"
- type: "QVariant"
- Parameter { name: "section"; type: "int" }
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "headerData"
- type: "QVariant"
- Parameter { name: "section"; type: "int" }
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- }
- Method {
- name: "fetchMore"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "canFetchMore"
- type: "bool"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "flags"
- type: "Qt::ItemFlags"
- Parameter { name: "index"; type: "QModelIndex" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "hits"; type: "int" }
- Parameter { name: "flags"; type: "Qt::MatchFlags" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "hits"; type: "int" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- }
- }
- Component { name: "QAbstractListModel"; prototype: "QAbstractItemModel" }
+ dependencies: ["QtQuick 2.8"]
Component {
name: "QQuickXmlListModel"
defaultProperty: "roles"
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
index 6e9e57a046..4306f477e9 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
@@ -176,7 +176,7 @@ public:
QQuickXmlQueryThreadObject(QQuickXmlQueryEngine *);
void processJobs();
- virtual bool event(QEvent *e);
+ bool event(QEvent *e) override;
private:
QQuickXmlQueryEngine *m_queryEngine;
@@ -202,7 +202,7 @@ signals:
void error(void*, const QString&);
protected:
- void run();
+ void run() override;
private:
void processQuery(XmlQueryJob *job);
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h
index f0096a9125..409dfa876d 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h
@@ -95,10 +95,10 @@ public:
QQuickXmlListModel(QObject *parent = 0);
~QQuickXmlListModel();
- QModelIndex index(int row, int column, const QModelIndex &parent) const;
- int rowCount(const QModelIndex &parent) const;
- QVariant data(const QModelIndex &index, int role) const;
- QHash<int, QByteArray> roleNames() const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const override;
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QHash<int, QByteArray> roleNames() const override;
int count() const;
@@ -124,8 +124,8 @@ public:
Q_INVOKABLE QString errorString() const;
- virtual void classBegin();
- virtual void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
Q_SIGNALS:
void statusChanged(QQuickXmlListModel::Status);
diff --git a/src/particles/qquickage_p.h b/src/particles/qquickage_p.h
index f6e277f8a7..5db6167dc1 100644
--- a/src/particles/qquickage_p.h
+++ b/src/particles/qquickage_p.h
@@ -74,7 +74,8 @@ public:
}
protected:
- virtual bool affectParticle(QQuickParticleData *d, qreal dt);
+ bool affectParticle(QQuickParticleData *d, qreal dt) override;
+
Q_SIGNALS:
void lifeLeftChanged(int arg);
void advancePositionChanged(bool arg);
diff --git a/src/particles/qquickangledirection.cpp b/src/particles/qquickangledirection.cpp
index 09aa047670..6f30e24a26 100644
--- a/src/particles/qquickangledirection.cpp
+++ b/src/particles/qquickangledirection.cpp
@@ -104,7 +104,7 @@ QQuickAngleDirection::QQuickAngleDirection(QObject *parent) :
}
-const QPointF QQuickAngleDirection::sample(const QPointF &from)
+QPointF QQuickAngleDirection::sample(const QPointF &from)
{
Q_UNUSED(from);
QPointF ret;
diff --git a/src/particles/qquickangledirection_p.h b/src/particles/qquickangledirection_p.h
index 3e981c5f9e..66290fb19e 100644
--- a/src/particles/qquickangledirection_p.h
+++ b/src/particles/qquickangledirection_p.h
@@ -62,7 +62,7 @@ class QQuickAngleDirection : public QQuickDirection
Q_PROPERTY(qreal magnitudeVariation READ magnitudeVariation WRITE setMagnitudeVariation NOTIFY magnitudeVariationChanged)
public:
explicit QQuickAngleDirection(QObject *parent = 0);
- const QPointF sample(const QPointF &from);
+ QPointF sample(const QPointF &from) override;
qreal angle() const
{
return m_angle;
diff --git a/src/particles/qquickcumulativedirection.cpp b/src/particles/qquickcumulativedirection.cpp
index b6b3e76f69..6fbd53df48 100644
--- a/src/particles/qquickcumulativedirection.cpp
+++ b/src/particles/qquickcumulativedirection.cpp
@@ -59,7 +59,7 @@ QQmlListProperty<QQuickDirection> QQuickCumulativeDirection::directions()
return QQmlListProperty<QQuickDirection>(this, m_directions);//TODO: Proper list property
}
-const QPointF QQuickCumulativeDirection::sample(const QPointF &from)
+QPointF QQuickCumulativeDirection::sample(const QPointF &from)
{
QPointF ret;
foreach (QQuickDirection* dir, m_directions)
diff --git a/src/particles/qquickcumulativedirection_p.h b/src/particles/qquickcumulativedirection_p.h
index 9af86bd39e..39f8ab8a24 100644
--- a/src/particles/qquickcumulativedirection_p.h
+++ b/src/particles/qquickcumulativedirection_p.h
@@ -62,7 +62,7 @@ class QQuickCumulativeDirection : public QQuickDirection
public:
explicit QQuickCumulativeDirection(QObject *parent = 0);
QQmlListProperty<QQuickDirection> directions();
- const QPointF sample(const QPointF &from);
+ QPointF sample(const QPointF &from) override;
private:
QList<QQuickDirection*> m_directions;
};
diff --git a/src/particles/qquickcustomaffector_p.h b/src/particles/qquickcustomaffector_p.h
index a383b196c2..c1745798c3 100644
--- a/src/particles/qquickcustomaffector_p.h
+++ b/src/particles/qquickcustomaffector_p.h
@@ -69,7 +69,7 @@ class QQuickCustomAffector : public QQuickParticleAffector
public:
explicit QQuickCustomAffector(QQuickItem *parent = 0);
- virtual void affectSystem(qreal dt);
+ void affectSystem(qreal dt) override;
QQuickDirection * position() const
{
@@ -153,7 +153,8 @@ public Q_SLOTS:
protected:
bool isAffectConnected();
- virtual bool affectParticle(QQuickParticleData *d, qreal dt);
+ bool affectParticle(QQuickParticleData *d, qreal dt) override;
+
private:
void affectProperties(const QList<QQuickParticleData*> particles, qreal dt);
QQuickDirection * m_position;
diff --git a/src/particles/qquickcustomparticle.cpp b/src/particles/qquickcustomparticle.cpp
index a89b0d6a3b..c08ae3d9ff 100644
--- a/src/particles/qquickcustomparticle.cpp
+++ b/src/particles/qquickcustomparticle.cpp
@@ -94,7 +94,8 @@ struct PlainVertices {
QQuickCustomParticle::QQuickCustomParticle(QQuickItem* parent)
: QQuickParticlePainter(parent)
- , m_common(this)
+ , m_common(this, [this](int mappedId){this->propertyChanged(mappedId);})
+ , m_myMetaObject(nullptr)
, m_dirtyUniforms(true)
, m_dirtyUniformValues(true)
, m_dirtyTextureProviders(true)
@@ -114,7 +115,10 @@ QQuickCustomParticle::~QQuickCustomParticle()
void QQuickCustomParticle::componentComplete()
{
- m_common.updateShader(this, Key::FragmentShader);
+ if (!m_myMetaObject)
+ m_myMetaObject = metaObject();
+
+ m_common.updateShader(this, m_myMetaObject, Key::FragmentShader);
updateVertexShader();
reset();
QQuickParticlePainter::componentComplete();
@@ -138,7 +142,7 @@ void QQuickCustomParticle::setFragmentShader(const QByteArray &code)
m_common.source.sourceCode[Key::FragmentShader] = code;
m_dirtyProgram = true;
if (isComponentComplete()) {
- m_common.updateShader(this, Key::FragmentShader);
+ m_common.updateShader(this, m_myMetaObject, Key::FragmentShader);
reset();
}
emit fragmentShaderChanged();
@@ -202,9 +206,8 @@ void QQuickCustomParticle::setVertexShader(const QByteArray &code)
void QQuickCustomParticle::updateVertexShader()
{
m_common.disconnectPropertySignals(this, Key::VertexShader);
- qDeleteAll(m_common.signalMappers[Key::VertexShader]);
m_common.uniformData[Key::VertexShader].clear();
- m_common.signalMappers[Key::VertexShader].clear();
+ m_common.clearSignalMappers(Key::VertexShader);
m_common.attributes.clear();
m_common.attributes.append("qt_ParticlePos");
m_common.attributes.append("qt_ParticleTex");
@@ -225,9 +228,9 @@ void QQuickCustomParticle::updateVertexShader()
const QByteArray &code = m_common.source.sourceCode[Key::VertexShader];
if (!code.isEmpty())
- m_common.lookThroughShaderCode(this, Key::VertexShader, code);
+ m_common.lookThroughShaderCode(this, m_myMetaObject, Key::VertexShader, code);
- m_common.connectPropertySignals(this, Key::VertexShader);
+ m_common.connectPropertySignals(this, m_myMetaObject, Key::VertexShader);
}
void QQuickCustomParticle::reset()
@@ -392,7 +395,7 @@ void QQuickCustomParticle::sourceDestroyed(QObject *object)
void QQuickCustomParticle::propertyChanged(int mappedId)
{
bool textureProviderChanged;
- m_common.propertyChanged(this, mappedId, &textureProviderChanged);
+ m_common.propertyChanged(this, m_myMetaObject, mappedId, &textureProviderChanged);
m_dirtyTextureProviders |= textureProviderChanged;
m_dirtyUniformValues = true;
update();
diff --git a/src/particles/qquickcustomparticle_p.h b/src/particles/qquickcustomparticle_p.h
index d9690aa96a..1d48786a41 100644
--- a/src/particles/qquickcustomparticle_p.h
+++ b/src/particles/qquickcustomparticle_p.h
@@ -84,24 +84,25 @@ Q_SIGNALS:
void vertexShaderChanged();
protected:
- virtual void initialize(int gIdx, int pIdx);
- virtual void commit(int gIdx, int pIdx);
+ void initialize(int gIdx, int pIdx) override;
+ void commit(int gIdx, int pIdx) override;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
QQuickOpenGLShaderEffectNode *prepareNextFrame(QQuickOpenGLShaderEffectNode *rootNode);
- void reset();
+ void reset() override;
void resize(int oldCount, int newCount);
- virtual void componentComplete();
+ void componentComplete() override;
QQuickOpenGLShaderEffectNode *buildCustomNodes();
- void sceneGraphInvalidated();
- void itemChange(ItemChange change, const ItemChangeData &value);
+ void sceneGraphInvalidated() override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
private Q_SLOTS:
void sourceDestroyed(QObject *object);
- void propertyChanged(int mappedId);
private:
+ void propertyChanged(int mappedId);
+
typedef QQuickOpenGLShaderEffectMaterialKey Key;
typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
@@ -109,6 +110,7 @@ private:
void updateVertexShader();
QQuickOpenGLShaderEffectCommon m_common;
+ const QMetaObject *m_myMetaObject;
QHash<int, QQuickOpenGLShaderEffectNode*> m_nodes;
qreal m_lastTime;
diff --git a/src/particles/qquickdirection.cpp b/src/particles/qquickdirection.cpp
index da1edfb3c3..fd94c8945c 100644
--- a/src/particles/qquickdirection.cpp
+++ b/src/particles/qquickdirection.cpp
@@ -56,7 +56,7 @@ QQuickDirection::QQuickDirection(QObject *parent) :
{
}
-const QPointF QQuickDirection::sample(const QPointF &from)
+QPointF QQuickDirection::sample(const QPointF &from)
{
Q_UNUSED(from);
return QPointF();
diff --git a/src/particles/qquickdirection_p.h b/src/particles/qquickdirection_p.h
index f7029488f7..10960f9920 100644
--- a/src/particles/qquickdirection_p.h
+++ b/src/particles/qquickdirection_p.h
@@ -62,7 +62,7 @@ class QQuickDirection : public QObject
public:
explicit QQuickDirection(QObject *parent = 0);
- virtual const QPointF sample(const QPointF &from);
+ virtual QPointF sample(const QPointF &from);
Q_SIGNALS:
public Q_SLOTS:
diff --git a/src/particles/qquickellipseextruder_p.h b/src/particles/qquickellipseextruder_p.h
index 1df7e32c83..0af7f4d94f 100644
--- a/src/particles/qquickellipseextruder_p.h
+++ b/src/particles/qquickellipseextruder_p.h
@@ -60,8 +60,8 @@ class QQuickEllipseExtruder : public QQuickParticleExtruder
Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)//###Use base class? If it's still box
public:
explicit QQuickEllipseExtruder(QObject *parent = 0);
- virtual QPointF extrude(const QRectF &);
- virtual bool contains(const QRectF &bounds, const QPointF &point);
+ QPointF extrude(const QRectF &) override;
+ bool contains(const QRectF &bounds, const QPointF &point) override;
bool fill() const
{
diff --git a/src/particles/qquickfriction_p.h b/src/particles/qquickfriction_p.h
index b67de631be..05ae7a38d5 100644
--- a/src/particles/qquickfriction_p.h
+++ b/src/particles/qquickfriction_p.h
@@ -73,7 +73,7 @@ public:
}
protected:
- virtual bool affectParticle(QQuickParticleData *d, qreal dt);
+ bool affectParticle(QQuickParticleData *d, qreal dt) override;
Q_SIGNALS:
diff --git a/src/particles/qquickgravity_p.h b/src/particles/qquickgravity_p.h
index 7c071c932d..d3a7f6665c 100644
--- a/src/particles/qquickgravity_p.h
+++ b/src/particles/qquickgravity_p.h
@@ -72,7 +72,8 @@ public:
return m_angle;
}
protected:
- virtual bool affectParticle(QQuickParticleData *d, qreal dt);
+ bool affectParticle(QQuickParticleData *d, qreal dt) override;
+
Q_SIGNALS:
void magnitudeChanged(qreal arg);
diff --git a/src/particles/qquickgroupgoal_p.h b/src/particles/qquickgroupgoal_p.h
index 0b935fc1d1..9a56ef5cce 100644
--- a/src/particles/qquickgroupgoal_p.h
+++ b/src/particles/qquickgroupgoal_p.h
@@ -75,7 +75,7 @@ public:
}
protected:
- virtual bool affectParticle(QQuickParticleData *d, qreal dt);
+ bool affectParticle(QQuickParticleData *d, qreal dt) override;
Q_SIGNALS:
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index 07cbee1383..c68153aca8 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -49,6 +49,7 @@
#include <private/qquicksprite_p.h>
#include <private/qquickspriteengine_p.h>
#include <QOpenGLFunctions>
+#include <QSGRendererInterface>
#include <QtQuick/private/qsgshadersourcebuilder_p.h>
#include <QtQuick/private/qsgtexture_p.h>
#include <private/qqmlglobal_p.h>
@@ -1469,8 +1470,17 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
update();
}
+static inline bool isOpenGL(QSGRenderContext *rc)
+{
+ QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc);
+ return !rif || rif->graphicsApi() == QSGRendererInterface::OpenGL;
+}
+
QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
+ if (!node && !isOpenGL(QQuickItemPrivate::get(this)->sceneGraphRenderContext()))
+ return 0;
+
if (m_pleaseReset){
if (node)
delete node;
diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h
index 492ec23c07..95323c25a6 100644
--- a/src/particles/qquickimageparticle_p.h
+++ b/src/particles/qquickimageparticle_p.h
@@ -347,15 +347,15 @@ public Q_SLOTS:
void setEntryEffect(EntryEffect arg);
protected:
- void reset();
- virtual void initialize(int gIdx, int pIdx);
- virtual void commit(int gIdx, int pIdx);
+ void reset() override;
+ void initialize(int gIdx, int pIdx) override;
+ void commit(int gIdx, int pIdx) override;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
void prepareNextFrame(QSGNode**);
void buildParticleNodes(QSGNode**);
- void sceneGraphInvalidated();
+ void sceneGraphInvalidated() override;
private Q_SLOTS:
void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty
@@ -440,7 +440,7 @@ private:
}
template<class MaterialData>
- MaterialData* getState(QSGMaterial* m){
+ static MaterialData* getState(QSGMaterial* m) {
return static_cast<QSGSimpleMaterial<MaterialData> *>(m)->state();
}
EntryEffect m_entryEffect;
diff --git a/src/particles/qquickitemparticle_p.h b/src/particles/qquickitemparticle_p.h
index 0edd05dfc7..9e6c7deaea 100644
--- a/src/particles/qquickitemparticle_p.h
+++ b/src/particles/qquickitemparticle_p.h
@@ -70,7 +70,7 @@ public:
bool fade() const { return m_fade; }
- virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
static QQuickItemParticleAttached *qmlAttachedProperties(QObject *object);
QQmlComponent* delegate() const
@@ -100,9 +100,9 @@ public Q_SLOTS:
}
protected:
- virtual void reset();
- virtual void commit(int gIdx, int pIdx);
- virtual void initialize(int gIdx, int pIdx);
+ void reset() override;
+ void commit(int gIdx, int pIdx) override;
+ void initialize(int gIdx, int pIdx) override;
void prepareNextFrame();
private:
void processDeletables();
@@ -131,7 +131,7 @@ public:
QQuickItemParticleAttached(QObject* parent)
: QObject(parent), m_mp(0)
{;}
- QQuickItemParticle* particle() {return m_mp;}
+ QQuickItemParticle* particle() const { return m_mp; }
void detach(){Q_EMIT detached();}
void attach(){Q_EMIT attached();}
private:
diff --git a/src/particles/qquicklineextruder_p.h b/src/particles/qquicklineextruder_p.h
index 72d2300dce..306f3a1dd6 100644
--- a/src/particles/qquicklineextruder_p.h
+++ b/src/particles/qquicklineextruder_p.h
@@ -56,11 +56,11 @@ class QQuickLineExtruder : public QQuickParticleExtruder
{
Q_OBJECT
//Default is topleft to bottom right. Flipped makes it topright to bottom left
- Q_PROPERTY(bool mirrored READ mirrored WRITE setmirrored NOTIFY mirroredChanged)
+ Q_PROPERTY(bool mirrored READ mirrored WRITE setMirrored NOTIFY mirroredChanged)
public:
explicit QQuickLineExtruder(QObject *parent = 0);
- virtual QPointF extrude(const QRectF &);
+ QPointF extrude(const QRectF &) override;
bool mirrored() const
{
return m_mirrored;
@@ -72,7 +72,7 @@ Q_SIGNALS:
public Q_SLOTS:
- void setmirrored(bool arg)
+ void setMirrored(bool arg)
{
if (m_mirrored != arg) {
m_mirrored = arg;
diff --git a/src/particles/qquickmaskextruder_p.h b/src/particles/qquickmaskextruder_p.h
index 32ace521da..0fc0331db8 100644
--- a/src/particles/qquickmaskextruder_p.h
+++ b/src/particles/qquickmaskextruder_p.h
@@ -63,8 +63,8 @@ class QQuickMaskExtruder : public QQuickParticleExtruder
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
public:
explicit QQuickMaskExtruder(QObject *parent = 0);
- virtual QPointF extrude(const QRectF &);
- virtual bool contains(const QRectF &bounds, const QPointF &point);
+ QPointF extrude(const QRectF &) override;
+ bool contains(const QRectF &bounds, const QPointF &point) override;
QUrl source() const
{
diff --git a/src/particles/qquickparticleaffector.cpp b/src/particles/qquickparticleaffector.cpp
index 6ed0d9e14a..31bcfb82af 100644
--- a/src/particles/qquickparticleaffector.cpp
+++ b/src/particles/qquickparticleaffector.cpp
@@ -244,7 +244,7 @@ void QQuickParticleAffector::updateOffsets()
m_offset = m_system->mapFromItem(this, QPointF(0, 0));
}
-bool QQuickParticleAffector::isColliding(QQuickParticleData *d)
+bool QQuickParticleAffector::isColliding(QQuickParticleData *d) const
{
qreal myCurX = d->curX(m_system);
qreal myCurY = d->curY(m_system);
diff --git a/src/particles/qquickparticleaffector_p.h b/src/particles/qquickparticleaffector_p.h
index c42c0b4cba..5c9652bc32 100644
--- a/src/particles/qquickparticleaffector_p.h
+++ b/src/particles/qquickparticleaffector_p.h
@@ -185,7 +185,7 @@ protected:
bool activeGroup(int g);
bool shouldAffect(QQuickParticleData* datum);//Call to do the logic on whether it is affecting that datum
void postAffect(QQuickParticleData* datum);//Call to do the post-affect logic on particles which WERE affected(once off, needs reset, affected signal)
- virtual void componentComplete();
+ void componentComplete() override;
bool isAffectedConnected();
static const qreal simulationDelta;
static const qreal simulationCutoff;
@@ -200,7 +200,7 @@ private:
QStringList m_whenCollidingWith;
- bool isColliding(QQuickParticleData* d);
+ bool isColliding(QQuickParticleData* d) const;
};
QT_END_NAMESPACE
diff --git a/src/particles/qquickparticleemitter_p.h b/src/particles/qquickparticleemitter_p.h
index dd55fdc7a6..4f7e12da44 100644
--- a/src/particles/qquickparticleemitter_p.h
+++ b/src/particles/qquickparticleemitter_p.h
@@ -62,7 +62,7 @@
#include <QPointF>
QT_BEGIN_NAMESPACE
-class QQuickParticleEmitter : public QQuickItem
+class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleEmitter : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QQuickParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
@@ -133,7 +133,7 @@ public:
qreal velocityFromMovement() const { return m_velocity_from_movement; }
void setVelocityFromMovement(qreal s);
- virtual void componentComplete();
+ void componentComplete() override;
Q_SIGNALS:
void emitParticles(QQmlV4Handle particles);
void particlesPerSecondChanged(qreal);
diff --git a/src/particles/qquickparticlegroup_p.h b/src/particles/qquickparticlegroup_p.h
index 25cc2130b1..0314234569 100644
--- a/src/particles/qquickparticlegroup_p.h
+++ b/src/particles/qquickparticlegroup_p.h
@@ -104,8 +104,8 @@ Q_SIGNALS:
void systemChanged(QQuickParticleSystem* arg);
protected:
- virtual void componentComplete();
- virtual void classBegin(){;}
+ void componentComplete() override;
+ void classBegin() override {}
private:
diff --git a/src/particles/qquickparticlepainter.cpp b/src/particles/qquickparticlepainter.cpp
index d6303eb219..0c2521cd9e 100644
--- a/src/particles/qquickparticlepainter.cpp
+++ b/src/particles/qquickparticlepainter.cpp
@@ -103,7 +103,8 @@ void QQuickParticlePainter::recalculateGroupIds() const
m_groupIdsNeedRecalculation = false;
m_groupIds.clear();
- for (const QString &str : groups()) {
+ const auto groupList = groups();
+ for (const QString &str : groupList) {
QQuickParticleGroupData::ID groupId = m_system->groupIds.value(str, QQuickParticleGroupData::InvalidID);
if (groupId == QQuickParticleGroupData::InvalidID) {
// invalid data, not finished setting up, or whatever. Fallback: do not cache.
diff --git a/src/particles/qquickparticlepainter_p.h b/src/particles/qquickparticlepainter_p.h
index 064ce27fe8..ac14a18103 100644
--- a/src/particles/qquickparticlepainter_p.h
+++ b/src/particles/qquickparticlepainter_p.h
@@ -98,7 +98,7 @@ public:
return m_groupIds;
}
- void itemChange(ItemChange, const ItemChangeData &);
+ void itemChange(ItemChange, const ItemChangeData &) override;
Q_SIGNALS:
void countChanged();
@@ -123,7 +123,7 @@ protected:
*/
virtual void reset();
- virtual void componentComplete();
+ void componentComplete() override;
virtual void initialize(int gIdx, int pIdx){//Called from main thread
Q_UNUSED(gIdx);
Q_UNUSED(pIdx);
diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h
index b57d55bd98..de39b436e2 100644
--- a/src/particles/qquickparticlesystem_p.h
+++ b/src/particles/qquickparticlesystem_p.h
@@ -389,7 +389,7 @@ public Q_SLOTS:
protected:
//This one only once per frame (effectively)
- void componentComplete();
+ void componentComplete() override;
private Q_SLOTS:
void emittersChanged();
@@ -477,12 +477,12 @@ public:
: QAbstractAnimation(static_cast<QObject*>(system)), m_system(system)
{ }
protected:
- virtual void updateCurrentTime( int t )
+ void updateCurrentTime(int t) override
{
m_system->updateCurrentTime(t);
}
- virtual int duration() const
+ int duration() const override
{
return -1;
}
diff --git a/src/particles/qquickpointattractor_p.h b/src/particles/qquickpointattractor_p.h
index 99fae300c6..47985b5e82 100644
--- a/src/particles/qquickpointattractor_p.h
+++ b/src/particles/qquickpointattractor_p.h
@@ -160,7 +160,8 @@ void setProportionalToDistance(Proportion arg)
}
protected:
- virtual bool affectParticle(QQuickParticleData *d, qreal dt);
+ bool affectParticle(QQuickParticleData *d, qreal dt) override;
+
private:
qreal m_strength;
qreal m_x;
diff --git a/src/particles/qquickpointdirection.cpp b/src/particles/qquickpointdirection.cpp
index dbd15148ba..9038ce0aa0 100644
--- a/src/particles/qquickpointdirection.cpp
+++ b/src/particles/qquickpointdirection.cpp
@@ -75,7 +75,7 @@ QQuickPointDirection::QQuickPointDirection(QObject *parent) :
{
}
-const QPointF QQuickPointDirection::sample(const QPointF &)
+QPointF QQuickPointDirection::sample(const QPointF &)
{
QPointF ret;
ret.setX(m_x - m_xVariation + rand() / float(RAND_MAX) * m_xVariation * 2);
diff --git a/src/particles/qquickpointdirection_p.h b/src/particles/qquickpointdirection_p.h
index b01dc7ea4e..a80be928ad 100644
--- a/src/particles/qquickpointdirection_p.h
+++ b/src/particles/qquickpointdirection_p.h
@@ -63,7 +63,7 @@ class QQuickPointDirection : public QQuickDirection
Q_PROPERTY(qreal yVariation READ yVariation WRITE setYVariation NOTIFY yVariationChanged)
public:
explicit QQuickPointDirection(QObject *parent = 0);
- virtual const QPointF sample(const QPointF &from);
+ QPointF sample(const QPointF &from) override;
qreal x() const
{
return m_x;
diff --git a/src/particles/qquickrectangleextruder_p.h b/src/particles/qquickrectangleextruder_p.h
index 001031c711..630cf3050d 100644
--- a/src/particles/qquickrectangleextruder_p.h
+++ b/src/particles/qquickrectangleextruder_p.h
@@ -62,8 +62,8 @@ class QQuickRectangleExtruder : public QQuickParticleExtruder
public:
explicit QQuickRectangleExtruder(QObject *parent = 0);
- virtual QPointF extrude(const QRectF &);
- virtual bool contains(const QRectF &bounds, const QPointF &point);
+ QPointF extrude(const QRectF &) override;
+ bool contains(const QRectF &bounds, const QPointF &point) override;
bool fill() const
{
return m_fill;
diff --git a/src/particles/qquickspritegoal_p.h b/src/particles/qquickspritegoal_p.h
index 7174fd2318..2b15d0b8bb 100644
--- a/src/particles/qquickspritegoal_p.h
+++ b/src/particles/qquickspritegoal_p.h
@@ -81,7 +81,8 @@ public:
}
protected:
- virtual bool affectParticle(QQuickParticleData *d, qreal dt);
+ bool affectParticle(QQuickParticleData *d, qreal dt) override;
+
Q_SIGNALS:
void goalStateChanged(const QString &arg);
diff --git a/src/particles/qquicktargetdirection.cpp b/src/particles/qquicktargetdirection.cpp
index f9bcfbc564..012c9a151b 100644
--- a/src/particles/qquicktargetdirection.cpp
+++ b/src/particles/qquicktargetdirection.cpp
@@ -94,7 +94,7 @@ QQuickTargetDirection::QQuickTargetDirection(QObject *parent) :
{
}
-const QPointF QQuickTargetDirection::sample(const QPointF &from)
+QPointF QQuickTargetDirection::sample(const QPointF &from)
{
//###This approach loses interpolating the last position of the target (like we could with the emitter) is it worthwhile?
QPointF ret;
diff --git a/src/particles/qquicktargetdirection_p.h b/src/particles/qquicktargetdirection_p.h
index 4de5867336..13e826743e 100644
--- a/src/particles/qquicktargetdirection_p.h
+++ b/src/particles/qquicktargetdirection_p.h
@@ -71,7 +71,7 @@ class QQuickTargetDirection : public QQuickDirection
public:
explicit QQuickTargetDirection(QObject *parent = 0);
- virtual const QPointF sample(const QPointF &from);
+ QPointF sample(const QPointF &from) override;
qreal targetX() const
{
diff --git a/src/particles/qquicktrailemitter_p.h b/src/particles/qquicktrailemitter_p.h
index b70f34999a..99464436ba 100644
--- a/src/particles/qquicktrailemitter_p.h
+++ b/src/particles/qquicktrailemitter_p.h
@@ -71,8 +71,8 @@ public:
};
Q_ENUM(EmitSize)
explicit QQuickTrailEmitter(QQuickItem *parent = 0);
- virtual void emitWindow(int timeStamp);
- virtual void reset();
+ void emitWindow(int timeStamp) override;
+ void reset() override;
int particlesPerParticlePerSecond() const
{
diff --git a/src/particles/qquickturbulence_p.h b/src/particles/qquickturbulence_p.h
index 7a6be1719e..e73f3ba153 100644
--- a/src/particles/qquickturbulence_p.h
+++ b/src/particles/qquickturbulence_p.h
@@ -65,7 +65,7 @@ class QQuickTurbulenceAffector : public QQuickParticleAffector
public:
explicit QQuickTurbulenceAffector(QQuickItem *parent = 0);
~QQuickTurbulenceAffector();
- virtual void affectSystem(qreal dt);
+ void affectSystem(qreal dt) override;
qreal strength() const
{
@@ -102,8 +102,8 @@ public Q_SLOTS:
}
protected:
- virtual void geometryChanged(const QRectF &newGeometry,
- const QRectF &oldGeometry);
+ void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry) override;
private:
void ensureInit();
void mapUpdate();
diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp
index 99451057ce..fbdbb85e94 100644
--- a/src/particles/qquickv4particledata.cpp
+++ b/src/particles/qquickv4particledata.cpp
@@ -524,7 +524,7 @@ QQuickV4ParticleData::~QQuickV4ParticleData()
{
}
-QQmlV4Handle QQuickV4ParticleData::v4Value()
+QQmlV4Handle QQuickV4ParticleData::v4Value() const
{
return QQmlV4Handle(m_v4Value.value());
}
diff --git a/src/particles/qquickv4particledata_p.h b/src/particles/qquickv4particledata_p.h
index 437491ff42..d73e3b644d 100644
--- a/src/particles/qquickv4particledata_p.h
+++ b/src/particles/qquickv4particledata_p.h
@@ -63,7 +63,7 @@ class QQuickV4ParticleData {
public:
QQuickV4ParticleData(QV8Engine*, QQuickParticleData*, QQuickParticleSystem *system);
~QQuickV4ParticleData();
- QQmlV4Handle v4Value();
+ QQmlV4Handle v4Value() const;
private:
QV4::PersistentValue m_v4Value;
};
diff --git a/src/particles/qquickwander_p.h b/src/particles/qquickwander_p.h
index 6461444cd1..0ad19d4d13 100644
--- a/src/particles/qquickwander_p.h
+++ b/src/particles/qquickwander_p.h
@@ -105,7 +105,8 @@ public:
}
protected:
- virtual bool affectParticle(QQuickParticleData *d, qreal dt);
+ bool affectParticle(QQuickParticleData *d, qreal dt) override;
+
Q_SIGNALS:
void xVarianceChanged(qreal arg);
diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
index d20ddf9dc0..e541810330 100644
--- a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
+++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
@@ -124,12 +124,9 @@ QPacketProtocol::QPacketProtocol(QIODevice *dev, QObject *parent)
Q_ASSERT(4 == sizeof(qint32));
Q_ASSERT(dev);
- QObject::connect(dev, SIGNAL(readyRead()),
- this, SLOT(readyToRead()));
- QObject::connect(dev, SIGNAL(aboutToClose()),
- this, SLOT(aboutToClose()));
- QObject::connect(dev, SIGNAL(bytesWritten(qint64)),
- this, SLOT(bytesWritten(qint64)));
+ QObject::connect(dev, &QIODevice::readyRead, this, &QPacketProtocol::readyToRead);
+ QObject::connect(dev, &QIODevice::aboutToClose, this, &QPacketProtocol::aboutToClose);
+ QObject::connect(dev, &QIODevice::bytesWritten, this, &QPacketProtocol::bytesWritten);
}
/*!
@@ -247,12 +244,9 @@ void QPacketProtocol::readyToRead()
// Check sizing constraints
if (d->inProgressSize > MAX_PACKET_SIZE) {
- QObject::disconnect(d->dev, SIGNAL(readyRead()),
- this, SLOT(readyToRead()));
- QObject::disconnect(d->dev, SIGNAL(aboutToClose()),
- this, SLOT(aboutToClose()));
- QObject::disconnect(d->dev, SIGNAL(bytesWritten(qint64)),
- this, SLOT(bytesWritten(qint64)));
+ disconnect(d->dev, &QIODevice::readyRead, this, &QPacketProtocol::readyToRead);
+ disconnect(d->dev, &QIODevice::aboutToClose, this, &QPacketProtocol::aboutToClose);
+ disconnect(d->dev, &QIODevice::bytesWritten, this, &QPacketProtocol::bytesWritten);
d->dev = 0;
emit invalidPacket();
return;
diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h b/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h
index 8f95a081e9..7fd722f17f 100644
--- a/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h
+++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h
@@ -74,7 +74,7 @@ Q_SIGNALS:
void readyRead();
void invalidPacket();
-private Q_SLOTS:
+private:
void aboutToClose();
void bytesWritten(qint64 bytes);
void readyToRead();
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index e08436b7a3..fe88d686fc 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -63,8 +63,12 @@ QT_BEGIN_NAMESPACE
QQmlEngineDebugServiceImpl::QQmlEngineDebugServiceImpl(QObject *parent) :
QQmlEngineDebugService(2, parent), m_watch(new QQmlWatcher(this)), m_statesDelegate(0)
{
- QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)),
- this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant)));
+ connect(m_watch, &QQmlWatcher::propertyChanged,
+ this, &QQmlEngineDebugServiceImpl::propertyChanged);
+
+ // Move the message into the correct thread for processing
+ connect(this, &QQmlEngineDebugServiceImpl::scheduleMessage,
+ this, &QQmlEngineDebugServiceImpl::processMessage, Qt::QueuedConnection);
}
QQmlEngineDebugServiceImpl::~QQmlEngineDebugServiceImpl()
@@ -285,10 +289,12 @@ void QQmlEngineDebugServiceImpl::buildObjectDump(QDataStream &message,
prop.value = expr->expression();
QObject *scope = expr->scopeObject();
if (scope) {
- QString methodName = QString::fromLatin1(QMetaObjectPrivate::signal(scope->metaObject(), signalHandler->signalIndex()).name());
- if (!methodName.isEmpty()) {
- prop.name = QLatin1String("on") + methodName[0].toUpper()
- + methodName.mid(1);
+ const QByteArray methodName = QMetaObjectPrivate::signal(scope->metaObject(),
+ signalHandler->signalIndex()).name();
+ const QLatin1String methodNameStr(methodName);
+ if (methodNameStr.size() != 0) {
+ prop.name = QLatin1String("on") + QChar(methodNameStr.at(0)).toUpper()
+ + methodNameStr.mid(1);
}
}
}
@@ -420,7 +426,7 @@ QQmlEngineDebugServiceImpl::objectData(QObject *object)
void QQmlEngineDebugServiceImpl::messageReceived(const QByteArray &message)
{
- QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message));
+ emit scheduleMessage(message);
}
/*!
@@ -516,12 +522,12 @@ void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message)
ds >> file >> lineNumber >> columnNumber >> recurse >> dumpProperties;
- QList<QObject*> objects = objectForLocationInfo(file, lineNumber, columnNumber);
+ const QList<QObject*> objects = objectForLocationInfo(file, lineNumber, columnNumber);
rs << QByteArray("FETCH_OBJECTS_FOR_LOCATION_R") << queryId
<< objects.count();
- foreach (QObject *object, objects) {
+ for (QObject *object : objects) {
if (recurse)
prepareDeferredObjects(object);
buildObjectDump(rs, object, recurse, dumpProperties);
@@ -656,7 +662,7 @@ bool QQmlEngineDebugServiceImpl::setBinding(int objectId,
filename, line, column);
QQmlPropertyPrivate::takeSignalExpression(property, qmlExpression);
} else if (property.isProperty()) {
- QQmlBinding *binding = new QQmlBinding(expression.toString(), object, QQmlContextData::get(context), filename, line, column);
+ QQmlBinding *binding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, expression.toString(), object, QQmlContextData::get(context), filename, line, column);
binding->setTarget(property);
QQmlPropertyPrivate::setBinding(binding);
binding->update();
@@ -749,7 +755,7 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth
if (!prop || !prop->isVMEFunction())
return false;
- QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex);
+ QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex());
QList<QByteArray> paramNames = metaMethod.parameterNames();
QString paramStr;
@@ -758,10 +764,8 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth
paramStr.append(QString::fromUtf8(paramNames.at(ii)));
}
- QString jsfunction = QLatin1String("(function ") + method + QLatin1Char('(') + paramStr +
- QLatin1String(") {");
- jsfunction += body;
- jsfunction += QLatin1String("\n})");
+ const QString jsfunction = QLatin1String("(function ") + method + QLatin1Char('(') + paramStr +
+ QLatin1String(") {") + body + QLatin1String("\n})");
QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
@@ -770,12 +774,12 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth
QV4::Scope scope(v4);
int lineNumber = 0;
- QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex));
+ QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex()));
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);
+ vmeMetaObject->setVmeMethod(prop->coreIndex(), v);
return true;
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h
index cb75a63850..2e40eb4de8 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h
@@ -101,16 +101,18 @@ public:
void setStatesDelegate(QQmlDebugStatesDelegate *) Q_DECL_OVERRIDE;
+signals:
+ void scheduleMessage(const QByteArray &);
+
protected:
virtual void messageReceived(const QByteArray &) Q_DECL_OVERRIDE;
-private Q_SLOTS:
- void processMessage(const QByteArray &msg);
- void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
-
private:
friend class QQmlDebuggerServiceFactory;
+ void processMessage(const QByteArray &msg);
+ void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
+
void prepareDeferredObjects(QObject *);
void buildObjectList(QDataStream &, QQmlContext *,
const QList<QPointer<QObject> > &instances);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp
index 99f5b760ba..9c198a8afc 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp
@@ -143,15 +143,15 @@ public:
void BreakPointHandler::handleSetBreakpoint(QJsonObject *response, const QJsonObject &arguments)
{
TRACE_PROTOCOL("SET BREAKPOINT" << arguments);
- QString type = arguments.value(QStringLiteral("type")).toString();
+ QString type = arguments.value(QLatin1String("type")).toString();
- QString fileName = arguments.value(QStringLiteral("file")).toString();
+ QString fileName = arguments.value(QLatin1String("file")).toString();
if (fileName.isEmpty()) {
setError(response, QStringLiteral("breakpoint has no file name"));
return;
}
- int line = arguments.value(QStringLiteral("line")).toInt(-1);
+ int line = arguments.value(QLatin1String("line")).toInt(-1);
if (line < 0) {
setError(response, QStringLiteral("breakpoint has an invalid line number"));
return;
@@ -161,9 +161,9 @@ void BreakPointHandler::handleSetBreakpoint(QJsonObject *response, const QJsonOb
bp.id = m_lastBreakpoint++;
bp.fileName = fileName.mid(fileName.lastIndexOf('/') + 1);
bp.lineNumber = line;
- bp.enabled = arguments.value(QStringLiteral("enabled")).toBool(true);
- bp.condition = arguments.value(QStringLiteral("condition")).toString();
- bp.ignoreCount = arguments.value(QStringLiteral("ignorecount")).toInt();
+ bp.enabled = arguments.value(QLatin1String("enabled")).toBool(true);
+ bp.condition = arguments.value(QLatin1String("condition")).toString();
+ bp.ignoreCount = arguments.value(QLatin1String("ignorecount")).toInt();
m_breakPoints.append(bp);
m_haveBreakPoints = true;
@@ -174,7 +174,7 @@ void BreakPointHandler::handleSetBreakpoint(QJsonObject *response, const QJsonOb
void BreakPointHandler::handleRemoveBreakpoint(QJsonObject *response, const QJsonObject &arguments)
{
- int id = arguments.value(QStringLiteral("id")).toInt();
+ int id = arguments.value(QLatin1String("id")).toInt();
removeBreakPoint(id);
response->insert(QStringLiteral("id"), id);
}
@@ -208,7 +208,7 @@ private:
void handleDebuggerDeleted(QObject *debugger);
- QV4::ReturnedValue evaluateExpression(QV4::Scope &scope, const QString &expression);
+ void evaluateExpression(QV4::Scope &scope, const QString &expression);
bool checkCondition(const QString &expression);
QStringList breakOnSignals;
@@ -241,12 +241,11 @@ private:
bool NativeDebugger::checkCondition(const QString &expression)
{
QV4::Scope scope(m_engine);
- QV4::ReturnedValue result = evaluateExpression(scope, expression);
- QV4::ScopedValue val(scope, result);
- return val->booleanValue();
+ evaluateExpression(scope, expression);
+ return scope.result.booleanValue();
}
-QV4::ReturnedValue NativeDebugger::evaluateExpression(QV4::Scope &scope, const QString &expression)
+void NativeDebugger::evaluateExpression(QV4::Scope &scope, const QString &expression)
{
m_runningJob = true;
@@ -261,12 +260,10 @@ QV4::ReturnedValue NativeDebugger::evaluateExpression(QV4::Scope &scope, const Q
// That is a side-effect of inheritContext.
script.inheritContext = true;
script.parse();
- QV4::ScopedValue result(scope);
if (!m_engine->hasException)
- result = script.run();
+ scope.result = script.run();
m_runningJob = false;
- return result->asReturnedValue();
}
NativeDebugger::NativeDebugger(QQmlNativeDebugServiceImpl *service, QV4::ExecutionEngine *engine)
@@ -290,7 +287,7 @@ void NativeDebugger::signalEmitted(const QString &signal)
//Normalize to Lower case.
QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower();
- foreach (const QString &signal, breakOnSignals) {
+ for (const QString &signal : qAsConst(breakOnSignals)) {
if (signal == signalName) {
// TODO: pause debugger
break;
@@ -301,19 +298,19 @@ void NativeDebugger::signalEmitted(const QString &signal)
void NativeDebugger::handleCommand(QJsonObject *response, const QString &cmd,
const QJsonObject &arguments)
{
- if (cmd == QStringLiteral("backtrace"))
+ if (cmd == QLatin1String("backtrace"))
handleBacktrace(response, arguments);
- else if (cmd == QStringLiteral("variables"))
+ else if (cmd == QLatin1String("variables"))
handleVariables(response, arguments);
- else if (cmd == QStringLiteral("expressions"))
+ else if (cmd == QLatin1String("expressions"))
handleExpressions(response, arguments);
- else if (cmd == QStringLiteral("stepin"))
+ else if (cmd == QLatin1String("stepin"))
handleContinue(response, StepIn);
- else if (cmd == QStringLiteral("stepout"))
+ else if (cmd == QLatin1String("stepout"))
handleContinue(response, StepOut);
- else if (cmd == QStringLiteral("stepover"))
+ else if (cmd == QLatin1String("stepover"))
handleContinue(response, StepOver);
- else if (cmd == QStringLiteral("continue"))
+ else if (cmd == QLatin1String("continue"))
handleContinue(response, NotStepping);
}
@@ -334,7 +331,7 @@ static void decodeContext(const QString &context, QV4::ExecutionContext **execut
void NativeDebugger::handleBacktrace(QJsonObject *response, const QJsonObject &arguments)
{
- int limit = arguments.value(QStringLiteral("limit")).toInt(0);
+ int limit = arguments.value(QLatin1String("limit")).toInt(0);
QJsonArray frameArray;
QV4::ExecutionContext *executionContext = m_engine->currentContext;
@@ -343,16 +340,16 @@ void NativeDebugger::handleBacktrace(QJsonObject *response, const QJsonObject &a
if (heapFunctionObject) {
QJsonObject frame;
- frame[QStringLiteral("language")] = QStringLiteral("js");
- frame[QStringLiteral("context")] = encodeContext(executionContext);
+ frame.insert(QStringLiteral("language"), QStringLiteral("js"));
+ frame.insert(QStringLiteral("context"), encodeContext(executionContext));
if (QV4::Function *function = heapFunctionObject->function) {
if (QV4::Heap::String *functionName = function->name())
- frame[QStringLiteral("function")] = functionName->toQString();
- frame[QStringLiteral("file")] = function->sourceFile();
+ frame.insert(QStringLiteral("function"), functionName->toQString());
+ frame.insert(QStringLiteral("file"), function->sourceFile());
}
int line = executionContext->d()->lineNumber;
- frame[QStringLiteral("line")] = (line < 0 ? -line : line);
+ frame.insert(QStringLiteral("line"), (line < 0 ? -line : line));
frameArray.push_back(frame);
}
@@ -463,7 +460,7 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a
{
TRACE_PROTOCOL("Build variables");
QV4::ExecutionContext *executionContext = 0;
- decodeContext(arguments.value(QStringLiteral("context")).toString(), &executionContext);
+ decodeContext(arguments.value(QLatin1String("context")).toString(), &executionContext);
if (!executionContext) {
setError(response, QStringLiteral("No execution context passed"));
return;
@@ -478,8 +475,8 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a
TRACE_PROTOCOL("Engine: " << engine);
Collector collector(engine);
- QJsonArray expanded = arguments.value(QStringLiteral("expanded")).toArray();
- foreach (const QJsonValue &ex, expanded)
+ const QJsonArray expanded = arguments.value(QLatin1String("expanded")).toArray();
+ for (const QJsonValue &ex : expanded)
collector.m_expanded.append(ex.toString());
TRACE_PROTOCOL("Expanded: " << collector.m_expanded);
@@ -515,7 +512,7 @@ void NativeDebugger::handleExpressions(QJsonObject *response, const QJsonObject
{
TRACE_PROTOCOL("Evaluate expressions");
QV4::ExecutionContext *executionContext = 0;
- decodeContext(arguments.value(QStringLiteral("context")).toString(), &executionContext);
+ decodeContext(arguments.value(QLatin1String("context")).toString(), &executionContext);
if (!executionContext) {
setError(response, QStringLiteral("No execution context passed"));
return;
@@ -530,36 +527,36 @@ void NativeDebugger::handleExpressions(QJsonObject *response, const QJsonObject
TRACE_PROTOCOL("Engines: " << engine << m_engine);
Collector collector(engine);
- QJsonArray expanded = arguments.value(QStringLiteral("expanded")).toArray();
- foreach (const QJsonValue &ex, expanded)
+ const QJsonArray expanded = arguments.value(QLatin1String("expanded")).toArray();
+ for (const QJsonValue &ex : expanded)
collector.m_expanded.append(ex.toString());
TRACE_PROTOCOL("Expanded: " << collector.m_expanded);
QJsonArray output;
QV4::Scope scope(engine);
- QJsonArray expressions = arguments.value(QStringLiteral("expressions")).toArray();
- foreach (const QJsonValue &expr, expressions) {
- QString expression = expr.toObject().value(QStringLiteral("expression")).toString();
- QString name = expr.toObject().value(QStringLiteral("name")).toString();
+ const QJsonArray expressions = arguments.value(QLatin1String("expressions")).toArray();
+ for (const QJsonValue &expr : expressions) {
+ QString expression = expr.toObject().value(QLatin1String("expression")).toString();
+ QString name = expr.toObject().value(QLatin1String("name")).toString();
TRACE_PROTOCOL("Evaluate expression: " << expression);
m_runningJob = true;
- QV4::ReturnedValue eval = evaluateExpression(scope, expression);
- QV4::ScopedValue result(scope, eval);
+ evaluateExpression(scope, expression);
+ QV4::ScopedValue result(scope, scope.result);
m_runningJob = false;
if (result->isUndefined()) {
QJsonObject dict;
- dict[QStringLiteral("name")] = name;
- dict[QStringLiteral("valueencoded")] = QStringLiteral("undefined");
+ dict.insert(QStringLiteral("name"), name);
+ dict.insert(QStringLiteral("valueencoded"), QStringLiteral("undefined"));
output.append(dict);
- } else if (result.ptr && result.ptr->_val) {
+ } else if (result.ptr && result.ptr->rawValue()) {
collector.collect(&output, QString(), name, *result);
} else {
QJsonObject dict;
- dict[QStringLiteral("name")] = name;
- dict[QStringLiteral("valueencoded")] = QStringLiteral("notaccessible");
+ dict.insert(QStringLiteral("name"), name);
+ dict.insert(QStringLiteral("valueencoded"), QStringLiteral("notaccessible"));
output.append(dict);
}
TRACE_PROTOCOL("EXCEPTION: " << engine->hasException);
@@ -751,7 +748,8 @@ void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
TRACE_PROTOCOL("Removing engine" << engine);
if (engine) {
QV4::ExecutionEngine *executionEngine = QV8Engine::getV4(engine->handle());
- foreach (NativeDebugger *debugger, m_debuggers) {
+ const auto debuggersCopy = m_debuggers;
+ for (NativeDebugger *debugger : debuggersCopy) {
if (debugger->engine() == executionEngine)
m_debuggers.removeAll(debugger);
}
@@ -762,9 +760,9 @@ void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
void QQmlNativeDebugServiceImpl::stateAboutToBeChanged(QQmlDebugService::State state)
{
if (state == Enabled) {
- foreach (NativeDebugger *debugger, m_debuggers) {
+ for (NativeDebugger *debugger : qAsConst(m_debuggers)) {
QV4::ExecutionEngine *engine = debugger->engine();
- if (!engine->debugger)
+ if (!engine->debugger())
engine->setDebugger(debugger);
}
}
@@ -776,17 +774,17 @@ void QQmlNativeDebugServiceImpl::messageReceived(const QByteArray &message)
TRACE_PROTOCOL("Native message received: " << message);
QJsonObject request = QJsonDocument::fromJson(message).object();
QJsonObject response;
- QJsonObject arguments = request.value(QStringLiteral("arguments")).toObject();
- QString cmd = request.value(QStringLiteral("command")).toString();
+ QJsonObject arguments = request.value(QLatin1String("arguments")).toObject();
+ QString cmd = request.value(QLatin1String("command")).toString();
- if (cmd == QStringLiteral("setbreakpoint")) {
+ if (cmd == QLatin1String("setbreakpoint")) {
m_breakHandler->handleSetBreakpoint(&response, arguments);
- } else if (cmd == QStringLiteral("removebreakpoint")) {
+ } else if (cmd == QLatin1String("removebreakpoint")) {
m_breakHandler->handleRemoveBreakpoint(&response, arguments);
- } else if (cmd == QStringLiteral("echo")) {
+ } else if (cmd == QLatin1String("echo")) {
response.insert(QStringLiteral("result"), arguments);
} else {
- foreach (NativeDebugger *debugger, m_debuggers)
+ for (NativeDebugger *debugger : qAsConst(m_debuggers))
if (debugger)
debugger->handleCommand(&response, cmd, arguments);
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
index 392080dd51..1214212727 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
@@ -69,7 +69,7 @@ public:
QQmlWatcher *parent = 0);
public slots:
- void notifyValueChanged();
+ void notifyValueChanged(); // Needs to be a slot because of QQmlPropertyPrivate::connect()
private:
friend class QQmlWatcher;
@@ -88,7 +88,8 @@ QQmlWatchProxy::QQmlWatchProxy(int id,
QQmlWatcher *parent)
: QObject(parent), m_id(id), m_watch(parent), m_object(0), m_debugId(debugId), m_expr(exp)
{
- QObject::connect(m_expr, SIGNAL(valueChanged()), this, SLOT(notifyValueChanged()));
+ QObject::connect(m_expr, &QQmlExpression::valueChanged,
+ this, &QQmlWatchProxy::notifyValueChanged);
}
QQmlWatchProxy::QQmlWatchProxy(int id,
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
index 53f2eab5ff..44810dd4cb 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
@@ -79,6 +79,8 @@ QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine)
static int pauseReasonId = qRegisterMetaType<QV4Debugger::PauseReason>();
Q_UNUSED(debuggerId);
Q_UNUSED(pauseReasonId);
+ connect(this, &QV4Debugger::scheduleJob,
+ this, &QV4Debugger::runJobUnpaused, Qt::QueuedConnection);
}
QV4::ExecutionEngine *QV4Debugger::engine() const
@@ -320,7 +322,7 @@ void QV4Debugger::runInEngine_havingLock(QV4DebugJob *job)
if (state() == Paused)
m_runningCondition.wakeAll();
else
- QMetaObject::invokeMethod(this, "runJobUnpaused", Qt::QueuedConnection);
+ emit scheduleJob();
m_jobIsRunning.wait(&m_lock);
m_runningJob = 0;
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h
index 3a5b6080cb..cd412e573d 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h
@@ -140,15 +140,14 @@ public:
signals:
void debuggerPaused(QV4Debugger *self, QV4Debugger::PauseReason reason);
-
-private slots:
- void runJobUnpaused();
+ void scheduleJob();
private:
// requires lock to be held
void pauseAndWait(PauseReason reason);
bool reallyHitTheBreakPoint(const QString &filename, int linenr);
void runInEngine_havingLock(QV4DebugJob *job);
+ void runJobUnpaused();
QV4::ExecutionEngine *m_engine;
QV4::PersistentValue m_currentContext;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
index 756b6b28be..773bc937f5 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
@@ -52,7 +52,7 @@ QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService)
QV4Debugger *QV4DebuggerAgent::pausedDebugger() const
{
- foreach (QV4Debugger *debugger, m_debuggers) {
+ for (QV4Debugger *debugger : m_debuggers) {
if (debugger->state() == QV4Debugger::Paused)
return debugger;
}
@@ -147,13 +147,13 @@ void QV4DebuggerAgent::pause(QV4Debugger *debugger) const
void QV4DebuggerAgent::pauseAll() const
{
- foreach (QV4Debugger *debugger, m_debuggers)
+ for (QV4Debugger *debugger : m_debuggers)
pause(debugger);
}
void QV4DebuggerAgent::resumeAll() const
{
- foreach (QV4Debugger *debugger, m_debuggers)
+ for (QV4Debugger *debugger : m_debuggers)
if (debugger->state() == QV4Debugger::Paused)
debugger->resume(QV4Debugger::FullThrottle);
}
@@ -161,7 +161,7 @@ void QV4DebuggerAgent::resumeAll() const
int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
{
if (enabled)
- foreach (QV4Debugger *debugger, m_debuggers)
+ for (QV4Debugger *debugger : qAsConst(m_debuggers))
debugger->addBreakPoint(fileName, lineNumber, condition);
int id = m_breakPoints.size();
@@ -178,7 +178,7 @@ void QV4DebuggerAgent::removeBreakPoint(int id)
m_breakPoints.remove(id);
if (breakPoint.enabled)
- foreach (QV4Debugger *debugger, m_debuggers)
+ for (QV4Debugger *debugger : qAsConst(m_debuggers))
debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
}
@@ -195,7 +195,7 @@ void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff)
return;
breakPoint.enabled = onoff;
- foreach (QV4Debugger *debugger, m_debuggers) {
+ for (QV4Debugger *debugger : qAsConst(m_debuggers)) {
if (onoff)
debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
else
@@ -218,14 +218,14 @@ void QV4DebuggerAgent::setBreakOnThrow(bool onoff)
{
if (onoff != m_breakOnThrow) {
m_breakOnThrow = onoff;
- foreach (QV4Debugger *debugger, m_debuggers)
+ for (QV4Debugger *debugger : qAsConst(m_debuggers))
debugger->setBreakOnThrow(onoff);
}
}
void QV4DebuggerAgent::clearAllPauseRequests()
{
- foreach (QV4Debugger *debugger, m_debuggers)
+ for (QV4Debugger *debugger : qAsConst(m_debuggers))
debugger->clearPauseRequest();
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
index 1c7eb50ac7..39ac4d4dcb 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
@@ -72,7 +72,6 @@ public:
void setBreakOnThrow(bool onoff);
void clearAllPauseRequests();
-public slots:
void debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason);
void handleDebuggerDeleted(QObject *debugger);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
index a2d2fff72b..4e4048f6ad 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
@@ -205,7 +205,7 @@ void ValueLookupJob::run()
QQmlContextData::get(engine->qmlEngine()->rootContext()),
scopeObject.data()));
}
- foreach (const QJsonValue &handle, handles) {
+ for (const QJsonValue &handle : handles) {
QV4DataCollector::Ref ref = handle.toInt();
if (!collector->isValidRef(ref)) {
exception = QString::fromLatin1("Invalid Ref: %1").arg(ref);
@@ -258,7 +258,7 @@ GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine)
void GatherSourcesJob::run()
{
- foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) {
+ for (QV4::CompiledData::CompilationUnit *unit : qAsConst(engine->compilationUnits)) {
QString fileName = unit->fileName();
if (!fileName.isEmpty())
sources.append(fileName);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
index 721f42b7c2..aff2ea1b6c 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
@@ -65,7 +65,7 @@ class JavaScriptJob : public QV4DebugJob
public:
JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script);
- void run();
+ void run() override;
bool hasExeption() const;
protected:
@@ -90,7 +90,7 @@ class BacktraceJob: public CollectJob
int toFrame;
public:
BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame);
- void run();
+ void run() override;
};
class FrameJob: public CollectJob
@@ -100,7 +100,7 @@ class FrameJob: public CollectJob
public:
FrameJob(QV4DataCollector *collector, int frameNr);
- void run();
+ void run() override;
bool wasSuccessful() const;
};
@@ -123,7 +123,7 @@ class ValueLookupJob: public CollectJob
public:
ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector);
- void run();
+ void run() override;
const QString &exceptionMessage() const;
};
@@ -137,7 +137,7 @@ class ExpressionEvalJob: public JavaScriptJob
public:
ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression,
QV4DataCollector *collector);
- virtual void handleResult(QV4::ScopedValue &value);
+ void handleResult(QV4::ScopedValue &value) override;
const QString &exceptionMessage() const;
const QJsonObject &returnValue() const;
const QJsonArray &refs() const;
@@ -150,7 +150,7 @@ class GatherSourcesJob: public QV4DebugJob
public:
GatherSourcesJob(QV4::ExecutionEngine *engine);
- void run();
+ void run() override;
const QStringList &result() const;
};
@@ -161,7 +161,7 @@ class EvalJob: public JavaScriptJob
public:
EvalJob(QV4::ExecutionEngine *engine, const QString &script);
- virtual void handleResult(QV4::ScopedValue &result);
+ void handleResult(QV4::ScopedValue &result) override;
bool resultAsBoolean() const;
};
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index 5ee9e5e9e9..de97b5437b 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
@@ -90,7 +90,7 @@ public:
TRACE_PROTOCOL(qDebug() << "handling command" << command() << "...");
req = request;
- seq = req.value(QStringLiteral("seq"));
+ seq = req.value(QLatin1String("seq"));
debugService = s;
handleRequest();
@@ -128,7 +128,7 @@ protected:
void createErrorResponse(const QString &msg)
{
- QJsonValue command = req.value(QStringLiteral("command"));
+ QJsonValue command = req.value(QLatin1String("command"));
response.insert(QStringLiteral("command"), command);
addRequestSequence();
addSuccess(false);
@@ -152,11 +152,11 @@ class UnknownV8CommandHandler: public V8CommandHandler
public:
UnknownV8CommandHandler(): V8CommandHandler(QString()) {}
- virtual void handleRequest()
+ void handleRequest() override
{
- QString msg = QStringLiteral("unimplemented command \"");
- msg += req.value(QStringLiteral("command")).toString();
- msg += QLatin1Char('"');
+ QString msg = QLatin1String("unimplemented command \"")
+ + req.value(QLatin1String("command")).toString()
+ + QLatin1Char('"');
createErrorResponse(msg);
}
};
@@ -167,7 +167,7 @@ class V8VersionRequest: public V8CommandHandler
public:
V8VersionRequest(): V8CommandHandler(QStringLiteral("version")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
addCommand();
addRequestSequence();
@@ -186,26 +186,26 @@ class V8SetBreakPointRequest: public V8CommandHandler
public:
V8SetBreakPointRequest(): V8CommandHandler(QStringLiteral("setbreakpoint")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
// decypher the payload:
- QJsonObject args = req.value(QStringLiteral("arguments")).toObject();
+ QJsonObject args = req.value(QLatin1String("arguments")).toObject();
if (args.isEmpty())
return;
- QString type = args.value(QStringLiteral("type")).toString();
- if (type != QStringLiteral("scriptRegExp")) {
+ QString type = args.value(QLatin1String("type")).toString();
+ if (type != QLatin1String("scriptRegExp")) {
createErrorResponse(QStringLiteral("breakpoint type \"%1\" is not implemented").arg(type));
return;
}
- QString fileName = args.value(QStringLiteral("target")).toString();
+ QString fileName = args.value(QLatin1String("target")).toString();
if (fileName.isEmpty()) {
createErrorResponse(QStringLiteral("breakpoint has no file name"));
return;
}
- int line = args.value(QStringLiteral("line")).toInt(-1);
+ int line = args.value(QLatin1String("line")).toInt(-1);
if (line < 0) {
createErrorResponse(QStringLiteral("breakpoint has an invalid line number"));
return;
@@ -237,14 +237,14 @@ class V8ClearBreakPointRequest: public V8CommandHandler
public:
V8ClearBreakPointRequest(): V8CommandHandler(QStringLiteral("clearbreakpoint")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
// decypher the payload:
- QJsonObject args = req.value(QStringLiteral("arguments")).toObject();
+ QJsonObject args = req.value(QLatin1String("arguments")).toObject();
if (args.isEmpty())
return;
- int id = args.value(QStringLiteral("breakpoint")).toInt(-1);
+ int id = args.value(QLatin1String("breakpoint")).toInt(-1);
if (id < 0) {
createErrorResponse(QStringLiteral("breakpoint has an invalid number"));
return;
@@ -270,13 +270,13 @@ class V8BacktraceRequest: public V8CommandHandler
public:
V8BacktraceRequest(): V8CommandHandler(QStringLiteral("backtrace")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
// decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- int fromFrame = arguments.value(QStringLiteral("fromFrame")).toInt(0);
- int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10);
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
+ int fromFrame = arguments.value(QLatin1String("fromFrame")).toInt(0);
+ int toFrame = arguments.value(QLatin1String("toFrame")).toInt(fromFrame + 10);
// no idea what the bottom property is for, so we'll ignore it.
QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
@@ -303,11 +303,11 @@ class V8FrameRequest: public V8CommandHandler
public:
V8FrameRequest(): V8CommandHandler(QStringLiteral("frame")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
// decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- const int frameNr = arguments.value(QStringLiteral("number")).toInt(
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
+ const int frameNr = arguments.value(QLatin1String("number")).toInt(
debugService->selectedFrame());
QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
@@ -345,13 +345,13 @@ class V8ScopeRequest: public V8CommandHandler
public:
V8ScopeRequest(): V8CommandHandler(QStringLiteral("scope")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
// decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- const int frameNr = arguments.value(QStringLiteral("frameNumber")).toInt(
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
+ const int frameNr = arguments.value(QLatin1String("frameNumber")).toInt(
debugService->selectedFrame());
- const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0);
+ const int scopeNr = arguments.value(QLatin1String("number")).toInt(0);
QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
if (!debugger) {
@@ -390,11 +390,11 @@ class V8LookupRequest: public V8CommandHandler
public:
V8LookupRequest(): V8CommandHandler(QStringLiteral("lookup")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
// decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray();
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
+ QJsonArray handles = arguments.value(QLatin1String("handles")).toArray();
QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
if (!debugger) {
@@ -430,10 +430,10 @@ class V8ContinueRequest: public V8CommandHandler
public:
V8ContinueRequest(): V8CommandHandler(QStringLiteral("continue")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
// decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
if (!debugger) {
@@ -445,17 +445,17 @@ public:
if (arguments.empty()) {
debugger->resume(QV4Debugger::FullThrottle);
} else {
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QString stepAction = arguments.value(QStringLiteral("stepaction")).toString();
- const int stepcount = arguments.value(QStringLiteral("stepcount")).toInt(1);
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
+ QString stepAction = arguments.value(QLatin1String("stepaction")).toString();
+ const int stepcount = arguments.value(QLatin1String("stepcount")).toInt(1);
if (stepcount != 1)
qWarning() << "Step count other than 1 is not supported.";
- if (stepAction == QStringLiteral("in")) {
+ if (stepAction == QLatin1String("in")) {
debugger->resume(QV4Debugger::StepIn);
- } else if (stepAction == QStringLiteral("out")) {
+ } else if (stepAction == QLatin1String("out")) {
debugger->resume(QV4Debugger::StepOut);
- } else if (stepAction == QStringLiteral("next")) {
+ } else if (stepAction == QLatin1String("next")) {
debugger->resume(QV4Debugger::StepOver);
} else {
createErrorResponse(QStringLiteral("continue command has invalid stepaction"));
@@ -476,7 +476,7 @@ class V8DisconnectRequest: public V8CommandHandler
public:
V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
debugService->debuggerAgent.removeAllBreakPoints();
debugService->debuggerAgent.resumeAll();
@@ -494,18 +494,18 @@ class V8SetExceptionBreakRequest: public V8CommandHandler
public:
V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
bool wasEnabled = debugService->debuggerAgent.breakOnThrow();
//decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QString type = arguments.value(QStringLiteral("type")).toString();
- bool enabled = arguments.value(QStringLiteral("number")).toBool(!wasEnabled);
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
+ QString type = arguments.value(QLatin1String("type")).toString();
+ bool enabled = arguments.value(QLatin1String("number")).toBool(!wasEnabled);
- if (type == QStringLiteral("all")) {
+ if (type == QLatin1String("all")) {
// that's fine
- } else if (type == QStringLiteral("uncaught")) {
+ } else if (type == QLatin1String("uncaught")) {
createErrorResponse(QStringLiteral("breaking only on uncaught exceptions is not supported yet"));
return;
} else {
@@ -534,11 +534,11 @@ class V8ScriptsRequest: public V8CommandHandler
public:
V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
//decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- int types = arguments.value(QStringLiteral("types")).toInt(-1);
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
+ int types = arguments.value(QLatin1String("types")).toInt(-1);
if (types < 0 || types > 7) {
createErrorResponse(QStringLiteral("invalid types value in scripts command"));
return;
@@ -558,7 +558,7 @@ public:
debugger->runInEngine(&job);
QJsonArray body;
- foreach (const QString &source, job.result()) {
+ for (const QString &source : job.result()) {
QJsonObject src;
src[QLatin1String("name")] = source;
src[QLatin1String("scriptType")] = 4;
@@ -606,10 +606,10 @@ class V8EvaluateRequest: public V8CommandHandler
public:
V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {}
- virtual void handleRequest()
+ void handleRequest() override
{
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QString expression = arguments.value(QStringLiteral("expression")).toString();
+ QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
+ QString expression = arguments.value(QLatin1String("expression")).toString();
int frame = -1;
QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
@@ -624,7 +624,7 @@ public:
}
debugger = debuggers.first();
} else {
- frame = arguments.value(QStringLiteral("frame")).toInt(0);
+ frame = arguments.value(QLatin1String("frame")).toInt(0);
}
ExpressionEvalJob job(debugger->engine(), frame, expression, debugger->collector());
@@ -706,7 +706,7 @@ void QV4DebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
if (engine){
const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
if (ee) {
- QV4Debugger *debugger = qobject_cast<QV4Debugger *>(ee->debugger);
+ QV4Debugger *debugger = qobject_cast<QV4Debugger *>(ee->debugger());
if (debugger)
debuggerAgent.removeDebugger(debugger);
}
@@ -718,9 +718,10 @@ void QV4DebugServiceImpl::stateAboutToBeChanged(State state)
{
QMutexLocker lock(&m_configMutex);
if (state == Enabled) {
- foreach (QV4Debugger *debugger, debuggerAgent.debuggers()) {
+ const auto debuggers = debuggerAgent.debuggers();
+ for (QV4Debugger *debugger : debuggers) {
QV4::ExecutionEngine *ee = debugger->engine();
- if (!ee->debugger)
+ if (!ee->debugger())
ee->setDebugger(debugger);
}
}
@@ -737,7 +738,7 @@ void QV4DebugServiceImpl::signalEmitted(const QString &signal)
//Normalize to Lower case.
QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower();
- foreach (const QString &signal, breakOnSignals) {
+ for (const QString &signal : qAsConst(breakOnSignals)) {
if (signal == signalName) {
// TODO: pause debugger
break;
@@ -802,9 +803,9 @@ void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload)
QJsonDocument request = QJsonDocument::fromJson(payload);
QJsonObject o = request.object();
- QJsonValue type = o.value(QStringLiteral("type"));
- if (type.toString() == QStringLiteral("request")) {
- QJsonValue command = o.value(QStringLiteral("command"));
+ QJsonValue type = o.value(QLatin1String("type"));
+ if (type.toString() == QLatin1String("request")) {
+ QJsonValue command = o.value(QLatin1String("command"));
V8CommandHandler *h = v8CommandHandler(command.toString());
if (h)
h->handle(o, this);
diff --git a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
index 2150b68f32..eb254ca1e0 100644
--- a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
+++ b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
@@ -92,7 +92,7 @@ void GlobalInspector::setSelectedItems(const QList<QQuickItem *> &items)
QList<QObject*> objectList;
objectList.reserve(items.count());
- foreach (QQuickItem *item, items)
+ for (QQuickItem *item : items)
objectList << item;
sendCurrentObjects(objectList);
@@ -113,7 +113,7 @@ void GlobalInspector::sendCurrentObjects(const QList<QObject*> &objects)
QList<int> debugIds;
debugIds.reserve(objects.count());
- foreach (QObject *object, objects)
+ for (QObject *object : objects)
debugIds << QQmlDebugService::idForObject(object);
ds << debugIds;
@@ -148,10 +148,6 @@ public:
m_component.setData(qml, filename);
}
-signals:
- void result(int requestId, bool success);
-
-public slots:
void tryCreateObject(QQmlComponent::Status status)
{
switch (status) {
@@ -171,7 +167,7 @@ public slots:
else
emit result(m_requestId, false);
}
- delete this;
+ deleteLater(); // The component might send more signals
return;
}
default:
@@ -179,6 +175,9 @@ public slots:
}
}
+signals:
+ void result(int requestId, bool success);
+
private:
QQmlComponent m_component;
int m_requestId;
@@ -195,7 +194,7 @@ bool GlobalInspector::createQmlObject(int requestId, const QString &qml, QObject
return false;
QString imports;
- foreach (const QString &s, importList)
+ for (const QString &s : importList)
imports += s + QLatin1Char('\n');
ObjectCreator *objectCreator = new ObjectCreator(requestId, parentContext->engine(), parent);
@@ -224,7 +223,7 @@ void GlobalInspector::removeWindow(QQuickWindow *window)
void GlobalInspector::setParentWindow(QQuickWindow *window, QWindow *parentWindow)
{
- foreach (QmlJSDebugger::QQuickWindowInspector *inspector, m_windowInspectors) {
+ for (QmlJSDebugger::QQuickWindowInspector *inspector : qAsConst(m_windowInspectors)) {
if (inspector->quickWindow() == window)
inspector->setParentWindow(parentWindow);
}
@@ -235,7 +234,8 @@ bool GlobalInspector::syncSelectedItems(const QList<QQuickItem *> &items)
bool selectionChanged = false;
// Disconnect and remove items that are no longer selected
- foreach (const QPointer<QQuickItem> &item, m_selectedItems) {
+ const auto selectedItemsCopy = m_selectedItems;
+ for (const QPointer<QQuickItem> &item : selectedItemsCopy) {
if (!item) // Don't see how this can happen due to handling of destroyed()
continue;
if (items.contains(item))
@@ -248,14 +248,14 @@ bool GlobalInspector::syncSelectedItems(const QList<QQuickItem *> &items)
}
// Connect and add newly selected items
- foreach (QQuickItem *item, items) {
+ for (QQuickItem *item : items) {
if (m_selectedItems.contains(item))
continue;
selectionChanged = true;
connect(item, &QObject::destroyed, this, &GlobalInspector::removeFromSelectedItems);
m_selectedItems.append(item);
- foreach (QQuickWindowInspector *inspector, m_windowInspectors) {
+ for (QQuickWindowInspector *inspector : qAsConst(m_windowInspectors)) {
if (inspector->isEnabled() && inspector->quickWindow() == item->window()) {
m_highlightItems.insert(item, new SelectionHighlight(titleForItem(item), item,
inspector->overlay()));
@@ -315,12 +315,12 @@ void GlobalInspector::processMessage(const QByteArray &message)
ds >> requestId >> command;
if (command == ENABLE) {
- foreach (QQuickWindowInspector *inspector, m_windowInspectors)
+ for (QQuickWindowInspector *inspector : qAsConst(m_windowInspectors))
inspector->setEnabled(true);
success = !m_windowInspectors.isEmpty();
} else if (command == DISABLE) {
setSelectedItems(QList<QQuickItem*>());
- foreach (QQuickWindowInspector *inspector, m_windowInspectors)
+ for (QQuickWindowInspector *inspector : qAsConst(m_windowInspectors))
inspector->setEnabled(false);
success = !m_windowInspectors.isEmpty();
} else if (command == SELECT) {
@@ -328,7 +328,7 @@ void GlobalInspector::processMessage(const QByteArray &message)
ds >> debugIds;
QList<QQuickItem *> selectedObjects;
- foreach (int debugId, debugIds) {
+ for (int debugId : qAsConst(debugIds)) {
if (QQuickItem *obj =
qobject_cast<QQuickItem *>(QQmlDebugService::objectForId(debugId)))
selectedObjects << obj;
@@ -342,7 +342,7 @@ void GlobalInspector::processMessage(const QByteArray &message)
} else if (command == SHOW_APP_ON_TOP) {
bool showOnTop;
ds >> showOnTop;
- foreach (QmlJSDebugger::QQuickWindowInspector *inspector, m_windowInspectors)
+ for (QmlJSDebugger::QQuickWindowInspector *inspector : qAsConst(m_windowInspectors))
inspector->setShowAppOnTop(showOnTop);
success = !m_windowInspectors.isEmpty();
} else if (command == CREATE_OBJECT) {
diff --git a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.h b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.h
index 7bbe6d6aa2..338eee14c3 100644
--- a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.h
+++ b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.h
@@ -72,10 +72,8 @@ public:
signals:
void messageToClient(const QString &name, const QByteArray &data);
-private slots:
- void sendResult(int requestId, bool success);
-
private:
+ void sendResult(int requestId, bool success);
void sendCurrentObjects(const QList<QObject *> &objects);
void removeFromSelectedItems(QObject *object);
QString titleForItem(QQuickItem *item) const;
diff --git a/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp b/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp
index 26eb0f8ed8..88a6ea6b6d 100644
--- a/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp
+++ b/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp
@@ -72,24 +72,22 @@ void Highlight::setItem(QQuickItem *item)
m_item->disconnect(this);
if (item) {
- connect(item, SIGNAL(xChanged()), SLOT(adjust()));
- connect(item, SIGNAL(yChanged()), SLOT(adjust()));
- connect(item, SIGNAL(widthChanged()), SLOT(adjust()));
- connect(item, SIGNAL(heightChanged()), SLOT(adjust()));
- connect(item, SIGNAL(rotationChanged()), SLOT(adjust()));
- connect(item, SIGNAL(transformOriginChanged(TransformOrigin)),
- SLOT(adjust()));
+ connect(item, &QQuickItem::xChanged, this, &Highlight::adjust);
+ connect(item, &QQuickItem::yChanged, this, &Highlight::adjust);
+ connect(item, &QQuickItem::widthChanged, this, &Highlight::adjust);
+ connect(item, &QQuickItem::heightChanged, this, &Highlight::adjust);
+ connect(item, &QQuickItem::rotationChanged, this, &Highlight::adjust);
+ connect(item, &QQuickItem::transformOriginChanged, this, &Highlight::adjust);
}
QQuickWindow *view = item->window();
QQuickItem * contentItem = view->contentItem();
if (contentItem) {
- connect(contentItem, SIGNAL(xChanged()), SLOT(adjust()));
- connect(contentItem, SIGNAL(yChanged()), SLOT(adjust()));
- connect(contentItem, SIGNAL(widthChanged()), SLOT(adjust()));
- connect(contentItem, SIGNAL(heightChanged()), SLOT(adjust()));
- connect(contentItem, SIGNAL(rotationChanged()), SLOT(adjust()));
- connect(contentItem, SIGNAL(transformOriginChanged(TransformOrigin)),
- SLOT(adjust()));
+ connect(contentItem, &QQuickItem::xChanged, this, &Highlight::adjust);
+ connect(contentItem, &QQuickItem::yChanged, this, &Highlight::adjust);
+ connect(contentItem, &QQuickItem::widthChanged, this, &Highlight::adjust);
+ connect(contentItem, &QQuickItem::heightChanged, this, &Highlight::adjust);
+ connect(contentItem, &QQuickItem::rotationChanged, this, &Highlight::adjust);
+ connect(contentItem, &QQuickItem::transformOriginChanged, this, &Highlight::adjust);
}
m_item = item;
setContentsSize(view->size());
diff --git a/src/plugins/qmltooling/qmldbg_inspector/highlight.h b/src/plugins/qmltooling/qmldbg_inspector/highlight.h
index 4a85cb4d50..2bf4fc1ad5 100644
--- a/src/plugins/qmltooling/qmldbg_inspector/highlight.h
+++ b/src/plugins/qmltooling/qmldbg_inspector/highlight.h
@@ -65,8 +65,6 @@ protected:
private:
void initRenderDetails();
-
-private slots:
void adjust();
private:
@@ -86,13 +84,12 @@ public:
void paint(QPainter *painter);
void showName(const QPointF &displayPoint);
-private slots:
- void disableNameDisplay();
-
private:
QPointF m_displayPoint;
QString m_name;
bool m_nameDisplayActive;
+
+ void disableNameDisplay();
};
/**
diff --git a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp
index 48a3f656b0..ab1aeebf64 100644
--- a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp
@@ -55,23 +55,27 @@ public:
void setParentWindow(QQuickWindow *window, QWindow *parent) Q_DECL_OVERRIDE;
void removeWindow(QQuickWindow *window) Q_DECL_OVERRIDE;
+signals:
+ void scheduleMessage(const QByteArray &message);
+
protected:
virtual void messageReceived(const QByteArray &) Q_DECL_OVERRIDE;
-private slots:
- void messageFromClient(const QByteArray &message);
-
private:
friend class QQmlInspectorServiceFactory;
QmlJSDebugger::GlobalInspector *checkInspector();
QmlJSDebugger::GlobalInspector *m_globalInspector;
QHash<QQuickWindow *, QWindow *> m_waitingWindows;
+
+ void messageFromClient(const QByteArray &message);
};
QQmlInspectorServiceImpl::QQmlInspectorServiceImpl(QObject *parent):
QQmlInspectorService(1, parent), m_globalInspector(0)
{
+ connect(this, &QQmlInspectorServiceImpl::scheduleMessage,
+ this, &QQmlInspectorServiceImpl::messageFromClient, Qt::QueuedConnection);
}
QmlJSDebugger::GlobalInspector *QQmlInspectorServiceImpl::checkInspector()
@@ -122,8 +126,8 @@ void QQmlInspectorServiceImpl::setParentWindow(QQuickWindow *window, QWindow *pa
void QQmlInspectorServiceImpl::messageReceived(const QByteArray &message)
{
- QMetaObject::invokeMethod(this, "messageFromClient", Qt::QueuedConnection,
- Q_ARG(QByteArray, message));
+ // Move the message to the right thread via queued signal
+ emit scheduleMessage(message);
}
void QQmlInspectorServiceImpl::messageFromClient(const QByteArray &message)
diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
index 01c24f2395..64b26bdd0d 100644
--- a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
+++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
@@ -65,10 +65,8 @@ public:
void waitForConnection();
void flush();
-private slots:
- void connectionEstablished();
-
private:
+ void connectionEstablished();
bool connectToServer();
bool m_block;
@@ -135,7 +133,8 @@ bool QLocalClientConnection::connectToServer()
{
m_socket = new QLocalSocket;
m_socket->setParent(this);
- QObject::connect(m_socket, SIGNAL(connected()), this, SLOT(connectionEstablished()));
+ QObject::connect(m_socket, &QLocalSocket::connected,
+ this, &QLocalClientConnection::connectionEstablished);
m_socket->connectToServer(m_filename);
qDebug("QML Debugger: Connecting to socket %s...", m_filename.toLatin1().constData());
return true;
diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp
index 3145601612..9eeb285951 100644
--- a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp
+++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp
@@ -205,7 +205,7 @@ QQmlNativeDebugConnector::QQmlNativeDebugConnector()
QQmlNativeDebugConnector::~QQmlNativeDebugConnector()
{
- foreach (QQmlDebugService *service, m_services) {
+ for (QQmlDebugService *service : qAsConst(m_services)) {
service->stateAboutToBeChanged(QQmlDebugService::NotConnected);
service->setState(QQmlDebugService::NotConnected);
service->stateChanged(QQmlDebugService::NotConnected);
@@ -232,12 +232,12 @@ void QQmlNativeDebugConnector::addEngine(QJSEngine *engine)
Q_ASSERT(!m_engines.contains(engine));
TRACE_PROTOCOL("Add engine to connector:" << engine);
- foreach (QQmlDebugService *service, m_services)
+ for (QQmlDebugService *service : qAsConst(m_services))
service->engineAboutToBeAdded(engine);
announceObjectAvailability(QLatin1String("qmlengine"), engine, true);
- foreach (QQmlDebugService *service, m_services)
+ for (QQmlDebugService *service : qAsConst(m_services))
service->engineAdded(engine);
m_engines.append(engine);
@@ -248,12 +248,12 @@ void QQmlNativeDebugConnector::removeEngine(QJSEngine *engine)
Q_ASSERT(m_engines.contains(engine));
TRACE_PROTOCOL("Remove engine from connector:" << engine);
- foreach (QQmlDebugService *service, m_services)
+ for (QQmlDebugService *service : qAsConst(m_services))
service->engineAboutToBeRemoved(engine);
announceObjectAvailability(QLatin1String("qmlengine"), engine, false);
- foreach (QQmlDebugService *service, m_services)
+ for (QQmlDebugService *service : qAsConst(m_services))
service->engineRemoved(engine);
m_engines.removeOne(engine);
diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h
index 03b5b5eb1e..1184925e53 100644
--- a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h
+++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h
@@ -63,11 +63,9 @@ public:
bool open(const QVariantHash &configuration) Q_DECL_OVERRIDE;
static void setDataStreamVersion(int version);
-private slots:
+private:
void sendMessage(const QString &name, const QByteArray &message);
void sendMessages(const QString &name, const QList<QByteArray> &messages);
-
-private:
void announceObjectAvailability(const QString &objectType, QObject *object, bool available);
QVector<QQmlDebugService *> m_services;
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp
index 6b653d5a54..0ed13d5105 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp
@@ -122,10 +122,10 @@ void QQmlEngineControlServiceImpl::stateChanged(State)
{
// We flush everything for any kind of state change, to avoid complicated timing issues.
QMutexLocker lock(&dataMutex);
- foreach (QJSEngine *engine, startingEngines)
+ for (QJSEngine *engine : qAsConst(startingEngines))
emit attachedToEngine(engine);
startingEngines.clear();
- foreach (QJSEngine *engine, stoppingEngines)
+ for (QJSEngine *engine : qAsConst(stoppingEngines))
emit detachedFromEngine(engine);
stoppingEngines.clear();
}
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
index f161f988de..a4320098c0 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
@@ -48,20 +48,21 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
next(0)
{
setService(service);
- engine->enableProfiler();
- connect(this, SIGNAL(profilingEnabled(quint64)), engine->profiler, SLOT(startProfiling(quint64)));
- connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)),
- engine->profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection);
- connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling()));
- connect(this, SIGNAL(profilingDisabledWhileWaiting()),
- engine->profiler, SLOT(stopProfiling()), Qt::DirectConnection);
- connect(this, SIGNAL(dataRequested(bool)), engine->profiler, SLOT(reportData(bool)));
- connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
- engine->profiler, SLOT(setTimer(QElapsedTimer)));
- connect(engine->profiler,
- SIGNAL(dataReady(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash)),
- this,
- SLOT(receiveData(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash)));
+ engine->profiler = new QQmlProfiler;
+ connect(this, &QQmlProfilerAdapter::profilingEnabled,
+ engine->profiler, &QQmlProfiler::startProfiling);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting,
+ engine->profiler, &QQmlProfiler::startProfiling, Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingDisabled,
+ engine->profiler, &QQmlProfiler::stopProfiling);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting,
+ engine->profiler, &QQmlProfiler::stopProfiling, Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::dataRequested,
+ engine->profiler, &QQmlProfiler::reportData);
+ connect(this, &QQmlAbstractProfilerAdapter::referenceTimeKnown,
+ engine->profiler, &QQmlProfiler::setTimer);
+ connect(engine->profiler, &QQmlProfiler::dataReady,
+ this, &QQmlProfilerAdapter::receiveData);
}
// convert to QByteArrays that can be sent to the debug client
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
index 96cdcd6d38..1fee5c389f 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
@@ -63,7 +63,6 @@ public:
qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations) Q_DECL_OVERRIDE;
-public slots:
void receiveData(const QVector<QQmlProfilerData> &new_data,
const QQmlProfiler::LocationHash &locations);
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
index a587188630..c1f6f93ef1 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
@@ -51,6 +51,8 @@
#include <QtCore/qthread.h>
#include <QtCore/qcoreapplication.h>
+#include <algorithm>
+
QT_BEGIN_NAMESPACE
Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter)
@@ -92,16 +94,18 @@ void QQmlProfilerServiceImpl::dataReady(QQmlAbstractProfilerAdapter *profiler)
m_startTimes.insert(0, profiler);
if (dataComplete) {
QList<QJSEngine *> enginesToRelease;
- foreach (QJSEngine *engine, m_stoppingEngines) {
- foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers.values(engine)) {
- if (m_startTimes.values().contains(engineProfiler)) {
+ for (QJSEngine *engine : qAsConst(m_stoppingEngines)) {
+ const auto range = qAsConst(m_engineProfilers).equal_range(engine);
+ const auto startTimesEnd = m_startTimes.cend();
+ for (auto it = range.first; it != range.second; ++it) {
+ if (std::find(m_startTimes.cbegin(), startTimesEnd, *it) != startTimesEnd) {
enginesToRelease.append(engine);
break;
}
}
}
sendMessages();
- foreach (QJSEngine *engine, enginesToRelease) {
+ for (QJSEngine *engine : qAsConst(enginesToRelease)) {
m_stoppingEngines.removeOne(engine);
emit detachedFromEngine(engine);
}
@@ -130,8 +134,9 @@ void QQmlProfilerServiceImpl::engineAdded(QJSEngine *engine)
"QML profilers have to be added from the engine thread");
QMutexLocker lock(&m_configMutex);
- foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine))
- profiler->stopWaiting();
+ const auto range = qAsConst(m_engineProfilers).equal_range(engine);
+ for (auto it = range.first; it != range.second; ++it)
+ (*it)->stopWaiting();
}
void QQmlProfilerServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
@@ -141,7 +146,9 @@ void QQmlProfilerServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
QMutexLocker lock(&m_configMutex);
bool isRunning = false;
- foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) {
+ const auto range = qAsConst(m_engineProfilers).equal_range(engine);
+ for (auto it = range.first; it != range.second; ++it) {
+ QQmlAbstractProfilerAdapter *profiler = *it;
if (profiler->isRunning())
isRunning = true;
profiler->startWaiting();
@@ -160,7 +167,9 @@ void QQmlProfilerServiceImpl::engineRemoved(QJSEngine *engine)
"QML profilers have to be removed from the engine thread");
QMutexLocker lock(&m_configMutex);
- foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) {
+ const auto range = qAsConst(m_engineProfilers).equal_range(engine);
+ for (auto it = range.first; it != range.second; ++it) {
+ QQmlAbstractProfilerAdapter *profiler = *it;
removeProfilerFromStartTimes(profiler);
delete profiler;
}
@@ -183,7 +192,7 @@ void QQmlProfilerServiceImpl::addGlobalProfiler(QQmlAbstractProfilerAdapter *pro
// Global profilers are started whenever any engine profiler is started and stopped when
// all engine profilers are stopped.
quint64 features = 0;
- foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers)
+ for (QQmlAbstractProfilerAdapter *engineProfiler : qAsConst(m_engineProfilers))
features |= engineProfiler->features();
if (features != 0)
@@ -231,7 +240,9 @@ void QQmlProfilerServiceImpl::startProfiling(QJSEngine *engine, quint64 features
d << m_timer.nsecsElapsed() << (int)Event << (int)StartTrace;
bool startedAny = false;
if (engine != 0) {
- foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) {
+ const auto range = qAsConst(m_engineProfilers).equal_range(engine);
+ for (auto it = range.first; it != range.second; ++it) {
+ QQmlAbstractProfilerAdapter *profiler = *it;
if (!profiler->isRunning()) {
profiler->startProfiling(features);
startedAny = true;
@@ -249,12 +260,12 @@ void QQmlProfilerServiceImpl::startProfiling(QJSEngine *engine, quint64 features
startedAny = true;
}
}
- foreach (QJSEngine *profiledEngine, engines)
+ for (QJSEngine *profiledEngine : qAsConst(engines))
d << idForObject(profiledEngine);
}
if (startedAny) {
- foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) {
+ for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_globalProfilers)) {
if (!profiler->isRunning())
profiler->startProfiling(features);
}
@@ -294,7 +305,7 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine)
if (stopping.isEmpty())
return;
- foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) {
+ for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_globalProfilers)) {
if (!profiler->isRunning())
continue;
m_startTimes.insert(-1, profiler);
@@ -308,10 +319,10 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine)
emit stopFlushTimer();
m_waitingForStop = true;
- foreach (QQmlAbstractProfilerAdapter *profiler, reporting)
+ for (QQmlAbstractProfilerAdapter *profiler : qAsConst(reporting))
profiler->reportData(m_useMessageTypes);
- foreach (QQmlAbstractProfilerAdapter *profiler, stopping)
+ for (QQmlAbstractProfilerAdapter *profiler : qAsConst(stopping))
profiler->stopProfiling();
}
@@ -327,7 +338,7 @@ void QQmlProfilerServiceImpl::sendMessages()
traceEnd << m_timer.nsecsElapsed() << (int)Event << (int)EndTrace;
QSet<QJSEngine *> seen;
- foreach (QQmlAbstractProfilerAdapter *profiler, m_startTimes) {
+ for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_startTimes)) {
for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin());
i != m_engineProfilers.end(); ++i) {
if (i.value() == profiler && !seen.contains(i.key())) {
@@ -367,7 +378,7 @@ void QQmlProfilerServiceImpl::sendMessages()
emit messagesToClient(name(), messages);
// Restart flushing if any profilers are still running
- foreach (const QQmlAbstractProfilerAdapter *profiler, m_engineProfilers) {
+ for (const QQmlAbstractProfilerAdapter *profiler : qAsConst(m_engineProfilers)) {
if (profiler->isRunning()) {
emit startFlushTimer();
break;
@@ -409,14 +420,16 @@ void QQmlProfilerServiceImpl::messageReceived(const QByteArray &message)
if (!stream.atEnd()) {
stream >> flushInterval;
m_flushTimer.setInterval(flushInterval);
+ auto timerStart = static_cast<void(QTimer::*)()>(&QTimer::start);
if (flushInterval > 0) {
- connect(&m_flushTimer, SIGNAL(timeout()), this, SLOT(flush()));
- connect(this, SIGNAL(startFlushTimer()), &m_flushTimer, SLOT(start()));
- connect(this, SIGNAL(stopFlushTimer()), &m_flushTimer, SLOT(stop()));
+ connect(&m_flushTimer, &QTimer::timeout, this, &QQmlProfilerServiceImpl::flush);
+ connect(this, &QQmlProfilerServiceImpl::startFlushTimer, &m_flushTimer, timerStart);
+ connect(this, &QQmlProfilerServiceImpl::stopFlushTimer, &m_flushTimer, &QTimer::stop);
} else {
- disconnect(&m_flushTimer, SIGNAL(timeout()), this, SLOT(flush()));
- disconnect(this, SIGNAL(startFlushTimer()), &m_flushTimer, SLOT(start()));
- disconnect(this, SIGNAL(stopFlushTimer()), &m_flushTimer, SLOT(stop()));
+ disconnect(&m_flushTimer, &QTimer::timeout, this, &QQmlProfilerServiceImpl::flush);
+ disconnect(this, &QQmlProfilerServiceImpl::startFlushTimer, &m_flushTimer, timerStart);
+ disconnect(this, &QQmlProfilerServiceImpl::stopFlushTimer,
+ &m_flushTimer, &QTimer::stop);
}
}
if (!stream.atEnd())
@@ -434,20 +447,24 @@ void QQmlProfilerServiceImpl::messageReceived(const QByteArray &message)
void QQmlProfilerServiceImpl::flush()
{
QMutexLocker lock(&m_configMutex);
+ QList<QQmlAbstractProfilerAdapter *> reporting;
- foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers) {
+ for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_engineProfilers)) {
if (profiler->isRunning()) {
m_startTimes.insert(-1, profiler);
- profiler->reportData(m_useMessageTypes);
+ reporting.append(profiler);
}
}
- foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) {
+ for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_globalProfilers)) {
if (profiler->isRunning()) {
m_startTimes.insert(-1, profiler);
- profiler->reportData(m_useMessageTypes);
+ reporting.append(profiler);
}
}
+
+ for (QQmlAbstractProfilerAdapter *profiler : qAsConst(reporting))
+ profiler->reportData(m_useMessageTypes);
}
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
index 42efdefd12..bbfc32b681 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
@@ -99,9 +99,6 @@ signals:
void startFlushTimer();
void stopFlushTimer();
-private slots:
- void flush();
-
protected:
virtual void stateAboutToBeChanged(State state) Q_DECL_OVERRIDE;
virtual void messageReceived(const QByteArray &) Q_DECL_OVERRIDE;
@@ -112,6 +109,7 @@ private:
void sendMessages();
void addEngineProfiler(QQmlAbstractProfilerAdapter *profiler, QJSEngine *engine);
void removeProfilerFromStartTimes(const QQmlAbstractProfilerAdapter *profiler);
+ void flush();
QElapsedTimer m_timer;
QTimer m_flushTimer;
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
index c3bbb86e3a..eee1dd7eae 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
@@ -46,27 +46,26 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut
m_functionCallPos(0), m_memoryPos(0)
{
setService(service);
- engine->enableProfiler();
- connect(this, SIGNAL(profilingEnabled(quint64)),
- this, SLOT(forwardEnabled(quint64)));
- connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)),
- this, SLOT(forwardEnabledWhileWaiting(quint64)), Qt::DirectConnection);
- connect(this, SIGNAL(v4ProfilingEnabled(quint64)),
- engine->profiler, SLOT(startProfiling(quint64)));
- connect(this, SIGNAL(v4ProfilingEnabledWhileWaiting(quint64)),
- engine->profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection);
- connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling()));
- connect(this, SIGNAL(profilingDisabledWhileWaiting()), engine->profiler, SLOT(stopProfiling()),
+ engine->setProfiler(new QV4::Profiling::Profiler(engine));
+ connect(this, &QQmlAbstractProfilerAdapter::profilingEnabled,
+ this, &QV4ProfilerAdapter::forwardEnabled);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting,
+ this, &QV4ProfilerAdapter::forwardEnabledWhileWaiting, Qt::DirectConnection);
+ connect(this, &QV4ProfilerAdapter::v4ProfilingEnabled,
+ engine->profiler(), &QV4::Profiling::Profiler::startProfiling);
+ connect(this, &QV4ProfilerAdapter::v4ProfilingEnabledWhileWaiting,
+ engine->profiler(), &QV4::Profiling::Profiler::startProfiling, Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingDisabled,
+ engine->profiler(), &QV4::Profiling::Profiler::stopProfiling);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting,
+ engine->profiler(), &QV4::Profiling::Profiler::stopProfiling,
Qt::DirectConnection);
- connect(this, SIGNAL(dataRequested(bool)), engine->profiler, SLOT(reportData(bool)));
- connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
- engine->profiler, SLOT(setTimer(QElapsedTimer)));
- connect(engine->profiler, SIGNAL(dataReady(QV4::Profiling::FunctionLocationHash,
- QVector<QV4::Profiling::FunctionCallProperties>,
- QVector<QV4::Profiling::MemoryAllocationProperties>)),
- this, SLOT(receiveData(QV4::Profiling::FunctionLocationHash,
- QVector<QV4::Profiling::FunctionCallProperties>,
- QVector<QV4::Profiling::MemoryAllocationProperties>)));
+ connect(this, &QQmlAbstractProfilerAdapter::dataRequested,
+ engine->profiler(), &QV4::Profiling::Profiler::reportData);
+ connect(this, &QQmlAbstractProfilerAdapter::referenceTimeKnown,
+ engine->profiler(), &QV4::Profiling::Profiler::setTimer);
+ connect(engine->profiler(), &QV4::Profiling::Profiler::dataReady,
+ this, &QV4ProfilerAdapter::receiveData);
}
qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages,
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
index 13a595f6eb..5d5b83f7ca 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
@@ -70,18 +70,13 @@ public:
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations) override;
-signals:
- void v4ProfilingEnabled(quint64 v4Features);
- void v4ProfilingEnabledWhileWaiting(quint64 v4Features);
-
-public slots:
void receiveData(const QV4::Profiling::FunctionLocationHash &,
const QVector<QV4::Profiling::FunctionCallProperties> &,
const QVector<QV4::Profiling::MemoryAllocationProperties> &);
-private slots:
- void forwardEnabled(quint64 features);
- void forwardEnabledWhileWaiting(quint64 features);
+signals:
+ void v4ProfilingEnabled(quint64 v4Features);
+ void v4ProfilingEnabledWhileWaiting(quint64 v4Features);
private:
QV4::Profiling::FunctionLocationHash m_functionLocations;
@@ -93,6 +88,8 @@ private:
qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages, QQmlDebugPacket &d);
qint64 finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext,
QQmlDebugPacket &d);
+ void forwardEnabled(quint64 features);
+ void forwardEnabledWhileWaiting(quint64 features);
static quint64 translateFeatures(quint64 qmlFeatures);
};
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
index bebf8806c6..0c9fc36463 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
@@ -51,20 +51,20 @@ QQuickProfilerAdapter::QQuickProfilerAdapter(QObject *parent) :
QQuickProfiler::initialize(this);
// We can always do DirectConnection here as all methods are protected by mutexes
- connect(this, SIGNAL(profilingEnabled(quint64)),
- QQuickProfiler::s_instance, SLOT(startProfilingImpl(quint64)), Qt::DirectConnection);
- connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)),
- QQuickProfiler::s_instance, SLOT(startProfilingImpl(quint64)), Qt::DirectConnection);
- connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
- QQuickProfiler::s_instance, SLOT(setTimer(QElapsedTimer)), Qt::DirectConnection);
- connect(this, SIGNAL(profilingDisabled()),
- QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection);
- connect(this, SIGNAL(profilingDisabledWhileWaiting()),
- QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection);
- connect(this, SIGNAL(dataRequested(bool)),
- QQuickProfiler::s_instance, SLOT(reportDataImpl(bool)), Qt::DirectConnection);
- connect(QQuickProfiler::s_instance, SIGNAL(dataReady(QVector<QQuickProfilerData>)),
- this, SLOT(receiveData(QVector<QQuickProfilerData>)), Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingEnabled,
+ QQuickProfiler::s_instance, &QQuickProfiler::startProfilingImpl, Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting,
+ QQuickProfiler::s_instance, &QQuickProfiler::startProfilingImpl, Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::referenceTimeKnown,
+ QQuickProfiler::s_instance, &QQuickProfiler::setTimer, Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingDisabled,
+ QQuickProfiler::s_instance, &QQuickProfiler::stopProfilingImpl, Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting,
+ QQuickProfiler::s_instance, &QQuickProfiler::stopProfilingImpl, Qt::DirectConnection);
+ connect(this, &QQmlAbstractProfilerAdapter::dataRequested,
+ QQuickProfiler::s_instance, &QQuickProfiler::reportDataImpl, Qt::DirectConnection);
+ connect(QQuickProfiler::s_instance, &QQuickProfiler::dataReady,
+ this, &QQuickProfilerAdapter::receiveData, Qt::DirectConnection);
}
QQuickProfilerAdapter::~QQuickProfilerAdapter()
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h
index f1ba411ac5..1ad020afd6 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h
@@ -62,8 +62,6 @@ public:
QQuickProfilerAdapter(QObject *parent = 0);
~QQuickProfilerAdapter();
qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) override;
-
-public slots:
void receiveData(const QVector<QQuickProfilerData> &new_data);
private:
diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
index cbde86e389..f449989598 100644
--- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
+++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
@@ -149,15 +149,6 @@ public:
static void cleanup();
-private slots:
- void wakeEngine(QJSEngine *engine);
- void sendMessage(const QString &name, const QByteArray &message);
- void sendMessages(const QString &name, const QList<QByteArray> &messages);
- void changeServiceState(const QString &serviceName, QQmlDebugService::State state);
- void removeThread();
- void receiveMessage();
- void invalidPacket();
-
private:
friend class QQmlDebugServerThread;
friend class QQmlDebugServerFactory;
@@ -179,6 +170,13 @@ private:
bool canSendMessage(const QString &name);
void doSendMessage(const QString &name, const QByteArray &message);
+ void wakeEngine(QJSEngine *engine);
+ void sendMessage(const QString &name, const QByteArray &message);
+ void sendMessages(const QString &name, const QList<QByteArray> &messages);
+ void changeServiceState(const QString &serviceName, QQmlDebugService::State state);
+ void removeThread();
+ void receiveMessage();
+ void invalidPacket();
QQmlDebugServerConnection *m_connection;
QHash<QString, QQmlDebugService *> m_plugins;
@@ -203,18 +201,22 @@ void QQmlDebugServerImpl::cleanup()
if (!server)
return;
- for (QHash<QString, QQmlDebugService *>::ConstIterator i = server->m_plugins.constBegin();
- i != server->m_plugins.constEnd(); ++i) {
- server->m_changeServiceStateCalls.ref();
- QMetaObject::invokeMethod(server, "changeServiceState", Qt::QueuedConnection,
- Q_ARG(QString, i.key()),
- Q_ARG(QQmlDebugService::State,
- QQmlDebugService::NotConnected));
+ {
+ QObject signalSource;
+ for (QHash<QString, QQmlDebugService *>::ConstIterator i = server->m_plugins.constBegin();
+ i != server->m_plugins.constEnd(); ++i) {
+ server->m_changeServiceStateCalls.ref();
+ QString key = i.key();
+ // Process this in the server's thread.
+ connect(&signalSource, &QObject::destroyed, server, [key, server](){
+ server->changeServiceState(key, QQmlDebugService::NotConnected);
+ }, Qt::QueuedConnection);
+ }
}
// Wait for changeServiceState calls to finish
// (while running an event loop because some services
- // might again use slots to execute stuff in the GUI thread)
+ // might again defer execution of stuff in the GUI thread)
QEventLoop loop;
while (!server->m_changeServiceStateCalls.testAndSetOrdered(0, 0))
loop.processEvents();
@@ -293,7 +295,7 @@ QQmlDebugServerImpl::QQmlDebugServerImpl() :
// Remove the thread immmediately when it finishes, so that we don't have to wait for the
// event loop to signal that.
- QObject::connect(&m_thread, SIGNAL(finished()), this, SLOT(removeThread()),
+ QObject::connect(&m_thread, &QThread::finished, this, &QQmlDebugServerImpl::removeThread,
Qt::DirectConnection);
m_thread.setObjectName(QStringLiteral("QQmlDebugServerThread"));
parseArguments();
@@ -587,12 +589,12 @@ void QQmlDebugServerImpl::addEngine(QJSEngine *engine)
QMutexLocker locker(&m_helloMutex);
Q_ASSERT(!m_engineConditions.contains(engine));
- foreach (QQmlDebugService *service, m_plugins)
+ for (QQmlDebugService *service : qAsConst(m_plugins))
service->engineAboutToBeAdded(engine);
m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count());
- foreach (QQmlDebugService *service, m_plugins)
+ for (QQmlDebugService *service : qAsConst(m_plugins))
service->engineAdded(engine);
}
@@ -604,12 +606,12 @@ void QQmlDebugServerImpl::removeEngine(QJSEngine *engine)
QMutexLocker locker(&m_helloMutex);
Q_ASSERT(m_engineConditions.contains(engine));
- foreach (QQmlDebugService *service, m_plugins)
+ for (QQmlDebugService *service : qAsConst(m_plugins))
service->engineAboutToBeRemoved(engine);
m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count());
- foreach (QQmlDebugService *service, m_plugins)
+ for (QQmlDebugService *service : qAsConst(m_plugins))
service->engineRemoved(engine);
m_engineConditions.remove(engine);
@@ -631,15 +633,15 @@ bool QQmlDebugServerImpl::addService(const QString &name, QQmlDebugService *serv
if (!service || m_plugins.contains(name))
return false;
- connect(service, SIGNAL(messageToClient(QString,QByteArray)),
- this, SLOT(sendMessage(QString,QByteArray)));
- connect(service, SIGNAL(messagesToClient(QString,QList<QByteArray>)),
- this, SLOT(sendMessages(QString,QList<QByteArray>)));
+ connect(service, &QQmlDebugService::messageToClient,
+ this, &QQmlDebugServerImpl::sendMessage);
+ connect(service, &QQmlDebugService::messagesToClient,
+ this, &QQmlDebugServerImpl::sendMessages);
- connect(service, SIGNAL(attachedToEngine(QJSEngine*)),
- this, SLOT(wakeEngine(QJSEngine*)), Qt::QueuedConnection);
- connect(service, SIGNAL(detachedFromEngine(QJSEngine*)),
- this, SLOT(wakeEngine(QJSEngine*)), Qt::QueuedConnection);
+ connect(service, &QQmlDebugService::attachedToEngine,
+ this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection);
+ connect(service, &QQmlDebugService::detachedFromEngine,
+ this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection);
service->setState(QQmlDebugService::Unavailable);
m_plugins.insert(name, service);
@@ -659,15 +661,15 @@ bool QQmlDebugServerImpl::removeService(const QString &name)
m_plugins.remove(name);
service->setState(QQmlDebugService::NotConnected);
- disconnect(service, SIGNAL(detachedFromEngine(QJSEngine*)),
- this, SLOT(wakeEngine(QJSEngine*)));
- disconnect(service, SIGNAL(attachedToEngine(QJSEngine*)),
- this, SLOT(wakeEngine(QJSEngine*)));
+ disconnect(service, &QQmlDebugService::detachedFromEngine,
+ this, &QQmlDebugServerImpl::wakeEngine);
+ disconnect(service, &QQmlDebugService::attachedToEngine,
+ this, &QQmlDebugServerImpl::wakeEngine);
- disconnect(service, SIGNAL(messagesToClient(QString,QList<QByteArray>)),
- this, SLOT(sendMessages(QString,QList<QByteArray>)));
- disconnect(service, SIGNAL(messageToClient(QString,QByteArray)),
- this, SLOT(sendMessage(QString,QByteArray)));
+ disconnect(service, &QQmlDebugService::messagesToClient,
+ this, &QQmlDebugServerImpl::sendMessages);
+ disconnect(service, &QQmlDebugService::messageToClient,
+ this, &QQmlDebugServerImpl::sendMessage);
return true;
}
@@ -701,11 +703,11 @@ void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArr
if (m_clientSupportsMultiPackets) {
QQmlDebugPacket out;
out << name;
- foreach (const QByteArray &message, messages)
+ for (const QByteArray &message : messages)
out << message;
m_protocol->send(out.data());
} else {
- foreach (const QByteArray &message, messages)
+ for (const QByteArray &message : messages)
doSendMessage(name, message);
}
m_connection->flush();
@@ -738,8 +740,10 @@ void QQmlDebugServerImpl::EngineCondition::wake()
void QQmlDebugServerImpl::setDevice(QIODevice *socket)
{
m_protocol = new QPacketProtocol(socket, this);
- QObject::connect(m_protocol, SIGNAL(readyRead()), this, SLOT(receiveMessage()));
- QObject::connect(m_protocol, SIGNAL(invalidPacket()), this, SLOT(invalidPacket()));
+ QObject::connect(m_protocol, &QPacketProtocol::readyRead,
+ this, &QQmlDebugServerImpl::receiveMessage);
+ QObject::connect(m_protocol, &QPacketProtocol::invalidPacket,
+ this, &QQmlDebugServerImpl::invalidPacket);
if (blockingMode())
m_protocol->waitForReadyRead(-1);
diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
index 3d64312b16..b305c3f535 100644
--- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
+++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
@@ -65,10 +65,8 @@ public:
void waitForConnection();
void flush();
-private slots:
- void newConnection();
-
private:
+ void newConnection();
bool listen();
int m_portFrom;
@@ -152,7 +150,8 @@ void QTcpServerConnection::flush()
bool QTcpServerConnection::listen()
{
m_tcpServer = new QTcpServer(this);
- QObject::connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
+ QObject::connect(m_tcpServer, &QTcpServer::newConnection,
+ this, &QTcpServerConnection::newConnection);
QHostAddress hostaddress;
if (!m_hostaddress.isEmpty()) {
if (!hostaddress.setAddress(m_hostaddress)) {
diff --git a/src/plugins/qmltooling/shared/qqmldebugserver.h b/src/plugins/qmltooling/shared/qqmldebugserver.h
index 424c7c4120..109f1e246c 100644
--- a/src/plugins/qmltooling/shared/qqmldebugserver.h
+++ b/src/plugins/qmltooling/shared/qqmldebugserver.h
@@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
-class QQmlDebugServer : protected QQmlDebugConnector
+class QQmlDebugServer : public QQmlDebugConnector
{
Q_OBJECT
public:
diff --git a/src/plugins/scenegraph/d3d12/d3d12.pro b/src/plugins/scenegraph/d3d12/d3d12.pro
index 6ba18acf22..9cca5458ee 100644
--- a/src/plugins/scenegraph/d3d12/d3d12.pro
+++ b/src/plugins/scenegraph/d3d12/d3d12.pro
@@ -12,19 +12,22 @@ QMAKE_TARGET_DESCRIPTION = "Quick D3D12 Renderer for Qt."
SOURCES += \
$$PWD/qsgd3d12adaptation.cpp \
$$PWD/qsgd3d12renderloop.cpp \
+ $$PWD/qsgd3d12threadedrenderloop.cpp \
$$PWD/qsgd3d12renderer.cpp \
$$PWD/qsgd3d12context.cpp \
$$PWD/qsgd3d12rendercontext.cpp \
- $$PWD/qsgd3d12rectanglenode.cpp \
+ $$PWD/qsgd3d12internalrectanglenode.cpp \
$$PWD/qsgd3d12material.cpp \
$$PWD/qsgd3d12builtinmaterials.cpp \
$$PWD/qsgd3d12texture.cpp \
- $$PWD/qsgd3d12imagenode.cpp \
+ $$PWD/qsgd3d12internalimagenode.cpp \
$$PWD/qsgd3d12glyphnode.cpp \
$$PWD/qsgd3d12glyphcache.cpp \
$$PWD/qsgd3d12layer.cpp \
$$PWD/qsgd3d12shadereffectnode.cpp \
- $$PWD/qsgd3d12painternode.cpp
+ $$PWD/qsgd3d12painternode.cpp \
+ $$PWD/qsgd3d12publicnodes.cpp \
+ $$PWD/qsgd3d12spritenode.cpp
NO_PCH_SOURCES += \
$$PWD/qsgd3d12engine.cpp
@@ -32,23 +35,26 @@ NO_PCH_SOURCES += \
HEADERS += \
$$PWD/qsgd3d12adaptation_p.h \
$$PWD/qsgd3d12renderloop_p.h \
+ $$PWD/qsgd3d12threadedrenderloop_p.h \
$$PWD/qsgd3d12renderer_p.h \
$$PWD/qsgd3d12context_p.h \
$$PWD/qsgd3d12rendercontext_p.h \
$$PWD/qsgd3d12engine_p.h \
$$PWD/qsgd3d12engine_p_p.h \
- $$PWD/qsgd3d12rectanglenode_p.h \
+ $$PWD/qsgd3d12internalrectanglenode_p.h \
$$PWD/qsgd3d12material_p.h \
$$PWD/qsgd3d12builtinmaterials_p.h \
$$PWD/qsgd3d12texture_p.h \
- $$PWD/qsgd3d12imagenode_p.h \
+ $$PWD/qsgd3d12internalimagenode_p.h \
$$PWD/qsgd3d12glyphnode_p.h \
$$PWD/qsgd3d12glyphcache_p.h \
$$PWD/qsgd3d12layer_p.h \
$$PWD/qsgd3d12shadereffectnode_p.h \
- $$PWD/qsgd3d12painternode_p.h
+ $$PWD/qsgd3d12painternode_p.h \
+ $$PWD/qsgd3d12publicnodes_p.h \
+ $$PWD/qsgd3d12spritenode_p.h
-LIBS += -ldxgi -ld3d12 -ld3dcompiler
+LIBS += -ldxgi -ld3d12 -ld3dcompiler -ldcomp
include($$PWD/shaders/shaders.pri)
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12adaptation.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12adaptation.cpp
index 2762177e5d..b93da0ae01 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12adaptation.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12adaptation.cpp
@@ -39,6 +39,7 @@
#include "qsgd3d12adaptation_p.h"
#include "qsgd3d12renderloop_p.h"
+#include "qsgd3d12threadedrenderloop_p.h"
#include "qsgd3d12context_p.h"
QT_BEGIN_NAMESPACE
@@ -68,6 +69,16 @@ QSGContextFactoryInterface::Flags QSGD3D12Adaptation::flags(const QString &) con
QSGRenderLoop *QSGD3D12Adaptation::createWindowManager()
{
+ static bool threaded = false;
+ static bool envChecked = false;
+ if (!envChecked) {
+ envChecked = true;
+ threaded = qgetenv("QSG_RENDER_LOOP") == QByteArrayLiteral("threaded");
+ }
+
+ if (threaded)
+ return new QSGD3D12ThreadedRenderLoop;
+
return new QSGD3D12RenderLoop;
}
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials.cpp
index ca92062120..fc3ea4e22e 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials.cpp
@@ -102,6 +102,7 @@ QSGMaterialType *QSGD3D12VertexColorMaterial::type() const
int QSGD3D12VertexColorMaterial::compare(const QSGMaterial *other) const
{
+ Q_UNUSED(other);
Q_ASSERT(other && type() == other->type());
// As the vertex color material has all its state in the vertex attributes
// defined by the geometry, all such materials will be equal.
@@ -148,6 +149,11 @@ QSGD3D12Material::UpdateResults QSGD3D12VertexColorMaterial::updatePipeline(cons
return r;
}
+QSGD3D12FlatColorMaterial::QSGD3D12FlatColorMaterial()
+ : m_color(QColor(255, 255, 255))
+{
+}
+
QSGMaterialType QSGD3D12FlatColorMaterial::mtype;
QSGMaterialType *QSGD3D12FlatColorMaterial::type() const
@@ -224,6 +230,7 @@ QSGMaterialType *QSGD3D12SmoothColorMaterial::type() const
int QSGD3D12SmoothColorMaterial::compare(const QSGMaterial *other) const
{
+ Q_UNUSED(other);
Q_ASSERT(other && type() == other->type());
return 0;
}
@@ -353,6 +360,12 @@ QSGD3D12Material::UpdateResults QSGD3D12TextureMaterial::updatePipeline(const QS
return r;
}
+void QSGD3D12TextureMaterial::setTexture(QSGTexture *texture)
+{
+ m_texture = texture;
+ setFlag(Blending, m_texture ? m_texture->hasAlphaChannel() : false);
+}
+
QSGD3D12SmoothTextureMaterial::QSGD3D12SmoothTextureMaterial()
{
setFlag(RequiresFullMatrixExceptTranslate, true);
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h
index 34ae73d2d6..8e488f8cd1 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h
@@ -80,6 +80,7 @@ private:
class QSGD3D12FlatColorMaterial : public QSGD3D12Material
{
public:
+ QSGD3D12FlatColorMaterial();
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
@@ -129,7 +130,7 @@ public:
ExtraState *extraState,
quint8 *constantBuffer) override;
- void setTexture(QSGTexture *texture) { m_texture = texture; }
+ void setTexture(QSGTexture *texture);
QSGTexture *texture() const { return m_texture; }
void setMipmapFiltering(QSGTexture::Filtering filter) { m_mipmap_filtering = filter; }
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
index ce44bc7a38..9b88af995d 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
@@ -39,12 +39,15 @@
#include "qsgd3d12context_p.h"
#include "qsgd3d12rendercontext_p.h"
-#include "qsgd3d12rectanglenode_p.h"
-#include "qsgd3d12imagenode_p.h"
+#include "qsgd3d12internalrectanglenode_p.h"
+#include "qsgd3d12internalimagenode_p.h"
#include "qsgd3d12glyphnode_p.h"
#include "qsgd3d12layer_p.h"
#include "qsgd3d12shadereffectnode_p.h"
#include "qsgd3d12painternode_p.h"
+#include "qsgd3d12publicnodes_p.h"
+#include "qsgd3d12spritenode_p.h"
+#include <QtQuick/qquickwindow.h>
QT_BEGIN_NAMESPACE
@@ -53,14 +56,14 @@ QSGRenderContext *QSGD3D12Context::createRenderContext()
return new QSGD3D12RenderContext(this);
}
-QSGRectangleNode *QSGD3D12Context::createRectangleNode()
+QSGInternalRectangleNode *QSGD3D12Context::createInternalRectangleNode()
{
- return new QSGD3D12RectangleNode;
+ return new QSGD3D12InternalRectangleNode;
}
-QSGImageNode *QSGD3D12Context::createImageNode()
+QSGInternalImageNode *QSGD3D12Context::createInternalImageNode()
{
- return new QSGD3D12ImageNode;
+ return new QSGD3D12InternalImageNode;
}
QSGPainterNode *QSGD3D12Context::createPainterNode(QQuickPaintedItem *item)
@@ -77,11 +80,6 @@ QSGGlyphNode *QSGD3D12Context::createGlyphNode(QSGRenderContext *renderContext,
return new QSGD3D12GlyphNode(rc);
}
-QSGNinePatchNode *QSGD3D12Context::createNinePatchNode()
-{
- return nullptr;
-}
-
QSGLayer *QSGD3D12Context::createLayer(QSGRenderContext *renderContext)
{
QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(renderContext);
@@ -108,17 +106,37 @@ QSize QSGD3D12Context::minimumFBOSize() const
QSurfaceFormat QSGD3D12Context::defaultSurfaceFormat() const
{
- return QSurfaceFormat::defaultFormat();
+ QSurfaceFormat format = QSurfaceFormat::defaultFormat();
+
+ if (QQuickWindow::hasDefaultAlphaBuffer())
+ format.setAlphaBufferSize(8);
+
+ return format;
}
QSGRendererInterface *QSGD3D12Context::rendererInterface(QSGRenderContext *renderContext)
{
- QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(renderContext);
- if (!rc->engine()) {
- qWarning("No D3D12 engine available yet (no render thread due to window not exposed?)");
- return nullptr;
- }
- return rc->engine();
+ return static_cast<QSGD3D12RenderContext *>(renderContext);
+}
+
+QSGRectangleNode *QSGD3D12Context::createRectangleNode()
+{
+ return new QSGD3D12RectangleNode;
+}
+
+QSGImageNode *QSGD3D12Context::createImageNode()
+{
+ return new QSGD3D12ImageNode;
+}
+
+QSGNinePatchNode *QSGD3D12Context::createNinePatchNode()
+{
+ return new QSGD3D12NinePatchNode;
+}
+
+QSGSpriteNode *QSGD3D12Context::createSpriteNode()
+{
+ return new QSGD3D12SpriteNode;
}
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h
index 0564c4edac..70cc606b52 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h
@@ -61,11 +61,10 @@ public:
QSGD3D12Context(QObject *parent = 0) : QSGContext(parent) { }
QSGRenderContext *createRenderContext() override;
- QSGRectangleNode *createRectangleNode() override;
- QSGImageNode *createImageNode() override;
+ QSGInternalRectangleNode *createInternalRectangleNode() override;
+ QSGInternalImageNode *createInternalImageNode() override;
QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override;
QSGGlyphNode *createGlyphNode(QSGRenderContext *renderContext, bool preferNativeGlyphNode) override;
- QSGNinePatchNode *createNinePatchNode() override;
QSGLayer *createLayer(QSGRenderContext *renderContext) override;
QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager() override;
QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext,
@@ -73,6 +72,11 @@ public:
QSize minimumFBOSize() const override;
QSurfaceFormat defaultSurfaceFormat() const override;
QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
+ QSGRectangleNode *createRectangleNode() override;
+ QSGImageNode *createImageNode() override;
+ QSGNinePatchNode *createNinePatchNode() override;
+ QSGSpriteNode *createSpriteNode() override;
+
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
index 45b9de9ece..2644c693ce 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
@@ -42,6 +42,7 @@
#include "cs_mipmapgen.hlslh"
#include <QString>
#include <QColor>
+#include <QLoggingCategory>
#include <qmath.h>
#include <qalgorithms.h>
@@ -69,18 +70,30 @@ QT_BEGIN_NAMESPACE
{ static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
DECLARE_DEBUG_VAR(render)
+DECLARE_DEBUG_VAR(descheap)
+DECLARE_DEBUG_VAR(buffer)
+DECLARE_DEBUG_VAR(texture)
+
+// Except for system info on startup.
+Q_LOGGING_CATEGORY(QSG_LOG_INFO_GENERAL, "qt.scenegraph.general")
+
+
+// Any changes to the defaults below must be reflected in adaptations.qdoc as
+// well and proven by qmlbench or similar.
static const int DEFAULT_SWAP_CHAIN_BUFFER_COUNT = 3;
static const int DEFAULT_FRAME_IN_FLIGHT_COUNT = 2;
static const int DEFAULT_WAITABLE_SWAP_CHAIN_MAX_LATENCY = 0;
-static const int MAX_DRAW_CALLS_PER_LIST = 128;
+static const int MAX_DRAW_CALLS_PER_LIST = 4096;
static const int MAX_CACHED_ROOTSIG = 16;
static const int MAX_CACHED_PSO = 64;
static const int GPU_CBVSRVUAV_DESCRIPTORS = 512;
+static const DXGI_FORMAT RT_COLOR_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
+
static const int BUCKETS_PER_HEAP = 8; // must match freeMap
static const int DESCRIPTORS_PER_BUCKET = 32; // the bit map (freeMap) is quint32
static const int MAX_DESCRIPTORS_PER_HEAP = BUCKETS_PER_HEAP * DESCRIPTORS_PER_BUCKET;
@@ -94,8 +107,8 @@ D3D12_CPU_DESCRIPTOR_HANDLE QSGD3D12CPUDescriptorHeapManager::allocate(D3D12_DES
if (heap.freeMap[bucket]) {
uint freePos = qCountTrailingZeroBits(heap.freeMap[bucket]);
heap.freeMap[bucket] &= ~(1UL << freePos);
- if (Q_UNLIKELY(debug_render()))
- qDebug("descriptor handle type %x reserve in bucket %d index %d", type, bucket, freePos);
+ if (Q_UNLIKELY(debug_descheap()))
+ qDebug("descriptor handle heap %p type %x reserve in bucket %d index %d", &heap, type, bucket, freePos);
freePos += bucket * DESCRIPTORS_PER_BUCKET;
h = heap.start;
h.ptr += freePos * heap.handleSize;
@@ -121,7 +134,7 @@ D3D12_CPU_DESCRIPTOR_HANDLE QSGD3D12CPUDescriptorHeapManager::allocate(D3D12_DES
heap.start = heap.heap->GetCPUDescriptorHandleForHeapStart();
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_descheap()))
qDebug("new descriptor heap, type %x, start %llu", type, heap.start.ptr);
heap.freeMap[0] = 0xFFFFFFFE;
@@ -145,8 +158,8 @@ void QSGD3D12CPUDescriptorHeapManager::release(D3D12_CPU_DESCRIPTOR_HANDLE handl
const int bucket = pos / DESCRIPTORS_PER_BUCKET;
const int indexInBucket = pos - bucket * DESCRIPTORS_PER_BUCKET;
heap.freeMap[bucket] |= 1UL << indexInBucket;
- if (Q_UNLIKELY(debug_render()))
- qDebug("free descriptor handle type %x bucket %d index %d", type, bucket, indexInBucket);
+ if (Q_UNLIKELY(debug_descheap()))
+ qDebug("free descriptor handle heap %p type %x bucket %d index %d", &heap, type, bucket, indexInBucket);
return;
}
}
@@ -184,18 +197,22 @@ static void getHardwareAdapter(IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapte
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
const QString name = QString::fromUtf16((char16_t *) desc.Description);
- qDebug("Adapter %d: '%s' (flags 0x%x)", adapterIndex, qPrintable(name), desc.Flags);
+ qCDebug(QSG_LOG_INFO_GENERAL, "Adapter %d: '%s' (flags 0x%x)", adapterIndex, qPrintable(name), desc.Flags);
}
if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX")) {
const int adapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
- if (SUCCEEDED(factory->EnumAdapters1(adapterIndex, &adapter))
- && SUCCEEDED(D3D12CreateDevice(adapter.Get(), fl, _uuidof(ID3D12Device), nullptr))) {
+ if (SUCCEEDED(factory->EnumAdapters1(adapterIndex, &adapter))) {
adapter->GetDesc1(&desc);
const QString name = QString::fromUtf16((char16_t *) desc.Description);
- qDebug("Using requested adapter '%s'", qPrintable(name));
- *outAdapter = adapter.Detach();
- return;
+ HRESULT hr = D3D12CreateDevice(adapter.Get(), fl, _uuidof(ID3D12Device), nullptr);
+ if (SUCCEEDED(hr)) {
+ qCDebug(QSG_LOG_INFO_GENERAL, "Using requested adapter '%s'", qPrintable(name));
+ *outAdapter = adapter.Detach();
+ return;
+ } else {
+ qWarning("Failed to create device for requested adapter '%s': 0x%x", qPrintable(name), hr);
+ }
}
}
@@ -206,7 +223,7 @@ static void getHardwareAdapter(IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapte
if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), fl, _uuidof(ID3D12Device), nullptr))) {
const QString name = QString::fromUtf16((char16_t *) desc.Description);
- qDebug("Using adapter '%s'", qPrintable(name));
+ qCDebug(QSG_LOG_INFO_GENERAL, "Using adapter '%s'", qPrintable(name));
break;
}
}
@@ -270,7 +287,7 @@ void QSGD3D12DeviceManager::ensureCreated()
}
if (warp) {
- qDebug("Using WARP");
+ qCDebug(QSG_LOG_INFO_GENERAL, "Using WARP");
m_factory->EnumWarpAdapter(IID_PPV_ARGS(&adapter));
HRESULT hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
if (FAILED(hr)) {
@@ -283,14 +300,14 @@ void QSGD3D12DeviceManager::ensureCreated()
if (SUCCEEDED(adapter.As(&adapter3))) {
DXGI_QUERY_VIDEO_MEMORY_INFO vidMemInfo;
if (SUCCEEDED(adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &vidMemInfo))) {
- qDebug("Video memory info: LOCAL: Budget %llu KB CurrentUsage %llu KB AvailableForReservation %llu KB CurrentReservation %llu KB",
- vidMemInfo.Budget / 1024, vidMemInfo.CurrentUsage / 1024,
- vidMemInfo.AvailableForReservation / 1024, vidMemInfo.CurrentReservation / 1024);
+ qCDebug(QSG_LOG_INFO_GENERAL, "Video memory info: LOCAL: Budget %llu KB CurrentUsage %llu KB AvailableForReservation %llu KB CurrentReservation %llu KB",
+ vidMemInfo.Budget / 1024, vidMemInfo.CurrentUsage / 1024,
+ vidMemInfo.AvailableForReservation / 1024, vidMemInfo.CurrentReservation / 1024);
}
if (SUCCEEDED(adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &vidMemInfo))) {
- qDebug("Video memory info: NON-LOCAL: Budget %llu KB CurrentUsage %llu KB AvailableForReservation %llu KB CurrentReservation %llu KB",
- vidMemInfo.Budget / 1024, vidMemInfo.CurrentUsage / 1024,
- vidMemInfo.AvailableForReservation / 1024, vidMemInfo.CurrentReservation / 1024);
+ qCDebug(QSG_LOG_INFO_GENERAL, "Video memory info: NON-LOCAL: Budget %llu KB CurrentUsage %llu KB AvailableForReservation %llu KB CurrentReservation %llu KB",
+ vidMemInfo.Budget / 1024, vidMemInfo.CurrentUsage / 1024,
+ vidMemInfo.AvailableForReservation / 1024, vidMemInfo.CurrentReservation / 1024);
}
}
}
@@ -313,14 +330,14 @@ QSGD3D12Engine::~QSGD3D12Engine()
delete d;
}
-bool QSGD3D12Engine::attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples)
+bool QSGD3D12Engine::attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha)
{
if (d->isInitialized()) {
qWarning("QSGD3D12Engine: Cannot attach active engine to window");
return false;
}
- d->initialize(window, size, dpr, surfaceFormatSamples);
+ d->initialize(window, size, dpr, surfaceFormatSamples, alpha);
return d->isInitialized();
}
@@ -480,14 +497,15 @@ void QSGD3D12Engine::queueTextureResize(uint id, const QSize &size)
d->queueTextureResize(id, size);
}
-void QSGD3D12Engine::queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos)
+void QSGD3D12Engine::queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos, TextureUploadFlags flags)
{
- d->queueTextureUpload(id, QVector<QImage>() << image, QVector<QPoint>() << dstPos);
+ d->queueTextureUpload(id, QVector<QImage>() << image, QVector<QPoint>() << dstPos, flags);
}
-void QSGD3D12Engine::queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos)
+void QSGD3D12Engine::queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos,
+ TextureUploadFlags flags)
{
- d->queueTextureUpload(id, images, dstPos);
+ d->queueTextureUpload(id, images, dstPos, flags);
}
void QSGD3D12Engine::releaseTexture(uint id)
@@ -535,31 +553,11 @@ void QSGD3D12Engine::simulateDeviceLoss()
d->simulateDeviceLoss();
}
-QSGRendererInterface::GraphicsApi QSGD3D12Engine::graphicsApi() const
-{
- return Direct3D12;
-}
-
-void *QSGD3D12Engine::getResource(Resource resource) const
+void *QSGD3D12Engine::getResource(QQuickWindow *, QSGRendererInterface::Resource resource) const
{
return d->getResource(resource);
}
-QSGRendererInterface::ShaderType QSGD3D12Engine::shaderType() const
-{
- return HLSL;
-}
-
-QSGRendererInterface::ShaderCompilationTypes QSGD3D12Engine::shaderCompilationType() const
-{
- return OfflineCompilation;
-}
-
-QSGRendererInterface::ShaderSourceTypes QSGD3D12Engine::shaderSourceType() const
-{
- return ShaderByteCode;
-}
-
static inline quint32 alignedSize(quint32 size, quint32 byteAlign)
{
return (size + byteAlign - 1) & ~(byteAlign - 1);
@@ -684,6 +682,13 @@ void QSGD3D12EnginePrivate::releaseResources()
commandQueue = nullptr;
copyCommandQueue = nullptr;
+
+#ifndef Q_OS_WINRT
+ dcompTarget = nullptr;
+ dcompVisual = nullptr;
+ dcompDevice = nullptr;
+#endif
+
swapChain = nullptr;
delete presentFence;
@@ -696,7 +701,7 @@ void QSGD3D12EnginePrivate::releaseResources()
// 'window' must be kept, may just be a device loss
}
-void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples)
+void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha)
{
if (initialized)
return;
@@ -705,6 +710,7 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
windowSize = size;
windowDpr = dpr;
windowSamples = qMax(1, surfaceFormatSamples); // may be -1 or 0, whereas windowSamples is uint and >= 1
+ windowAlpha = alpha;
swapChainBufferCount = qMin(qEnvironmentVariableIntValue("QT_D3D_BUFFER_COUNT"), MAX_SWAP_CHAIN_BUFFER_COUNT);
if (swapChainBufferCount < 2)
@@ -720,22 +726,53 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
else
waitableSwapChainMaxLatency = qBound(0, qEnvironmentVariableIntValue(latReqEnvVar), 16);
- qDebug("d3d12 engine init. swap chain buffer count %d, max frames prepared without blocking %d",
- swapChainBufferCount, frameInFlightCount);
+ if (qEnvironmentVariableIsSet("QSG_INFO"))
+ const_cast<QLoggingCategory &>(QSG_LOG_INFO_GENERAL()).setEnabled(QtDebugMsg, true);
+
+ qCDebug(QSG_LOG_INFO_GENERAL, "d3d12 engine init. swap chain buffer count %d, max frames prepared without blocking %d",
+ swapChainBufferCount, frameInFlightCount);
if (waitableSwapChainMaxLatency)
- qDebug("Swap chain frame latency waitable object enabled. Frame latency is %d", waitableSwapChainMaxLatency);
+ qCDebug(QSG_LOG_INFO_GENERAL, "Swap chain frame latency waitable object enabled. Frame latency is %d", waitableSwapChainMaxLatency);
- if (qEnvironmentVariableIntValue("QT_D3D_DEBUG") != 0) {
- qDebug("Enabling debug layer");
+ const bool debugLayer = qEnvironmentVariableIntValue("QT_D3D_DEBUG") != 0;
+ if (debugLayer) {
+ qCDebug(QSG_LOG_INFO_GENERAL, "Enabling debug layer");
+#if !defined(Q_OS_WINRT) || !defined(NDEBUG)
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
debugController->EnableDebugLayer();
+#else
+ qCDebug(QSG_LOG_INFO_GENERAL, "Using DebugInterface will not allow certification to pass");
+#endif
}
QSGD3D12DeviceManager *dev = deviceManager();
device = dev->ref();
dev->registerDeviceLossObserver(this);
+ if (debugLayer) {
+ ComPtr<ID3D12InfoQueue> infoQueue;
+ if (SUCCEEDED(device->QueryInterface(IID_PPV_ARGS(&infoQueue)))) {
+ infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
+ infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
+ const bool breakOnWarning = qEnvironmentVariableIntValue("QT_D3D_DEBUG_BREAK_ON_WARNING") != 0;
+ infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, breakOnWarning);
+ D3D12_INFO_QUEUE_FILTER filter = {};
+ D3D12_MESSAGE_ID suppressedMessages[] = {
+ // When using a render target other than the default one we
+ // have no way to know the custom clear color, if there is one.
+ D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE
+ };
+ filter.DenyList.NumIDs = _countof(suppressedMessages);
+ filter.DenyList.pIDList = suppressedMessages;
+ // setting the filter would enable Info messages which we don't need
+ D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
+ filter.DenyList.NumSeverities = 1;
+ filter.DenyList.pSeverityList = &infoSev;
+ infoQueue->PushStorageFilter(&filter);
+ }
+ }
+
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
if (FAILED(device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)))) {
@@ -752,28 +789,91 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
#ifndef Q_OS_WINRT
HWND hwnd = reinterpret_cast<HWND>(w);
- DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
- swapChainDesc.BufferCount = swapChainBufferCount;
- swapChainDesc.BufferDesc.Width = windowSize.width() * windowDpr;
- swapChainDesc.BufferDesc.Height = windowSize.height() * windowDpr;
- swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // D3D12 requires the flip model
- swapChainDesc.OutputWindow = hwnd;
- swapChainDesc.SampleDesc.Count = 1; // Flip does not support MSAA so no choice here
- swapChainDesc.Windowed = TRUE;
- if (waitableSwapChainMaxLatency)
- swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+ if (windowAlpha) {
+ // Go through DirectComposition for semi-transparent windows since the
+ // traditional approaches won't fly with flip model swapchains.
+ HRESULT hr = DCompositionCreateDevice(nullptr, IID_PPV_ARGS(&dcompDevice));
+ if (SUCCEEDED(hr)) {
+ hr = dcompDevice->CreateTargetForHwnd(hwnd, true, &dcompTarget);
+ if (SUCCEEDED(hr)) {
+ hr = dcompDevice->CreateVisual(&dcompVisual);
+ if (FAILED(hr)) {
+ qWarning("Failed to create DirectComposition visual: 0x%x", hr);
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("Failed to create DirectComposition target: 0x%x", hr);
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("Failed to create DirectComposition device: 0x%x", hr);
+ windowAlpha = false;
+ }
+ }
- ComPtr<IDXGISwapChain> baseSwapChain;
- HRESULT hr = dev->dxgi()->CreateSwapChain(commandQueue.Get(), &swapChainDesc, &baseSwapChain);
- if (FAILED(hr)) {
- qWarning("Failed to create swap chain: 0x%x", hr);
- return;
+ if (windowAlpha) {
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
+ swapChainDesc.Width = windowSize.width() * windowDpr;
+ swapChainDesc.Height = windowSize.height() * windowDpr;
+ swapChainDesc.Format = RT_COLOR_FORMAT;
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.BufferCount = swapChainBufferCount;
+ swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+ swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
+ if (waitableSwapChainMaxLatency)
+ swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+
+ ComPtr<IDXGISwapChain1> baseSwapChain;
+ HRESULT hr = dev->dxgi()->CreateSwapChainForComposition(commandQueue.Get(), &swapChainDesc, nullptr, &baseSwapChain);
+ if (SUCCEEDED(hr)) {
+ if (SUCCEEDED(baseSwapChain.As(&swapChain))) {
+ hr = dcompVisual->SetContent(swapChain.Get());
+ if (SUCCEEDED(hr)) {
+ hr = dcompTarget->SetRoot(dcompVisual.Get());
+ if (FAILED(hr)) {
+ qWarning("SetRoot failed for DirectComposition target: 0x%x", hr);
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("SetContent failed for DirectComposition visual: 0x%x", hr);
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("Failed to cast swap chain");
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("Failed to create swap chain for composition: 0x%x", hr);
+ windowAlpha = false;
+ }
}
- if (FAILED(baseSwapChain.As(&swapChain))) {
- qWarning("Failed to cast swap chain");
- return;
+
+ if (!windowAlpha) {
+ DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
+ swapChainDesc.BufferCount = swapChainBufferCount;
+ swapChainDesc.BufferDesc.Width = windowSize.width() * windowDpr;
+ swapChainDesc.BufferDesc.Height = windowSize.height() * windowDpr;
+ swapChainDesc.BufferDesc.Format = RT_COLOR_FORMAT;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // D3D12 requires the flip model
+ swapChainDesc.OutputWindow = hwnd;
+ swapChainDesc.SampleDesc.Count = 1; // Flip does not support MSAA so no choice here
+ swapChainDesc.Windowed = TRUE;
+ if (waitableSwapChainMaxLatency)
+ swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+
+ ComPtr<IDXGISwapChain> baseSwapChain;
+ HRESULT hr = dev->dxgi()->CreateSwapChain(commandQueue.Get(), &swapChainDesc, &baseSwapChain);
+ if (FAILED(hr)) {
+ qWarning("Failed to create swap chain: 0x%x", hr);
+ return;
+ }
+ if (FAILED(baseSwapChain.As(&swapChain))) {
+ qWarning("Failed to cast swap chain");
+ return;
+ }
}
dev->dxgi()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
@@ -781,7 +881,7 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = windowSize.width() * windowDpr;
swapChainDesc.Height = windowSize.height() * windowDpr;
- swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swapChainDesc.Format = RT_COLOR_FORMAT;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = swapChainBufferCount;
@@ -798,7 +898,7 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
return;
}
if (FAILED(baseSwapChain.As(&swapChain))) {
- qWarning("Failed to case swap chain");
+ qWarning("Failed to cast swap chain");
return;
}
@@ -932,7 +1032,7 @@ ID3D12Resource *QSGD3D12EnginePrivate::createColorBuffer(D3D12_CPU_DESCRIPTOR_HA
const QVector4D &clearColor, uint samples)
{
D3D12_CLEAR_VALUE clearValue = {};
- clearValue.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ clearValue.Format = RT_COLOR_FORMAT;
clearValue.Color[0] = clearColor.x();
clearValue.Color[1] = clearColor.y();
clearValue.Color[2] = clearColor.z();
@@ -947,7 +1047,7 @@ ID3D12Resource *QSGD3D12EnginePrivate::createColorBuffer(D3D12_CPU_DESCRIPTOR_HA
rtDesc.Height = size.height();
rtDesc.DepthOrArraySize = 1;
rtDesc.MipLevels = 1;
- rtDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ rtDesc.Format = RT_COLOR_FORMAT;
rtDesc.SampleDesc = makeSampleDesc(rtDesc.Format, samples);
rtDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
@@ -1013,7 +1113,9 @@ void QSGD3D12EnginePrivate::setupDefaultRenderTargets()
device->CreateRenderTargetView(defaultRT[i].Get(), nullptr, defaultRTV[i]);
} else {
const QSize size(windowSize.width() * windowDpr, windowSize.height() * windowDpr);
- const QColor cc(Qt::white); // ### what if setClearColor? non-fatal but debug layer warns...
+ // Not optimal if the user called setClearColor, but there's so
+ // much we can do. The debug layer warning is suppressed so we're good to go.
+ const QColor cc(Qt::white);
const QVector4D clearColor(cc.redF(), cc.greenF(), cc.blueF(), cc.alphaF());
ID3D12Resource *msaaRT = createColorBuffer(defaultRTV[i], size, clearColor, windowSamples);
if (msaaRT)
@@ -1054,7 +1156,7 @@ void QSGD3D12EnginePrivate::setWindowSize(const QSize &size, float dpr)
const int w = windowSize.width() * windowDpr;
const int h = windowSize.height() * windowDpr;
- HRESULT hr = swapChain->ResizeBuffers(swapChainBufferCount, w, h, DXGI_FORMAT_R8G8B8A8_UNORM,
+ HRESULT hr = swapChain->ResizeBuffers(swapChainBufferCount, w, h, RT_COLOR_FORMAT,
waitableSwapChainMaxLatency ? DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT : 0);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
deviceManager()->deviceLossDetected();
@@ -1138,7 +1240,7 @@ void QSGD3D12EnginePrivate::resolveMultisampledTarget(ID3D12Resource *msaa,
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_DEST;
commandList->ResourceBarrier(2, barriers);
- commandList->ResolveSubresource(resolve, 0, msaa, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
+ commandList->ResolveSubresource(resolve, 0, msaa, 0, RT_COLOR_FORMAT);
barriers[0].Transition.pResource = msaa;
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
@@ -1193,7 +1295,7 @@ void QSGD3D12EnginePrivate::ensureBuffer(Buffer *buf)
// buffer contents rebuild with a slightly larger total size does
// not lead to creating a new buffer.
const quint32 sz = alignedSize(buf->cpuDataRef.size, 4096);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug("new buffer[pf=%d] of size %d (actual data size %d)", currentPFrameIndex, sz, buf->cpuDataRef.size);
bfd.buffer.Attach(createBuffer(sz));
bfd.resourceSize = sz;
@@ -1215,7 +1317,7 @@ void QSGD3D12EnginePrivate::updateBuffer(Buffer *buf)
return;
}
for (const auto &r : qAsConst(buf->cpuDataRef.dirty)) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug("%p o %d s %d", buf, r.first, r.second);
memcpy(p + r.first, buf->cpuDataRef.p + r.first, r.second);
}
@@ -1226,7 +1328,7 @@ void QSGD3D12EnginePrivate::updateBuffer(Buffer *buf)
void QSGD3D12EnginePrivate::ensureDevice()
{
if (!initialized && window)
- initialize(window, windowSize, windowDpr, windowSamples);
+ initialize(window, windowSize, windowDpr, windowSamples, windowAlpha);
}
void QSGD3D12EnginePrivate::beginFrame()
@@ -1296,13 +1398,13 @@ void QSGD3D12EnginePrivate::beginFrame()
for (uint id : qAsConst(prevFrameData.buffersUsedInFrame)) {
Buffer &b(buffers[id - 1]);
if (b.d[currentPFrameIndex].buffer && b.d[currentPFrameIndex].dataSize == b.cpuDataRef.size) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug() << "frame" << frameIndex << "takes dirty" << b.d[prevPFrameIndex].dirty
<< "from frame" << frameIndex - delta << "for buffer" << id;
for (const auto &range : qAsConst(b.d[prevPFrameIndex].dirty))
addDirtyRange(&b.cpuDataRef.dirty, range.first, range.second, b.cpuDataRef.size);
} else {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug() << "frame" << frameIndex << "makes all dirty from frame" << frameIndex - delta
<< "for buffer" << id;
addDirtyRange(&b.cpuDataRef.dirty, 0, b.cpuDataRef.size, b.cpuDataRef.size);
@@ -1316,7 +1418,7 @@ void QSGD3D12EnginePrivate::beginFrame()
const quint64 finishedFrameIndex = frameIndex - frameInFlightCount; // we know since we just blocked for this
// pfd conveniently refers to the same slot that was used by that frame
if (!pfd.pendingTextureUploads.isEmpty()) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("Removing texture upload data for frame %d", finishedFrameIndex);
for (uint id : qAsConst(pfd.pendingTextureUploads)) {
const int idx = id - 1;
@@ -1330,13 +1432,13 @@ void QSGD3D12EnginePrivate::beginFrame()
t.lastWaitFenceValue = 0;
t.stagingBuffers.clear();
t.stagingHeaps.clear();
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("Cleaned staging data for texture %u", id);
}
}
pfd.pendingTextureUploads.clear();
if (!pfd.pendingTextureMipMap.isEmpty()) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug() << "cleaning mipmap generation data for " << pfd.pendingTextureMipMap;
// no special cleanup is needed as mipmap generation uses the frame's resources
pfd.pendingTextureMipMap.clear();
@@ -1350,7 +1452,7 @@ void QSGD3D12EnginePrivate::beginFrame()
}
}
if (!hasPending) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("no more pending textures");
copyCommandAllocator->Reset();
}
@@ -1471,7 +1573,7 @@ void QSGD3D12EnginePrivate::endDrawCalls(bool lastInFrame)
PersistentFrameData &pfd(pframeData[currentPFrameIndex]);
// Now is the time to sync all the changed areas in the buffers.
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug() << "buffers used in drawcall set" << pfd.buffersUsedInDrawCallSet;
for (uint id : qAsConst(pfd.buffersUsedInDrawCallSet))
updateBuffer(&buffers[id - 1]);
@@ -1496,12 +1598,12 @@ void QSGD3D12EnginePrivate::endDrawCalls(bool lastInFrame)
pfd.pendingTextureMipMap.insert(id);
}
if (topFenceValue) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("added wait for texture fence %llu", topFenceValue);
commandQueue->Wait(textureUploadFence.Get(), topFenceValue);
// Generate mipmaps after the wait, when necessary.
if (!pfd.pendingTextureMipMap.isEmpty()) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug() << "starting mipmap generation for" << pfd.pendingTextureMipMap;
for (uint id : qAsConst(pfd.pendingTextureMipMap))
mipmapper.queueGenerate(textures[id - 1]);
@@ -1580,8 +1682,8 @@ void QSGD3D12EnginePrivate::endLayer()
// Root signature:
// [0] CBV - always present
-// [1] table with 1 SRV per texture (optional)
-// one static sampler per texture (optional)
+// [1] table with one SRV per texture (must be a table since root descriptor SRVs cannot be textures) - optional
+// one static sampler per texture - optional
//
// SRVs can be created freely via QSGD3D12CPUDescriptorHeapManager and stored
// in QSGD3D12TextureView. The engine will copy them onto a dedicated,
@@ -1612,17 +1714,17 @@ void QSGD3D12EnginePrivate::finalizePipeline(const QSGD3D12PipelineState &pipeli
rootParams[0].Descriptor.RegisterSpace = 0;
++rootParamCount;
+ D3D12_DESCRIPTOR_RANGE tvDescRange;
if (pipelineState.shaders.rootSig.textureViewCount > 0) {
rootParams[rootParamCount].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootParams[rootParamCount].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
rootParams[rootParamCount].DescriptorTable.NumDescriptorRanges = 1;
- D3D12_DESCRIPTOR_RANGE descRange;
- descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
- descRange.NumDescriptors = pipelineState.shaders.rootSig.textureViewCount;
- descRange.BaseShaderRegister = 0; // t0, t1, ...
- descRange.RegisterSpace = 0;
- descRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
- rootParams[rootParamCount].DescriptorTable.pDescriptorRanges = &descRange;
+ tvDescRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ tvDescRange.NumDescriptors = pipelineState.shaders.rootSig.textureViewCount;
+ tvDescRange.BaseShaderRegister = 0; // t0, t1, ...
+ tvDescRange.RegisterSpace = 0;
+ tvDescRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ rootParams[rootParamCount].DescriptorTable.pDescriptorRanges = &tvDescRange;
++rootParamCount;
}
@@ -1657,7 +1759,8 @@ void QSGD3D12EnginePrivate::finalizePipeline(const QSGD3D12PipelineState &pipeli
ComPtr<ID3DBlob> signature;
ComPtr<ID3DBlob> error;
if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
- qWarning("Failed to serialize root signature");
+ QByteArray msg(static_cast<const char *>(error->GetBufferPointer()), error->GetBufferSize());
+ qWarning("Failed to serialize root signature: %s", qPrintable(msg));
return;
}
if (FAILED(device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),
@@ -1762,7 +1865,7 @@ void QSGD3D12EnginePrivate::finalizePipeline(const QSGD3D12PipelineState &pipeli
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE(pipelineState.topologyType);
psoDesc.NumRenderTargets = 1;
- psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.RTVFormats[0] = RT_COLOR_FORMAT;
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
psoDesc.SampleDesc = defaultRT[0]->GetDesc().SampleDesc;
@@ -2046,7 +2149,7 @@ void QSGD3D12EnginePrivate::ensureGPUDescriptorHeap(int cbvSrvUavDescriptorCount
while (pfd.cbvSrvUavNextFreeDescriptorIndex + cbvSrvUavDescriptorCount > newSize)
newSize *= 2;
if (newSize != pfd.gpuCbvSrvUavHeapSize) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_descheap()))
qDebug("Out of space for SRVs, creating new CBV-SRV-UAV descriptor heap with descriptor count %d", newSize);
deferredDelete(pfd.gpuCbvSrvUavHeap);
createCbvSrvUavHeap(currentPFrameIndex, newSize);
@@ -2077,6 +2180,11 @@ void QSGD3D12EnginePrivate::present()
return;
}
+#ifndef Q_OS_WINRT
+ if (dcompDevice)
+ dcompDevice->Commit();
+#endif
+
++presentFrameIndex;
}
@@ -2132,7 +2240,7 @@ void QSGD3D12EnginePrivate::releaseBuffer(uint id)
const int idx = id - 1;
Q_ASSERT(idx < buffers.count());
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug("releasing buffer %u", id);
Buffer &b(buffers[idx]);
@@ -2166,7 +2274,7 @@ void QSGD3D12EnginePrivate::resetBuffer(uint id, const quint8 *data, int size)
Q_ASSERT(idx < buffers.count() && buffers[idx].entryInUse());
Buffer &b(buffers[idx]);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug("reset buffer %u, size %d", id, size);
b.cpuDataRef.p = data;
@@ -2218,7 +2326,7 @@ uint QSGD3D12EnginePrivate::genTexture()
return id;
}
-static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha, bool mipmap,
+static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha, bool mipmap, bool force32bit,
QImage::Format *imageFormat, int *bytesPerPixel)
{
DXGI_FORMAT f = DXGI_FORMAT_R8G8B8A8_UNORM;
@@ -2230,8 +2338,12 @@ static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha,
case QImage::Format_Grayscale8:
case QImage::Format_Indexed8:
case QImage::Format_Alpha8:
- f = DXGI_FORMAT_R8_UNORM;
- bpp = 1;
+ if (!force32bit) {
+ f = DXGI_FORMAT_R8_UNORM;
+ bpp = 1;
+ } else {
+ convFormat = QImage::Format_RGBA8888;
+ }
break;
case QImage::Format_RGB32:
f = DXGI_FORMAT_B8G8R8A8_UNORM;
@@ -2307,7 +2419,9 @@ void QSGD3D12EnginePrivate::createTexture(uint id, const QSize &size, QImage::Fo
textureDesc.Height = adjustedSize.height();
textureDesc.DepthOrArraySize = 1;
textureDesc.MipLevels = !t.mipmap() ? 1 : QSGD3D12Engine::mipMapLevels(adjustedSize);
- textureDesc.Format = textureFormat(format, t.alpha(), t.mipmap(), nullptr, nullptr);
+ textureDesc.Format = textureFormat(format, t.alpha(), t.mipmap(),
+ createFlags.testFlag(QSGD3D12Engine::TextureAlways32Bit),
+ nullptr, nullptr);
textureDesc.SampleDesc.Count = 1;
textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
if (t.mipmap())
@@ -2344,7 +2458,7 @@ void QSGD3D12EnginePrivate::createTexture(uint id, const QSize &size, QImage::Fo
}
}
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("created texture %u, size %dx%d, miplevels %d", id, adjustedSize.width(), adjustedSize.height(), textureDesc.MipLevels);
}
@@ -2365,7 +2479,7 @@ void QSGD3D12EnginePrivate::queueTextureResize(uint id, const QSize &size)
return;
}
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("resizing texture %u, size %dx%d", id, size.width(), size.height());
D3D12_RESOURCE_DESC textureDesc = t.texture->GetDesc();
@@ -2417,11 +2531,12 @@ void QSGD3D12EnginePrivate::queueTextureResize(uint id, const QSize &size)
t.fenceValue = nextTextureUploadFenceValue.fetchAndAddAcquire(1) + 1;
copyCommandQueue->Signal(textureUploadFence.Get(), t.fenceValue);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("submitted old content copy for texture %u on the copy queue, fence %llu", id, t.fenceValue);
}
-void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos)
+void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos,
+ QSGD3D12Engine::TextureUploadFlags flags)
{
Q_ASSERT(id);
Q_ASSERT(images.count() == dstPos.count());
@@ -2449,7 +2564,7 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
t.fenceValue = nextTextureUploadFenceValue.fetchAndAddAcquire(1) + 1;
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("adding upload for texture %u on the copy queue, fence %llu", id, t.fenceValue);
D3D12_RESOURCE_DESC textureDesc = t.texture->GetDesc();
@@ -2458,14 +2573,16 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
int totalSize = 0;
for (const QImage &image : images) {
int bytesPerPixel;
- textureFormat(image.format(), t.alpha(), t.mipmap(), nullptr, &bytesPerPixel);
+ textureFormat(image.format(), t.alpha(), t.mipmap(),
+ flags.testFlag(QSGD3D12Engine::TextureUploadAlways32Bit),
+ nullptr, &bytesPerPixel);
const int w = !t.mipmap() ? image.width() : adjustedTextureSize.width();
const int h = !t.mipmap() ? image.height() : adjustedTextureSize.height();
const int stride = alignedSize(w * bytesPerPixel, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
totalSize += alignedSize(h * stride, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
}
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("%d sub-uploads, heap size %d bytes", images.count(), totalSize);
// Instead of individual committed resources for each upload buffer,
@@ -2490,8 +2607,10 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
for (int i = 0; i < images.count(); ++i) {
QImage::Format convFormat;
int bytesPerPixel;
- textureFormat(images[i].format(), t.alpha(), t.mipmap(), &convFormat, &bytesPerPixel);
- if (Q_UNLIKELY(debug_render() && i == 0))
+ textureFormat(images[i].format(), t.alpha(), t.mipmap(),
+ flags.testFlag(QSGD3D12Engine::TextureUploadAlways32Bit),
+ &convFormat, &bytesPerPixel);
+ if (Q_UNLIKELY(debug_texture() && i == 0))
qDebug("source image format %d, target format %d, bpp %d", images[i].format(), convFormat, bytesPerPixel);
QImage convImage = images[i].format() == convFormat ? images[i] : images[i].convertToFormat(convFormat);
@@ -2566,7 +2685,7 @@ void QSGD3D12EnginePrivate::releaseTexture(uint id)
const int idx = id - 1;
Q_ASSERT(idx < textures.count());
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("releasing texture %d", id);
Texture &t(textures[idx]);
@@ -2825,7 +2944,7 @@ void QSGD3D12EnginePrivate::createRenderTarget(uint id, const QSize &size, const
textureDesc.Height = size.height();
textureDesc.DepthOrArraySize = 1;
textureDesc.MipLevels = 1;
- textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ textureDesc.Format = RT_COLOR_FORMAT;
textureDesc.SampleDesc.Count = 1;
textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
index 2ebe1e733a..b30994fe0d 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
@@ -281,13 +281,13 @@ inline uint qHash(const QSGD3D12PipelineState &key, uint seed = 0)
+ key.topologyType;
}
-class QSGD3D12Engine : public QSGRendererInterface
+class QSGD3D12Engine
{
public:
QSGD3D12Engine();
~QSGD3D12Engine();
- bool attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples);
+ bool attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha);
void releaseResources();
bool hasResources() const;
void setWindowSize(const QSize &size, float dpr);
@@ -349,16 +349,22 @@ public:
static QSize mipMapAdjustedSourceSize(const QSize &size);
enum TextureCreateFlag {
- TextureWithAlpha = 0x1,
- TextureWithMipMaps = 0x2
+ TextureWithAlpha = 0x01,
+ TextureWithMipMaps = 0x02,
+ TextureAlways32Bit = 0x04
};
Q_DECLARE_FLAGS(TextureCreateFlags, TextureCreateFlag)
+ enum TextureUploadFlag {
+ TextureUploadAlways32Bit = 0x01
+ };
+ Q_DECLARE_FLAGS(TextureUploadFlags, TextureUploadFlag)
+
uint genTexture();
void createTexture(uint id, const QSize &size, QImage::Format format, TextureCreateFlags flags);
void queueTextureResize(uint id, const QSize &size);
- void queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos = QPoint());
- void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos);
+ void queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos = QPoint(), TextureUploadFlags flags = 0);
+ void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos, TextureUploadFlags flags = 0);
void releaseTexture(uint id);
void useTexture(uint id);
@@ -372,12 +378,7 @@ public:
void simulateDeviceLoss();
- // QSGRendererInterface
- GraphicsApi graphicsApi() const override;
- void *getResource(Resource resource) const override;
- ShaderType shaderType() const override;
- ShaderCompilationTypes shaderCompilationType() const override;
- ShaderSourceTypes shaderSourceType() const override;
+ void *getResource(QQuickWindow *window, QSGRendererInterface::Resource resource) const;
private:
QSGD3D12EnginePrivate *d;
@@ -386,6 +387,7 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::ClearFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::TextureCreateFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::TextureUploadFlags)
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h
index 6cd7cbd24e..1048ed63e7 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h
@@ -56,6 +56,7 @@
#include <d3d12.h>
#include <dxgi1_4.h>
+#include <dcomp.h>
#include <wrl/client.h>
using namespace Microsoft::WRL;
@@ -130,7 +131,7 @@ struct QSGD3D12CPUWaitableFence
class QSGD3D12EnginePrivate : public QSGD3D12DeviceManager::DeviceLossObserver
{
public:
- void initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples);
+ void initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha);
bool isInitialized() const { return initialized; }
void releaseResources();
void setWindowSize(const QSize &size, float dpr);
@@ -169,7 +170,8 @@ public:
uint genTexture();
void createTexture(uint id, const QSize &size, QImage::Format format, QSGD3D12Engine::TextureCreateFlags flags);
void queueTextureResize(uint id, const QSize &size);
- void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos);
+ void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos,
+ QSGD3D12Engine::TextureUploadFlags flags);
void releaseTexture(uint id);
void useTexture(uint id);
@@ -269,6 +271,7 @@ private:
QSize windowSize;
float windowDpr;
uint windowSamples;
+ bool windowAlpha;
int swapChainBufferCount;
int frameInFlightCount;
int waitableSwapChainMaxLatency;
@@ -432,6 +435,12 @@ private:
};
DeviceLossTester devLossTest;
+
+#ifndef Q_OS_WINRT
+ ComPtr<IDCompositionDevice> dcompDevice;
+ ComPtr<IDCompositionTarget> dcompTarget;
+ ComPtr<IDCompositionVisual> dcompVisual;
+#endif
};
inline uint qHash(const QSGD3D12EnginePrivate::PersistentFrameData::PendingRelease &pr, uint seed = 0)
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12glyphcache.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12glyphcache.cpp
index 45ef202e83..915917c3d5 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12glyphcache.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12glyphcache.cpp
@@ -42,6 +42,11 @@
QT_BEGIN_NAMESPACE
+// Convert A8 glyphs to 32-bit in the engine. This is here to work around
+// QTBUG-55330 for AMD cards.
+// If removing, textmask.hlsl must be adjusted! (.a -> .r)
+#define ALWAYS_32BIT
+
// NOTE: Avoid categorized logging. It is slow.
#define DECLARE_DEBUG_VAR(variable) \
@@ -77,7 +82,11 @@ void QSGD3D12GlyphCache::createTextureData(int width, int height)
const QImage::Format imageFormat =
m_format == QFontEngine::Format_A8 ? QImage::Format_Alpha8 : QImage::Format_ARGB32_Premultiplied;
- m_engine->createTexture(m_id, m_size, imageFormat, QSGD3D12Engine::TextureWithAlpha);
+ m_engine->createTexture(m_id, m_size, imageFormat, QSGD3D12Engine::TextureWithAlpha
+#ifdef ALWAYS_32BIT
+ | QSGD3D12Engine::TextureAlways32Bit
+#endif
+ );
}
void QSGD3D12GlyphCache::resizeTextureData(int width, int height)
@@ -146,7 +155,11 @@ void QSGD3D12GlyphCache::endFillTexture()
Q_ASSERT(m_id);
- m_engine->queueTextureUpload(m_id, m_glyphImages, m_glyphPos);
+ m_engine->queueTextureUpload(m_id, m_glyphImages, m_glyphPos
+#ifdef ALWAYS_32BIT
+ , QSGD3D12Engine::TextureUploadAlways32Bit
+#endif
+ );
// Nothing else left to do, it is up to the text material to call
// useTexture() which will then add the texture dependency to the frame.
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12imagenode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12internalimagenode.cpp
index 9bb360bc5e..aa163cacbf 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12imagenode.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12internalimagenode.cpp
@@ -37,16 +37,16 @@
**
****************************************************************************/
-#include "qsgd3d12imagenode_p.h"
+#include "qsgd3d12internalimagenode_p.h"
QT_BEGIN_NAMESPACE
-QSGD3D12ImageNode::QSGD3D12ImageNode()
+QSGD3D12InternalImageNode::QSGD3D12InternalImageNode()
{
setMaterial(&m_material);
}
-void QSGD3D12ImageNode::setFiltering(QSGTexture::Filtering filtering)
+void QSGD3D12InternalImageNode::setFiltering(QSGTexture::Filtering filtering)
{
if (m_material.filtering() == filtering)
return;
@@ -56,7 +56,7 @@ void QSGD3D12ImageNode::setFiltering(QSGTexture::Filtering filtering)
markDirty(DirtyMaterial);
}
-void QSGD3D12ImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
+void QSGD3D12InternalImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
{
if (m_material.mipmapFiltering() == filtering)
return;
@@ -66,7 +66,7 @@ void QSGD3D12ImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
markDirty(DirtyMaterial);
}
-void QSGD3D12ImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
+void QSGD3D12InternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
{
if (m_material.verticalWrapMode() == wrapMode)
return;
@@ -76,7 +76,7 @@ void QSGD3D12ImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
markDirty(DirtyMaterial);
}
-void QSGD3D12ImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
+void QSGD3D12InternalImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
{
if (m_material.horizontalWrapMode() == wrapMode)
return;
@@ -86,7 +86,7 @@ void QSGD3D12ImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
markDirty(DirtyMaterial);
}
-void QSGD3D12ImageNode::updateMaterialAntialiasing()
+void QSGD3D12InternalImageNode::updateMaterialAntialiasing()
{
if (m_antialiasing)
setMaterial(&m_smoothMaterial);
@@ -94,18 +94,18 @@ void QSGD3D12ImageNode::updateMaterialAntialiasing()
setMaterial(&m_material);
}
-void QSGD3D12ImageNode::setMaterialTexture(QSGTexture *texture)
+void QSGD3D12InternalImageNode::setMaterialTexture(QSGTexture *texture)
{
m_material.setTexture(texture);
m_smoothMaterial.setTexture(texture);
}
-QSGTexture *QSGD3D12ImageNode::materialTexture() const
+QSGTexture *QSGD3D12InternalImageNode::materialTexture() const
{
return m_material.texture();
}
-bool QSGD3D12ImageNode::updateMaterialBlending()
+bool QSGD3D12InternalImageNode::updateMaterialBlending()
{
const bool alpha = m_material.flags() & QSGMaterial::Blending;
if (materialTexture() && alpha != materialTexture()->hasAlphaChannel()) {
@@ -115,7 +115,7 @@ bool QSGD3D12ImageNode::updateMaterialBlending()
return false;
}
-bool QSGD3D12ImageNode::supportsWrap(const QSize &) const
+bool QSGD3D12InternalImageNode::supportsWrap(const QSize &) const
{
return true;
}
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12imagenode_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12internalimagenode_p.h
index ef4b38884a..26284740ee 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12imagenode_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12internalimagenode_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QSGD3D12IMAGENODE_P_H
-#define QSGD3D12IMAGENODE_P_H
+#ifndef QSGD3D12INTERNALIMAGENODE_P_H
+#define QSGD3D12INTERNALIMAGENODE_P_H
//
// W A R N I N G
@@ -51,15 +51,15 @@
// We mean it.
//
-#include <private/qsgbasicimagenode_p.h>
+#include <private/qsgbasicinternalimagenode_p.h>
#include "qsgd3d12builtinmaterials_p.h"
QT_BEGIN_NAMESPACE
-class QSGD3D12ImageNode : public QSGBasicImageNode
+class QSGD3D12InternalImageNode : public QSGBasicInternalImageNode
{
public:
- QSGD3D12ImageNode();
+ QSGD3D12InternalImageNode();
void setMipmapFiltering(QSGTexture::Filtering filtering) override;
void setFiltering(QSGTexture::Filtering filtering) override;
@@ -79,4 +79,4 @@ private:
QT_END_NAMESPACE
-#endif // QSGD3D12IMAGENODE_P_H
+#endif // QSGD3D12INTERNALIMAGENODE_P_H
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rectanglenode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12internalrectanglenode.cpp
index 7548f5cbc0..2d9c5b55d1 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12rectanglenode.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12internalrectanglenode.cpp
@@ -37,16 +37,16 @@
**
****************************************************************************/
-#include "qsgd3d12rectanglenode_p.h"
+#include "qsgd3d12internalrectanglenode_p.h"
QT_BEGIN_NAMESPACE
-QSGD3D12RectangleNode::QSGD3D12RectangleNode()
+QSGD3D12InternalRectangleNode::QSGD3D12InternalRectangleNode()
{
setMaterial(&m_material);
}
-void QSGD3D12RectangleNode::updateMaterialAntialiasing()
+void QSGD3D12InternalRectangleNode::updateMaterialAntialiasing()
{
if (m_antialiasing)
setMaterial(&m_smoothMaterial);
@@ -54,7 +54,7 @@ void QSGD3D12RectangleNode::updateMaterialAntialiasing()
setMaterial(&m_material);
}
-void QSGD3D12RectangleNode::updateMaterialBlending(QSGNode::DirtyState *state)
+void QSGD3D12InternalRectangleNode::updateMaterialBlending(QSGNode::DirtyState *state)
{
// smoothed material is always blended, so no change in material state
if (material() == &m_material) {
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rectanglenode_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12internalrectanglenode_p.h
index 95f734bc4c..2fc3c69285 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12rectanglenode_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12internalrectanglenode_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QSGD3D12RECTANGLENODE_P_H
-#define QSGD3D12RECTANGLENODE_P_H
+#ifndef QSGD3D12INTERNALRECTANGLENODE_P_H
+#define QSGD3D12INTERNALRECTANGLENODE_P_H
//
// W A R N I N G
@@ -51,15 +51,15 @@
// We mean it.
//
-#include <private/qsgbasicrectanglenode_p.h>
+#include <private/qsgbasicinternalrectanglenode_p.h>
#include "qsgd3d12builtinmaterials_p.h"
QT_BEGIN_NAMESPACE
-class QSGD3D12RectangleNode : public QSGBasicRectangleNode
+class QSGD3D12InternalRectangleNode : public QSGBasicInternalRectangleNode
{
public:
- QSGD3D12RectangleNode();
+ QSGD3D12InternalRectangleNode();
private:
void updateMaterialAntialiasing() override;
@@ -71,4 +71,4 @@ private:
QT_END_NAMESPACE
-#endif // QSGD3D12RECTANGLENODE_P_H
+#endif // QSGD3D12INTERNALRECTANGLENODE_P_H
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12painternode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12painternode.cpp
index 7837c3a2d3..b22c42f2e5 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12painternode.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12painternode.cpp
@@ -84,10 +84,9 @@ QSGD3D12PainterNode::QSGD3D12PainterNode(QQuickPaintedItem *item)
m_dirtyGeometry(false),
m_dirtyContents(false)
{
- m_material.setFlag(QSGMaterial::Blending);
+ setGeometry(&m_geometry);
m_material.setTexture(m_texture);
setMaterial(&m_material);
- setGeometry(&m_geometry);
}
QSGD3D12PainterNode::~QSGD3D12PainterNode()
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12painternode_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12painternode_p.h
index 67246cc3cd..7f4842b3a6 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12painternode_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12painternode_p.h
@@ -65,6 +65,7 @@ public:
QSGD3D12PainterTexture(QSGD3D12Engine *engine);
void bind() override;
+ bool hasAlphaChannel() const override { return true; }
QImage *image() { return &m_image; }
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes.cpp
new file mode 100644
index 0000000000..783caa280f
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes.cpp
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12publicnodes_p.h"
+
+// for rebuildGeometry
+#include <private/qsgdefaultninepatchnode_p.h>
+#include <private/qsgdefaultimagenode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGD3D12RectangleNode::QSGD3D12RectangleNode()
+ : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
+{
+ QSGGeometry::updateRectGeometry(&m_geometry, QRectF());
+ setMaterial(&m_material);
+ setGeometry(&m_geometry);
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(this, QLatin1String("rectangle"));
+#endif
+}
+
+void QSGD3D12RectangleNode::setRect(const QRectF &rect)
+{
+ QSGGeometry::updateRectGeometry(&m_geometry, rect);
+ markDirty(QSGNode::DirtyGeometry);
+}
+
+QRectF QSGD3D12RectangleNode::rect() const
+{
+ const QSGGeometry::Point2D *pts = m_geometry.vertexDataAsPoint2D();
+ return QRectF(pts[0].x,
+ pts[0].y,
+ pts[3].x - pts[0].x,
+ pts[3].y - pts[0].y);
+}
+
+void QSGD3D12RectangleNode::setColor(const QColor &color)
+{
+ if (color != m_material.color()) {
+ m_material.setColor(color);
+ markDirty(QSGNode::DirtyMaterial);
+ }
+}
+
+QColor QSGD3D12RectangleNode::color() const
+{
+ return m_material.color();
+}
+
+QSGD3D12ImageNode::QSGD3D12ImageNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4),
+ m_texCoordMode(QSGD3D12ImageNode::NoTransform),
+ m_isAtlasTexture(false),
+ m_ownsTexture(false)
+{
+ setGeometry(&m_geometry);
+ setMaterial(&m_material);
+ m_material.setMipmapFiltering(QSGTexture::None);
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(this, QLatin1String("image"));
+#endif
+}
+
+QSGD3D12ImageNode::~QSGD3D12ImageNode()
+{
+ if (m_ownsTexture)
+ delete m_material.texture();
+}
+
+void QSGD3D12ImageNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture::Filtering QSGD3D12ImageNode::filtering() const
+{
+ return m_material.filtering();
+}
+
+void QSGD3D12ImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.mipmapFiltering() == filtering)
+ return;
+
+ m_material.setMipmapFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture::Filtering QSGD3D12ImageNode::mipmapFiltering() const
+{
+ return m_material.mipmapFiltering();
+}
+
+void QSGD3D12ImageNode::setRect(const QRectF &r)
+{
+ if (m_rect == r)
+ return;
+
+ m_rect = r;
+ QSGDefaultImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode);
+ markDirty(DirtyGeometry);
+}
+
+QRectF QSGD3D12ImageNode::rect() const
+{
+ return m_rect;
+}
+
+void QSGD3D12ImageNode::setSourceRect(const QRectF &r)
+{
+ if (m_sourceRect == r)
+ return;
+
+ m_sourceRect = r;
+ QSGDefaultImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode);
+ markDirty(DirtyGeometry);
+}
+
+QRectF QSGD3D12ImageNode::sourceRect() const
+{
+ return m_sourceRect;
+}
+
+void QSGD3D12ImageNode::setTexture(QSGTexture *texture)
+{
+ Q_ASSERT(texture);
+
+ if (m_ownsTexture)
+ delete m_material.texture();
+
+ m_material.setTexture(texture);
+ QSGDefaultImageNode::rebuildGeometry(&m_geometry, texture, m_rect, m_sourceRect, m_texCoordMode);
+
+ DirtyState dirty = DirtyMaterial;
+ const bool wasAtlas = m_isAtlasTexture;
+ m_isAtlasTexture = texture->isAtlasTexture();
+ if (wasAtlas || m_isAtlasTexture)
+ dirty |= DirtyGeometry;
+
+ markDirty(dirty);
+}
+
+QSGTexture *QSGD3D12ImageNode::texture() const
+{
+ return m_material.texture();
+}
+
+void QSGD3D12ImageNode::setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode)
+{
+ if (m_texCoordMode == mode)
+ return;
+
+ m_texCoordMode = mode;
+ QSGDefaultImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode);
+ markDirty(DirtyMaterial);
+}
+
+QSGD3D12ImageNode::TextureCoordinatesTransformMode QSGD3D12ImageNode::textureCoordinatesTransform() const
+{
+ return m_texCoordMode;
+}
+
+void QSGD3D12ImageNode::setOwnsTexture(bool owns)
+{
+ m_ownsTexture = owns;
+}
+
+bool QSGD3D12ImageNode::ownsTexture() const
+{
+ return m_ownsTexture;
+}
+
+QSGD3D12NinePatchNode::QSGD3D12NinePatchNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ m_geometry.setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ setGeometry(&m_geometry);
+ setMaterial(&m_material);
+}
+
+QSGD3D12NinePatchNode::~QSGD3D12NinePatchNode()
+{
+ delete m_material.texture();
+}
+
+void QSGD3D12NinePatchNode::setTexture(QSGTexture *texture)
+{
+ delete m_material.texture();
+ m_material.setTexture(texture);
+}
+
+void QSGD3D12NinePatchNode::setBounds(const QRectF &bounds)
+{
+ m_bounds = bounds;
+}
+
+void QSGD3D12NinePatchNode::setDevicePixelRatio(qreal ratio)
+{
+ m_devicePixelRatio = ratio;
+}
+
+void QSGD3D12NinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom)
+{
+ m_padding = QVector4D(left, top, right, bottom);
+}
+
+void QSGD3D12NinePatchNode::update()
+{
+ QSGDefaultNinePatchNode::rebuildGeometry(m_material.texture(), &m_geometry, m_padding, m_bounds, m_devicePixelRatio);
+ markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes_p.h
new file mode 100644
index 0000000000..6150083aaf
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12PUBLICNODES_P_H
+#define QSGD3D12PUBLICNODES_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/qsgrectanglenode.h>
+#include <QtQuick/qsgimagenode.h>
+#include <QtQuick/qsgninepatchnode.h>
+#include "qsgd3d12builtinmaterials_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12RectangleNode : public QSGRectangleNode
+{
+public:
+ QSGD3D12RectangleNode();
+
+ void setRect(const QRectF &rect) override;
+ QRectF rect() const override;
+
+ void setColor(const QColor &color) override;
+ QColor color() const override;
+
+private:
+ QSGGeometry m_geometry;
+ QSGD3D12FlatColorMaterial m_material;
+};
+
+class QSGD3D12ImageNode : public QSGImageNode
+{
+public:
+ QSGD3D12ImageNode();
+ ~QSGD3D12ImageNode();
+
+ void setRect(const QRectF &rect) override;
+ QRectF rect() const override;
+
+ void setSourceRect(const QRectF &r) override;
+ QRectF sourceRect() const override;
+
+ void setTexture(QSGTexture *texture) override;
+ QSGTexture *texture() const override;
+
+ void setFiltering(QSGTexture::Filtering filtering) override;
+ QSGTexture::Filtering filtering() const override;
+
+ void setMipmapFiltering(QSGTexture::Filtering filtering) override;
+ QSGTexture::Filtering mipmapFiltering() const override;
+
+ void setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode) override;
+ TextureCoordinatesTransformMode textureCoordinatesTransform() const override;
+
+ void setOwnsTexture(bool owns) override;
+ bool ownsTexture() const override;
+
+private:
+ QSGGeometry m_geometry;
+ QSGD3D12TextureMaterial m_material;
+ QRectF m_rect;
+ QRectF m_sourceRect;
+ TextureCoordinatesTransformMode m_texCoordMode;
+ uint m_isAtlasTexture : 1;
+ uint m_ownsTexture : 1;
+};
+
+class QSGD3D12NinePatchNode : public QSGNinePatchNode
+{
+public:
+ QSGD3D12NinePatchNode();
+ ~QSGD3D12NinePatchNode();
+
+ void setTexture(QSGTexture *texture) override;
+ void setBounds(const QRectF &bounds) override;
+ void setDevicePixelRatio(qreal ratio) override;
+ void setPadding(qreal left, qreal top, qreal right, qreal bottom) override;
+ void update() override;
+
+private:
+ QSGGeometry m_geometry;
+ QSGD3D12TextureMaterial m_material;
+ QRectF m_bounds;
+ qreal m_devicePixelRatio;
+ QVector4D m_padding;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
index b32bfe063a..4ee4656e63 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
@@ -64,8 +64,22 @@ bool QSGD3D12RenderContext::isValid() const
return m_engine != nullptr;
}
+void QSGD3D12RenderContext::initialize(void *)
+{
+ if (m_initialized)
+ return;
+
+ m_initialized = true;
+ emit initialized();
+}
+
void QSGD3D12RenderContext::invalidate()
{
+ if (!m_initialized)
+ return;
+
+ m_initialized = false;
+
if (Q_UNLIKELY(debug_render()))
qDebug("rendercontext invalidate engine %p, %d/%d/%d", m_engine,
m_texturesToDelete.count(), m_textures.count(), m_fontEnginesToClean.count());
@@ -101,6 +115,11 @@ QSGRenderer *QSGD3D12RenderContext::createRenderer()
return new QSGD3D12Renderer(this);
}
+int QSGD3D12RenderContext::maxTextureSize() const
+{
+ return 16384; // D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
+}
+
void QSGD3D12RenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo)
{
static_cast<QSGD3D12Renderer *>(renderer)->renderScene(fbo);
@@ -114,16 +133,37 @@ void QSGD3D12RenderContext::setEngine(QSGD3D12Engine *engine)
m_engine = engine;
if (m_engine)
- emit initialized();
+ initialize(nullptr);
}
-void QSGD3D12RenderContext::ensureInitializedEmitted()
+QSGRendererInterface::GraphicsApi QSGD3D12RenderContext::graphicsApi() const
{
- if (!m_pendingInitialized)
- return;
+ return Direct3D12;
+}
- m_pendingInitialized = false;
- emit initialized();
+void *QSGD3D12RenderContext::getResource(QQuickWindow *window, Resource resource) const
+{
+ if (!m_engine) {
+ qWarning("getResource: No D3D12 engine available yet (window not exposed?)");
+ return nullptr;
+ }
+ // window can be ignored since the rendercontext and engine are both per window
+ return m_engine->getResource(window, resource);
+}
+
+QSGRendererInterface::ShaderType QSGD3D12RenderContext::shaderType() const
+{
+ return HLSL;
+}
+
+QSGRendererInterface::ShaderCompilationTypes QSGD3D12RenderContext::shaderCompilationType() const
+{
+ return RuntimeCompilation | OfflineCompilation;
+}
+
+QSGRendererInterface::ShaderSourceTypes QSGD3D12RenderContext::shaderSourceType() const
+{
+ return ShaderSourceString | ShaderSourceFile | ShaderByteCode;
}
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
index 86a300831d..35aca100f4 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
@@ -52,30 +52,37 @@
//
#include <private/qsgcontext_p.h>
+#include <qsgrendererinterface.h>
QT_BEGIN_NAMESPACE
class QSGD3D12Engine;
-class QSGD3D12RenderContext : public QSGRenderContext
+class QSGD3D12RenderContext : public QSGRenderContext, public QSGRendererInterface
{
public:
QSGD3D12RenderContext(QSGContext *ctx);
bool isValid() const override;
+ void initialize(void *context) override;
void invalidate() override;
void renderNextFrame(QSGRenderer *renderer, uint fbo) override;
QSGTexture *createTexture(const QImage &image, uint flags) const override;
QSGRenderer *createRenderer() override;
+ int maxTextureSize() const override;
void setEngine(QSGD3D12Engine *engine);
QSGD3D12Engine *engine() { return m_engine; }
- void ensureInitializedEmitted();
- void setInitializedPending() { m_pendingInitialized = true; }
+ // QSGRendererInterface
+ GraphicsApi graphicsApi() const override;
+ void *getResource(QQuickWindow *window, Resource resource) const override;
+ ShaderType shaderType() const override;
+ ShaderCompilationTypes shaderCompilationType() const override;
+ ShaderSourceTypes shaderSourceType() const override;
private:
QSGD3D12Engine *m_engine = nullptr;
- bool m_pendingInitialized = false;
+ bool m_initialized = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp
index 5e5d7a13f8..ce633ae996 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp
@@ -451,6 +451,7 @@ struct RenderNodeState : public QSGRenderNode::RenderState
bool scissorEnabled() const { return m_scissorEnabled; }
int stencilValue() const { return m_stencilValue; }
bool stencilEnabled() const { return m_stencilEnabled; }
+ const QRegion *clipRegion() const override { return nullptr; }
const QMatrix4x4 *m_projectionMatrix;
QRect m_scissorRect;
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
index 067b0d35f6..c53a1fa6c1 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
@@ -42,16 +42,12 @@
#include "qsgd3d12context_p.h"
#include "qsgd3d12rendercontext_p.h"
#include "qsgd3d12shadereffectnode_p.h"
-#include <private/qsgrenderer_p.h>
#include <private/qquickwindow_p.h>
#include <private/qquickprofiler_p.h>
#include <private/qquickanimatorcontroller_p.h>
-#include <private/qquickprofiler_p.h>
-#include <private/qqmldebugserviceinterfaces_p.h>
-#include <private/qqmldebugconnector_p.h>
#include <QElapsedTimer>
-#include <QQueue>
#include <QGuiApplication>
+#include <QScreen>
QT_BEGIN_NAMESPACE
@@ -64,140 +60,9 @@ QT_BEGIN_NAMESPACE
DECLARE_DEBUG_VAR(loop)
DECLARE_DEBUG_VAR(time)
-/*
- The D3D render loop mostly mirrors the threaded OpenGL render loop.
-
- There are two classes here. QSGD3D12RenderLoop and QSGD3D12RenderThread. All
- communication between the two is based on event passing and we have a number
- of custom events.
-
- Render loop is per process, render thread is per window. The
- QSGD3D12RenderContext and QSGD3D12Engine are per window as well. The former
- is created (but not owned) by QQuickWindow. The D3D device is per process.
-
- In this implementation, the render thread is never blocked and the GUI
- thread will initiate a polishAndSync which will block and wait for the
- render thread to pick it up and release the block only after the render
- thread is done syncing. The reason for this is:
-
- 1. Clear blocking paradigm. We only have one real "block" point
- (polishAndSync()) and all blocking is initiated by GUI and picked up by
- Render at specific times based on events. This makes the execution
- deterministic.
-
- 2. Render does not have to interact with GUI. This is done so that the
- render thread can run its own animation system which stays alive even when
- the GUI thread is blocked doing I/O, object instantiation, QPainter-painting
- or any other non-trivial task.
-
- The render thread has affinity to the GUI thread until a window is shown.
- From that moment and until the window is destroyed, it will have affinity to
- the render thread. (moved back at the end of run for cleanup).
- */
-
-// Passed from the RL to the RT when a window is removed obscured and should be
-// removed from the render loop.
-const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1);
-
-// Passed from the RL to RT when GUI has been locked, waiting for sync.
-const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2);
-
-// Passed by the RT to itself to trigger another render pass. This is typically
-// a result of QQuickWindow::update().
-const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3);
-
-// Passed by the RL to the RT to maybe release resource if no windows are
-// rendering.
-const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4);
-
-// Passed by the RL to the RT when a QQuickWindow::grabWindow() is called.
-const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5);
-// Passed by the window when there is a render job to run.
-const QEvent::Type WM_PostJob = QEvent::Type(QEvent::User + 6);
-
-class QSGD3D12WindowEvent : public QEvent
-{
-public:
- QSGD3D12WindowEvent(QQuickWindow *c, QEvent::Type type) : QEvent(type), window(c) { }
- QQuickWindow *window;
-};
-
-class QSGD3D12TryReleaseEvent : public QSGD3D12WindowEvent
-{
-public:
- QSGD3D12TryReleaseEvent(QQuickWindow *win, bool destroy)
- : QSGD3D12WindowEvent(win, WM_TryRelease), destroying(destroy) { }
- bool destroying;
-};
-
-class QSGD3D12SyncEvent : public QSGD3D12WindowEvent
-{
-public:
- QSGD3D12SyncEvent(QQuickWindow *c, bool inExpose, bool force)
- : QSGD3D12WindowEvent(c, WM_RequestSync)
- , size(c->size())
- , dpr(c->effectiveDevicePixelRatio())
- , syncInExpose(inExpose)
- , forceRenderPass(force) { }
- QSize size;
- float dpr;
- bool syncInExpose;
- bool forceRenderPass;
-};
-
-class QSGD3D12GrabEvent : public QSGD3D12WindowEvent
-{
-public:
- QSGD3D12GrabEvent(QQuickWindow *c, QImage *result)
- : QSGD3D12WindowEvent(c, WM_Grab), image(result) { }
- QImage *image;
-};
-
-class QSGD3D12JobEvent : public QSGD3D12WindowEvent
-{
-public:
- QSGD3D12JobEvent(QQuickWindow *c, QRunnable *postedJob)
- : QSGD3D12WindowEvent(c, WM_PostJob), job(postedJob) { }
- ~QSGD3D12JobEvent() { delete job; }
- QRunnable *job;
-};
-
-class QSGD3D12EventQueue : public QQueue<QEvent *>
-{
-public:
- void addEvent(QEvent *e) {
- mutex.lock();
- enqueue(e);
- if (waiting)
- condition.wakeOne();
- mutex.unlock();
- }
-
- QEvent *takeEvent(bool wait) {
- mutex.lock();
- if (isEmpty() && wait) {
- waiting = true;
- condition.wait(&mutex);
- waiting = false;
- }
- QEvent *e = dequeue();
- mutex.unlock();
- return e;
- }
-
- bool hasMoreEvents() {
- mutex.lock();
- bool has = !isEmpty();
- mutex.unlock();
- return has;
- }
-
-private:
- QMutex mutex;
- QWaitCondition condition;
- bool waiting = false;
-};
+// This render loop operates on the gui (main) thread.
+// Conceptually it matches the OpenGL 'windows' render loop.
static inline int qsgrl_animation_interval()
{
@@ -205,648 +70,206 @@ static inline int qsgrl_animation_interval()
return refreshRate < 1 ? 16 : int(1000 / refreshRate);
}
-class QSGD3D12RenderThread : public QThread
-{
- Q_OBJECT
-
-public:
- QSGD3D12RenderThread(QSGD3D12RenderLoop *rl, QSGRenderContext *renderContext)
- : renderLoop(rl)
- {
- rc = static_cast<QSGD3D12RenderContext *>(renderContext);
- vsyncDelta = qsgrl_animation_interval();
- }
-
- ~QSGD3D12RenderThread()
- {
- delete rc;
- }
-
- bool event(QEvent *e);
- void run();
-
- void syncAndRender();
- void sync(bool inExpose);
-
- void requestRepaint()
- {
- if (sleeping)
- stopEventProcessing = true;
- if (exposedWindow)
- pendingUpdate |= RepaintRequest;
- }
-
- void processEventsAndWaitForMore();
- void processEvents();
- void postEvent(QEvent *e);
-
- enum UpdateRequest {
- SyncRequest = 0x01,
- RepaintRequest = 0x02,
- ExposeRequest = 0x04 | RepaintRequest | SyncRequest
- };
-
- QSGD3D12Engine *engine = nullptr;
- QSGD3D12RenderLoop *renderLoop;
- QSGD3D12RenderContext *rc;
- QAnimationDriver *rtAnim = nullptr;
- volatile bool active = false;
- uint pendingUpdate = 0;
- bool sleeping = false;
- bool syncResultedInChanges = false;
- float vsyncDelta;
- QMutex mutex;
- QWaitCondition waitCondition;
- QQuickWindow *exposedWindow = nullptr;
- bool stopEventProcessing = false;
- QSGD3D12EventQueue eventQueue;
- QElapsedTimer threadTimer;
- qint64 syncTime;
- qint64 renderTime;
- qint64 sinceLastTime;
-
-public slots:
- void onSceneGraphChanged() {
- syncResultedInChanges = true;
- }
-};
-
-bool QSGD3D12RenderThread::event(QEvent *e)
+QSGD3D12RenderLoop::QSGD3D12RenderLoop()
{
- switch (e->type()) {
-
- case WM_Obscure:
- Q_ASSERT(!exposedWindow || exposedWindow == static_cast<QSGD3D12WindowEvent *>(e)->window);
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "RT - WM_Obscure" << exposedWindow;
- mutex.lock();
- if (exposedWindow) {
- QQuickWindowPrivate::get(exposedWindow)->fireAboutToStop();
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_Obscure - window removed");
- exposedWindow = nullptr;
- }
- waitCondition.wakeOne();
- mutex.unlock();
- return true;
-
- case WM_RequestSync: {
- QSGD3D12SyncEvent *wme = static_cast<QSGD3D12SyncEvent *>(e);
- if (sleeping)
- stopEventProcessing = true;
- // One thread+engine for each window. However, the native window may
- // change in some (quite artificial) cases, e.g. due to a hide -
- // destroy - show on the QWindow.
- bool needsWindow = !engine->window();
- if (engine->window() && engine->window() != wme->window->winId()) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_RequestSync - native window handle changes for active engine");
- engine->waitGPU();
- QQuickWindowPrivate::get(wme->window)->cleanupNodesOnShutdown();
- QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
- rc->invalidate();
- engine->releaseResources();
- needsWindow = true;
- // Be nice and emit the rendercontext's initialized() later on at
- // some point so that QQuickWindow::sceneGraphInitialized() behaves
- // in a manner similar to GL.
- rc->setInitializedPending();
- }
- if (needsWindow) {
- // Must only ever get here when there is no window or releaseResources() has been called.
- const int samples = wme->window->format().samples();
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "RT - WM_RequestSync - initializing D3D12 engine" << wme->window
- << wme->size << wme->dpr << samples;
- engine->attachToWindow(wme->window->winId(), wme->size, wme->dpr, samples);
- }
- exposedWindow = wme->window;
- engine->setWindowSize(wme->size, wme->dpr);
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "RT - WM_RequestSync" << exposedWindow;
- pendingUpdate |= SyncRequest;
- if (wme->syncInExpose) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_RequestSync - triggered from expose");
- pendingUpdate |= ExposeRequest;
- }
- if (wme->forceRenderPass) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_RequestSync - repaint regardless");
- pendingUpdate |= RepaintRequest;
- }
- return true;
- }
-
- case WM_TryRelease: {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_TryRelease");
- mutex.lock();
- renderLoop->lockedForSync = true;
- QSGD3D12TryReleaseEvent *wme = static_cast<QSGD3D12TryReleaseEvent *>(e);
- // Only when no windows are exposed anymore or we are shutting down.
- if (!exposedWindow || wme->destroying) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_TryRelease - invalidating rc");
- if (wme->window) {
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window);
- if (wme->destroying) {
- // QSGNode destruction may release graphics resources in use so wait first.
- engine->waitGPU();
- // Bye bye nodes...
- wd->cleanupNodesOnShutdown();
- QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
- }
- rc->invalidate();
- QCoreApplication::processEvents();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- if (wme->destroying)
- delete wd->animationController;
- }
- if (wme->destroying)
- active = false;
- if (sleeping)
- stopEventProcessing = true;
- } else {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_TryRelease - not releasing because window is still active");
- }
- waitCondition.wakeOne();
- renderLoop->lockedForSync = false;
- mutex.unlock();
- return true;
- }
-
- case WM_Grab: {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_Grab");
- QSGD3D12GrabEvent *wme = static_cast<QSGD3D12GrabEvent *>(e);
- Q_ASSERT(wme->window);
- Q_ASSERT(wme->window == exposedWindow || !exposedWindow);
- mutex.lock();
- if (wme->window) {
- // Grabbing is generally done by rendering a frame and reading the
- // color buffer contents back, without presenting, and then
- // creating a QImage from the returned data. It is terribly
- // inefficient since it involves a full blocking wait for the GPU.
- // However, our hands are tied by the existing, synchronous APIs of
- // QQuickWindow and such.
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window);
- rc->ensureInitializedEmitted();
- wd->syncSceneGraph();
- wd->renderSceneGraph(wme->window->size());
- *wme->image = engine->executeAndWaitReadbackRenderTarget();
- }
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_Grab - waking gui to handle result");
- waitCondition.wakeOne();
- mutex.unlock();
- return true;
- }
-
- case WM_PostJob: {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_PostJob");
- QSGD3D12JobEvent *wme = static_cast<QSGD3D12JobEvent *>(e);
- Q_ASSERT(wme->window == exposedWindow);
- if (exposedWindow) {
- wme->job->run();
- delete wme->job;
- wme->job = nullptr;
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_PostJob - job done");
- }
- return true;
- }
-
- case WM_RequestRepaint:
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_RequestPaint");
- // When GUI posts this event, it is followed by a polishAndSync, so we
- // must not exit the event loop yet.
- pendingUpdate |= RepaintRequest;
- break;
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("new d3d12 render loop");
- default:
- break;
- }
+ sg = new QSGD3D12Context;
- return QThread::event(e);
-}
+ m_anims = sg->createAnimationDriver(this);
+ connect(m_anims, &QAnimationDriver::started, this, &QSGD3D12RenderLoop::onAnimationStarted);
+ connect(m_anims, &QAnimationDriver::stopped, this, &QSGD3D12RenderLoop::onAnimationStopped);
+ m_anims->install();
-void QSGD3D12RenderThread::postEvent(QEvent *e)
-{
- eventQueue.addEvent(e);
+ m_vsyncDelta = qsgrl_animation_interval();
}
-void QSGD3D12RenderThread::processEvents()
+QSGD3D12RenderLoop::~QSGD3D12RenderLoop()
{
- while (eventQueue.hasMoreEvents()) {
- QEvent *e = eventQueue.takeEvent(false);
- event(e);
- delete e;
- }
+ delete sg;
}
-void QSGD3D12RenderThread::processEventsAndWaitForMore()
+void QSGD3D12RenderLoop::show(QQuickWindow *window)
{
- stopEventProcessing = false;
- while (!stopEventProcessing) {
- QEvent *e = eventQueue.takeEvent(true);
- event(e);
- delete e;
- }
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "show" << window;
}
-void QSGD3D12RenderThread::run()
+void QSGD3D12RenderLoop::hide(QQuickWindow *window)
{
if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - run()");
-
- engine = new QSGD3D12Engine;
- rc->setEngine(engine);
-
- rtAnim = rc->sceneGraphContext()->createAnimationDriver(nullptr);
- rtAnim->install();
-
- if (QQmlDebugConnector::service<QQmlProfilerService>())
- QQuickProfiler::registerAnimationCallback();
-
- while (active) {
- if (exposedWindow)
- syncAndRender();
-
- processEvents();
- QCoreApplication::processEvents();
-
- if (pendingUpdate == 0 || !exposedWindow) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - done drawing, sleep");
- sleeping = true;
- processEventsAndWaitForMore();
- sleeping = false;
- }
- }
-
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - run() exiting");
-
- delete rtAnim;
- rtAnim = nullptr;
-
- rc->moveToThread(renderLoop->thread());
- moveToThread(renderLoop->thread());
-
- rc->setEngine(nullptr);
- delete engine;
- engine = nullptr;
+ qDebug() << "hide" << window;
}
-void QSGD3D12RenderThread::sync(bool inExpose)
+void QSGD3D12RenderLoop::resize(QQuickWindow *window)
{
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - sync");
-
- mutex.lock();
- Q_ASSERT_X(renderLoop->lockedForSync, "QSGD3D12RenderThread::sync()", "sync triggered with gui not locked");
-
- // Recover from device loss.
- if (!engine->hasResources()) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - sync - device was lost, resetting scenegraph");
- QQuickWindowPrivate::get(exposedWindow)->cleanupNodesOnShutdown();
- QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
- rc->invalidate();
- }
-
- if (engine->window()) {
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow);
- bool hadRenderer = wd->renderer != nullptr;
- // If the scene graph was touched since the last sync() make sure it sends the
- // changed signal.
- if (wd->renderer)
- wd->renderer->clearChangedFlag();
+ if (!m_windows.contains(window) || window->size().isEmpty())
+ return;
- rc->ensureInitializedEmitted();
- wd->syncSceneGraph();
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "resize" << window;
- if (!hadRenderer && wd->renderer) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - created renderer");
- syncResultedInChanges = true;
- connect(wd->renderer, &QSGRenderer::sceneGraphChanged, this,
- &QSGD3D12RenderThread::onSceneGraphChanged, Qt::DirectConnection);
- }
+ const WindowData &data(m_windows[window]);
- // Process deferred deletes now, directly after the sync as deleteLater
- // on the GUI must now also have resulted in SG changes and the delete
- // is a safe operation.
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- }
+ if (!data.exposed)
+ return;
- if (!inExpose) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - sync complete, waking gui");
- waitCondition.wakeOne();
- mutex.unlock();
- }
+ if (data.engine)
+ data.engine->setWindowSize(window->size(), window->effectiveDevicePixelRatio());
}
-void QSGD3D12RenderThread::syncAndRender()
+void QSGD3D12RenderLoop::windowDestroyed(QQuickWindow *window)
{
- if (Q_UNLIKELY(debug_time())) {
- sinceLastTime = threadTimer.nsecsElapsed();
- threadTimer.start();
- }
- Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame);
-
- QElapsedTimer waitTimer;
- waitTimer.start();
-
if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - syncAndRender()");
-
- syncResultedInChanges = false;
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow);
-
- const bool repaintRequested = (pendingUpdate & RepaintRequest) || wd->customRenderStage;
- const bool syncRequested = pendingUpdate & SyncRequest;
- const bool exposeRequested = (pendingUpdate & ExposeRequest) == ExposeRequest;
- pendingUpdate = 0;
-
- if (syncRequested)
- sync(exposeRequested);
-
-#ifndef QSG_NO_RENDER_TIMING
- if (Q_UNLIKELY(debug_time()))
- syncTime = threadTimer.nsecsElapsed();
-#endif
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+ qDebug() << "window destroyed" << window;
- if (!syncResultedInChanges && !repaintRequested) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - no changes, render aborted");
- int waitTime = vsyncDelta - (int) waitTimer.elapsed();
- if (waitTime > 0)
- msleep(waitTime);
+ if (!m_windows.contains(window))
return;
- }
-
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - rendering started");
-
- if (rtAnim->isRunning()) {
- wd->animationController->lock();
- rtAnim->advance();
- wd->animationController->unlock();
- }
-
- bool canRender = wd->renderer != nullptr;
- // Recover from device loss.
- if (!engine->hasResources()) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - syncAndRender - device was lost, posting FullUpdateRequest");
- // Cannot do anything here because gui is not locked. Request a new
- // sync+render round on the gui thread and let the sync handle it.
- QCoreApplication::postEvent(exposedWindow, new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)));
- canRender = false;
- }
-
- if (canRender) {
- wd->renderSceneGraph(engine->windowSize());
- if (Q_UNLIKELY(debug_time()))
- renderTime = threadTimer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
- // The engine is able to have multiple frames in flight. This in effect is
- // similar to BufferQueueingOpenGL. Provide an env var to force the
- // traditional blocking swap behavior, just in case.
- static bool blockOnEachFrame = qEnvironmentVariableIntValue("QT_D3D_BLOCKING_PRESENT") != 0;
-
- if (!wd->customRenderStage || !wd->customRenderStage->swap())
- engine->present();
-
- if (blockOnEachFrame)
- engine->waitGPU();
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ wd->fireAboutToStop();
- // The concept of "frame swaps" is quite misleading by default, when
- // blockOnEachFrame is not used, but emit it for compatibility.
- wd->fireFrameSwapped();
- } else {
- Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame, 1);
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - window not ready, skipping render");
- }
+ WindowData &data(m_windows[window]);
+ QSGD3D12Engine *engine = data.engine;
+ QSGD3D12RenderContext *rc = data.rc;
+ m_windows.remove(window);
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - rendering done");
+ // QSGNode destruction may release graphics resources in use so wait first.
+ engine->waitGPU();
- if (exposeRequested) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - wake gui after initial expose");
- waitCondition.wakeOne();
- mutex.unlock();
- }
+ // Bye bye nodes...
+ wd->cleanupNodesOnShutdown();
- if (Q_UNLIKELY(debug_time()))
- qDebug("Frame rendered with 'd3d12' renderloop in %dms, sync=%d, render=%d, swap=%d - (on render thread)",
- int(threadTimer.elapsed()),
- int((syncTime/1000000)),
- int((renderTime - syncTime) / 1000000),
- int(threadTimer.elapsed() - renderTime / 1000000));
+ QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
- Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame);
+ rc->invalidate();
- static int devLossTest = qEnvironmentVariableIntValue("QT_D3D_TEST_DEVICE_LOSS");
- if (devLossTest > 0) {
- static QElapsedTimer kt;
- static bool timerRunning = false;
- if (!timerRunning) {
- kt.start();
- timerRunning = true;
- } else if (kt.elapsed() > 5000) {
- --devLossTest;
- kt.restart();
- engine->simulateDeviceLoss();
- }
- }
-}
-
-template<class T> T *windowFor(const QVector<T> &list, QQuickWindow *window)
-{
- for (const T &t : list) {
- if (t.window == window)
- return const_cast<T *>(&t);
- }
- return nullptr;
-}
-
-QSGD3D12RenderLoop::QSGD3D12RenderLoop()
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug("new d3d12 render loop ctor");
+ if (m_windows.isEmpty())
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- sg = new QSGD3D12Context;
+ delete rc;
+ delete engine;
- anim = sg->createAnimationDriver(this);
- connect(anim, &QAnimationDriver::started, this, &QSGD3D12RenderLoop::onAnimationStarted);
- connect(anim, &QAnimationDriver::stopped, this, &QSGD3D12RenderLoop::onAnimationStopped);
- anim->install();
+ delete wd->animationController;
}
-QSGD3D12RenderLoop::~QSGD3D12RenderLoop()
+void QSGD3D12RenderLoop::exposeWindow(QQuickWindow *window)
{
- if (Q_UNLIKELY(debug_loop()))
- qDebug("new d3d12 render loop dtor");
+ WindowData data;
+ data.exposed = true;
+ data.engine = new QSGD3D12Engine;
+ data.rc = static_cast<QSGD3D12RenderContext *>(QQuickWindowPrivate::get(window)->context);
+ data.rc->setEngine(data.engine);
+ m_windows[window] = data;
- delete sg;
-}
+ const int samples = window->format().samples();
+ const bool alpha = window->format().alphaBufferSize() > 0;
+ const qreal dpr = window->effectiveDevicePixelRatio();
-void QSGD3D12RenderLoop::show(QQuickWindow *window)
-{
if (Q_UNLIKELY(debug_loop()))
- qDebug() << "show" << window;
-}
+ qDebug() << "initializing D3D12 engine" << window << window->size() << dpr << samples << alpha;
-void QSGD3D12RenderLoop::hide(QQuickWindow *window)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "hide" << window;
-
- if (window->isExposed())
- handleObscurity(windowFor(windows, window));
-
- releaseResources(window);
+ data.engine->attachToWindow(window->winId(), window->size(), dpr, samples, alpha);
}
-void QSGD3D12RenderLoop::resize(QQuickWindow *window)
+void QSGD3D12RenderLoop::obscureWindow(QQuickWindow *window)
{
- if (!window->isExposed() || window->size().isEmpty())
- return;
-
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "resize" << window << window->size();
+ m_windows[window].exposed = false;
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ wd->fireAboutToStop();
}
-void QSGD3D12RenderLoop::windowDestroyed(QQuickWindow *window)
+void QSGD3D12RenderLoop::exposureChanged(QQuickWindow *window)
{
if (Q_UNLIKELY(debug_loop()))
- qDebug() << "window destroyed" << window;
+ qDebug() << "exposure changed" << window << window->isExposed();
- WindowData *w = windowFor(windows, window);
- if (!w)
- return;
+ if (window->isExposed()) {
+ if (!m_windows.contains(window))
+ exposeWindow(window);
- handleObscurity(w);
- handleResourceRelease(w, true);
+ // Stop non-visual animation timer as we now have a window rendering.
+ if (m_animationTimer && somethingVisible()) {
+ killTimer(m_animationTimer);
+ m_animationTimer = 0;
+ }
+ // If we have a pending timer and we get an expose, we need to stop it.
+ // Otherwise we get two frames and two animation ticks in the same time interval.
+ if (m_updateTimer) {
+ killTimer(m_updateTimer);
+ m_updateTimer = 0;
+ }
- QSGD3D12RenderThread *thread = w->thread;
- while (thread->isRunning())
- QThread::yieldCurrentThread();
+ WindowData &data(m_windows[window]);
+ data.exposed = true;
+ data.updatePending = true;
- Q_ASSERT(thread->thread() == QThread::currentThread());
- delete thread;
+ render();
- for (int i = 0; i < windows.size(); ++i) {
- if (windows.at(i).window == window) {
- windows.removeAt(i);
- break;
- }
- }
-}
-
-void QSGD3D12RenderLoop::exposureChanged(QQuickWindow *window)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "exposure changed" << window;
+ } else if (m_windows.contains(window)) {
+ obscureWindow(window);
- if (window->isExposed()) {
- handleExposure(window);
- } else {
- WindowData *w = windowFor(windows, window);
- if (w)
- handleObscurity(w);
+ // Potentially start the non-visual animation timer if nobody is rendering.
+ if (m_anims->isRunning() && !somethingVisible() && !m_animationTimer)
+ m_animationTimer = startTimer(m_vsyncDelta);
}
}
QImage QSGD3D12RenderLoop::grab(QQuickWindow *window)
{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "grab" << window;
-
- WindowData *w = windowFor(windows, window);
- // Have to support invisible (but created()'ed) windows as well.
- // Unlike with GL, leaving that case for QQuickWindow to handle is not feasible.
- const bool tempExpose = !w;
- if (tempExpose) {
- handleExposure(window);
- w = windowFor(windows, window);
- Q_ASSERT(w);
- }
-
- if (!w->thread->isRunning())
- return QImage();
-
- if (!window->handle())
- window->create();
+ const bool tempExpose = !m_windows.contains(window);
+ if (tempExpose)
+ exposeWindow(window);
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
- wd->polishItems();
+ m_windows[window].grabOnly = true;
- QImage result;
- w->thread->mutex.lock();
- lockedForSync = true;
- w->thread->postEvent(new QSGD3D12GrabEvent(window, &result));
- w->thread->waitCondition.wait(&w->thread->mutex);
- lockedForSync = false;
- w->thread->mutex.unlock();
+ renderWindow(window);
- result.setDevicePixelRatio(window->effectiveDevicePixelRatio());
+ QImage grabbed = m_grabContent;
+ m_grabContent = QImage();
if (tempExpose)
- handleObscurity(w);
+ obscureWindow(window);
- return result;
+ return grabbed;
}
-void QSGD3D12RenderLoop::update(QQuickWindow *window)
+bool QSGD3D12RenderLoop::somethingVisible() const
{
- WindowData *w = windowFor(windows, window);
- if (!w)
- return;
-
- if (w->thread == QThread::currentThread()) {
- w->thread->requestRepaint();
- return;
+ for (auto it = m_windows.constBegin(), itEnd = m_windows.constEnd(); it != itEnd; ++it) {
+ if (it.key()->isVisible() && it.key()->isExposed())
+ return true;
}
+ return false;
+}
- // We set forceRenderPass because we want to make sure the QQuickWindow
- // actually does a full render pass after the next sync.
- w->forceRenderPass = true;
- scheduleUpdate(w);
+void QSGD3D12RenderLoop::maybePostUpdateTimer()
+{
+ if (!m_updateTimer) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("starting update timer");
+ m_updateTimer = startTimer(m_vsyncDelta / 3);
+ }
}
-void QSGD3D12RenderLoop::maybeUpdate(QQuickWindow *window)
+void QSGD3D12RenderLoop::update(QQuickWindow *window)
{
- WindowData *w = windowFor(windows, window);
- if (w)
- scheduleUpdate(w);
+ maybeUpdate(window);
}
-// called in response to window->requestUpdate()
-void QSGD3D12RenderLoop::handleUpdateRequest(QQuickWindow *window)
+void QSGD3D12RenderLoop::maybeUpdate(QQuickWindow *window)
{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "handleUpdateRequest" << window;
+ if (!m_windows.contains(window) || !somethingVisible())
+ return;
- WindowData *w = windowFor(windows, window);
- if (w)
- polishAndSync(w, false);
+ m_windows[window].updatePending = true;
+ maybePostUpdateTimer();
}
QAnimationDriver *QSGD3D12RenderLoop::animationDriver() const
{
- return anim;
+ return m_anims;
}
QSGContext *QSGD3D12RenderLoop::sceneGraphContext() const
@@ -856,6 +279,8 @@ QSGContext *QSGD3D12RenderLoop::sceneGraphContext() const
QSGRenderContext *QSGD3D12RenderLoop::createRenderContext(QSGContext *) const
{
+ // The rendercontext and engine are per-window, like with the threaded
+ // loop, but unlike the non-threaded OpenGL variants.
return sg->createRenderContext();
}
@@ -863,19 +288,15 @@ void QSGD3D12RenderLoop::releaseResources(QQuickWindow *window)
{
if (Q_UNLIKELY(debug_loop()))
qDebug() << "releaseResources" << window;
-
- WindowData *w = windowFor(windows, window);
- if (w)
- handleResourceRelease(w, false);
}
void QSGD3D12RenderLoop::postJob(QQuickWindow *window, QRunnable *job)
{
- WindowData *w = windowFor(windows, window);
- if (w && w->thread && w->thread->exposedWindow)
- w->thread->postEvent(new QSGD3D12JobEvent(window, job));
- else
- delete job;
+ Q_UNUSED(window);
+ Q_ASSERT(job);
+ Q_ASSERT(window);
+ job->run();
+ delete job;
}
QSurface::SurfaceType QSGD3D12RenderLoop::windowSurfaceType() const
@@ -885,283 +306,229 @@ QSurface::SurfaceType QSGD3D12RenderLoop::windowSurfaceType() const
bool QSGD3D12RenderLoop::interleaveIncubation() const
{
- bool somethingVisible = false;
- for (const WindowData &w : windows) {
- if (w.window->isVisible() && w.window->isExposed()) {
- somethingVisible = true;
- break;
- }
- }
- return somethingVisible && anim->isRunning();
-}
-
-int QSGD3D12RenderLoop::flags() const
-{
- return SupportsGrabWithoutExpose;
+ return m_anims->isRunning() && somethingVisible();
}
-bool QSGD3D12RenderLoop::event(QEvent *e)
+void QSGD3D12RenderLoop::onAnimationStarted()
{
- if (e->type() == QEvent::Timer) {
- QTimerEvent *te = static_cast<QTimerEvent *>(e);
- if (te->timerId() == animationTimer) {
- anim->advance();
- emit timeToIncubate();
- return true;
+ if (!somethingVisible()) {
+ if (!m_animationTimer) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("starting non-visual animation timer");
+ m_animationTimer = startTimer(m_vsyncDelta);
}
+ } else {
+ maybePostUpdateTimer();
}
-
- return QObject::event(e);
-}
-
-void QSGD3D12RenderLoop::onAnimationStarted()
-{
- startOrStopAnimationTimer();
-
- for (const WindowData &w : qAsConst(windows))
- w.window->requestUpdate();
}
void QSGD3D12RenderLoop::onAnimationStopped()
{
- startOrStopAnimationTimer();
+ if (m_animationTimer) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("stopping non-visual animation timer");
+ killTimer(m_animationTimer);
+ m_animationTimer = 0;
+ }
}
-void QSGD3D12RenderLoop::startOrStopAnimationTimer()
+bool QSGD3D12RenderLoop::event(QEvent *event)
{
- int exposedWindowCount = 0;
- const WindowData *exposed = nullptr;
-
- for (int i = 0; i < windows.size(); ++i) {
- const WindowData &w(windows[i]);
- if (w.window->isVisible() && w.window->isExposed()) {
- ++exposedWindowCount;
- exposed = &w;
+ switch (event->type()) {
+ case QEvent::Timer:
+ {
+ QTimerEvent *te = static_cast<QTimerEvent *>(event);
+ if (te->timerId() == m_animationTimer) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("animation tick while no windows exposed");
+ m_anims->advance();
+ } else if (te->timerId() == m_updateTimer) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("update timeout - rendering");
+ killTimer(m_updateTimer);
+ m_updateTimer = 0;
+ render();
}
+ return true;
}
-
- if (animationTimer && (exposedWindowCount == 1 || !anim->isRunning())) {
- killTimer(animationTimer);
- animationTimer = 0;
- // If animations are running, make sure we keep on animating
- if (anim->isRunning())
- exposed->window->requestUpdate();
- } else if (!animationTimer && exposedWindowCount != 1 && anim->isRunning()) {
- animationTimer = startTimer(qsgrl_animation_interval());
+ default:
+ break;
}
+
+ return QObject::event(event);
}
-void QSGD3D12RenderLoop::handleExposure(QQuickWindow *window)
+void QSGD3D12RenderLoop::render()
{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "handleExposure" << window;
-
- WindowData *w = windowFor(windows, window);
- if (!w) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("adding window to list");
- WindowData win;
- win.window = window;
- QSGRenderContext *rc = QQuickWindowPrivate::get(window)->context; // will transfer ownership
- win.thread = new QSGD3D12RenderThread(this, rc);
- win.updateDuringSync = false;
- win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt
- windows.append(win);
- w = &windows.last();
- }
-
- // set this early as we'll be rendering shortly anyway and this avoids
- // special casing exposure in polishAndSync.
- w->thread->exposedWindow = window;
-
- if (w->window->size().isEmpty()
- || (w->window->isTopLevel() && !w->window->geometry().intersects(w->window->screen()->availableGeometry()))) {
-#ifndef QT_NO_DEBUG
- qWarning().noquote().nospace() << "QSGD3D12RenderLoop: expose event received for window "
- << w->window << " with invalid geometry: " << w->window->geometry()
- << " on " << w->window->screen();
-#endif
+ bool rendered = false;
+ for (auto it = m_windows.begin(), itEnd = m_windows.end(); it != itEnd; ++it) {
+ if (it->updatePending) {
+ it->updatePending = false;
+ renderWindow(it.key());
+ rendered = true;
+ }
}
- if (!w->window->handle())
- w->window->create();
-
- // Start render thread if it is not running
- if (!w->thread->isRunning()) {
+ if (!rendered) {
if (Q_UNLIKELY(debug_loop()))
- qDebug("starting render thread");
- // Push a few things to the render thread.
- QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController;
- if (controller->thread() != w->thread)
- controller->moveToThread(w->thread);
- if (w->thread->thread() == QThread::currentThread()) {
- w->thread->rc->moveToThread(w->thread);
- w->thread->moveToThread(w->thread);
- }
-
- w->thread->active = true;
- w->thread->start();
-
- if (!w->thread->isRunning())
- qFatal("Render thread failed to start, aborting application.");
+ qDebug("render - no changes, sleep");
+ QThread::msleep(m_vsyncDelta);
}
- polishAndSync(w, true);
+ if (m_anims->isRunning()) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("render - advancing animations");
- startOrStopAnimationTimer();
-}
+ m_anims->advance();
-void QSGD3D12RenderLoop::handleObscurity(WindowData *w)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "handleObscurity" << w->window;
+ // It is not given that animations triggered another maybeUpdate()
+ // and thus another render pass, so to keep things running,
+ // make sure there is another frame pending.
+ maybePostUpdateTimer();
- if (w->thread->isRunning()) {
- w->thread->mutex.lock();
- w->thread->postEvent(new QSGD3D12WindowEvent(w->window, WM_Obscure));
- w->thread->waitCondition.wait(&w->thread->mutex);
- w->thread->mutex.unlock();
+ emit timeToIncubate();
}
-
- startOrStopAnimationTimer();
}
-void QSGD3D12RenderLoop::scheduleUpdate(WindowData *w)
+void QSGD3D12RenderLoop::renderWindow(QQuickWindow *window)
{
- if (!QCoreApplication::instance())
- return;
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "renderWindow" << window;
- if (!w || !w->thread->isRunning())
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ if (!m_windows.contains(window) || !window->geometry().isValid())
return;
- QThread *current = QThread::currentThread();
- if (current != QCoreApplication::instance()->thread() && (current != w->thread || !lockedForSync)) {
- qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()";
+ WindowData &data(m_windows[window]);
+ if (!data.exposed) { // not the same as window->isExposed(), when grabbing invisible windows for instance
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("renderWindow - not exposed, abort");
return;
}
- if (current == w->thread) {
- w->updateDuringSync = true;
- return;
- }
+ if (!data.grabOnly)
+ wd->flushFrameSynchronousEvents();
- w->window->requestUpdate();
-}
+ QElapsedTimer renderTimer;
+ qint64 renderTime = 0, syncTime = 0, polishTime = 0;
+ const bool profileFrames = debug_time();
+ if (profileFrames)
+ renderTimer.start();
+ Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
-void QSGD3D12RenderLoop::handleResourceRelease(WindowData *w, bool destroying)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "handleResourceRelease" << (destroying ? "destroying" : "hide/releaseResources") << w->window;
-
- w->thread->mutex.lock();
- if (w->thread->isRunning() && w->thread->active) {
- QQuickWindow *window = w->window;
-
- // Note that window->handle() is typically null by this time because
- // the platform window is already destroyed. This should not be a
- // problem for the D3D cleanup.
-
- w->thread->postEvent(new QSGD3D12TryReleaseEvent(window, destroying));
- w->thread->waitCondition.wait(&w->thread->mutex);
-
- // Avoid a shutdown race condition.
- // If SG is invalidated and 'active' becomes false, the thread's run()
- // method will exit. handleExposure() relies on QThread::isRunning() (because it
- // potentially needs to start the thread again) and our mutex cannot be used to
- // track the thread stopping, so we wait a few nanoseconds extra so the thread
- // can exit properly.
- if (!w->thread->active)
- w->thread->wait();
- }
- w->thread->mutex.unlock();
-}
+ wd->polishItems();
-void QSGD3D12RenderLoop::polishAndSync(WindowData *w, bool inExpose)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "polishAndSync" << (inExpose ? "(in expose)" : "(normal)") << w->window;
+ if (profileFrames)
+ polishTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
+ QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ emit window->afterAnimating();
- QQuickWindow *window = w->window;
- if (!w->thread || !w->thread->exposedWindow) {
+ // The native window may change in some (quite artificial) cases, e.g. due
+ // to a hide - destroy - show on the QWindow.
+ bool needsWindow = !data.engine->window();
+ if (data.engine->window() && data.engine->window() != window->winId()) {
if (Q_UNLIKELY(debug_loop()))
- qDebug("polishAndSync - not exposed, abort");
- return;
+ qDebug("sync - native window handle changes for active engine");
+ data.engine->waitGPU();
+ wd->cleanupNodesOnShutdown();
+ QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
+ data.rc->invalidate();
+ data.engine->releaseResources();
+ needsWindow = true;
+ }
+ if (needsWindow) {
+ // Must only ever get here when there is no window or releaseResources() has been called.
+ const int samples = window->format().samples();
+ const bool alpha = window->format().alphaBufferSize() > 0;
+ const qreal dpr = window->effectiveDevicePixelRatio();
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "sync - reinitializing D3D12 engine" << window << window->size() << dpr << samples << alpha;
+ data.engine->attachToWindow(window->winId(), window->size(), dpr, samples, alpha);
}
- // Flush pending touch events.
- QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
- // The delivery of the event might have caused the window to stop rendering
- w = windowFor(windows, window);
- if (!w || !w->thread || !w->thread->exposedWindow) {
+ // Recover from device loss.
+ if (!data.engine->hasResources()) {
if (Q_UNLIKELY(debug_loop()))
- qDebug("polishAndSync - removed after touch event flushing, abort");
- return;
+ qDebug("sync - device was lost, resetting scenegraph");
+ wd->cleanupNodesOnShutdown();
+ QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
+ data.rc->invalidate();
}
- QElapsedTimer timer;
- qint64 polishTime = 0;
- qint64 waitTime = 0;
- qint64 syncTime = 0;
- if (Q_UNLIKELY(debug_time()))
- timer.start();
- Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync);
+ data.rc->initialize(nullptr);
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
- wd->polishItems();
+ wd->syncSceneGraph();
- if (Q_UNLIKELY(debug_time()))
- polishTime = timer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
+ if (profileFrames)
+ syncTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
- w->updateDuringSync = false;
+ wd->renderSceneGraph(window->size());
- emit window->afterAnimating();
+ if (profileFrames)
+ renderTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
- if (Q_UNLIKELY(debug_loop()))
- qDebug("polishAndSync - lock for sync");
- w->thread->mutex.lock();
- lockedForSync = true;
- w->thread->postEvent(new QSGD3D12SyncEvent(window, inExpose, w->forceRenderPass));
- w->forceRenderPass = false;
+ if (!data.grabOnly) {
+ // The engine is able to have multiple frames in flight. This in effect is
+ // similar to BufferQueueingOpenGL. Provide an env var to force the
+ // traditional blocking swap behavior, just in case.
+ static bool blockOnEachFrame = qEnvironmentVariableIntValue("QT_D3D_BLOCKING_PRESENT") != 0;
- if (Q_UNLIKELY(debug_loop()))
- qDebug("polishAndSync - wait for sync");
- if (Q_UNLIKELY(debug_time()))
- waitTime = timer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
- w->thread->waitCondition.wait(&w->thread->mutex);
- lockedForSync = false;
- w->thread->mutex.unlock();
- if (Q_UNLIKELY(debug_loop()))
- qDebug("polishAndSync - unlock after sync");
+ if (window->isVisible()) {
+ data.engine->present();
+ if (blockOnEachFrame)
+ data.engine->waitGPU();
+ // The concept of "frame swaps" is quite misleading by default, when
+ // blockOnEachFrame is not used, but emit it for compatibility.
+ wd->fireFrameSwapped();
+ } else {
+ if (blockOnEachFrame)
+ data.engine->waitGPU();
+ }
+ } else {
+ m_grabContent = data.engine->executeAndWaitReadbackRenderTarget();
+ data.grabOnly = false;
+ }
- if (Q_UNLIKELY(debug_time()))
- syncTime = timer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
+ qint64 swapTime = 0;
+ if (profileFrames)
+ swapTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame);
- if (!animationTimer && anim->isRunning()) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("polishAndSync - advancing animations");
- anim->advance();
- // We need to trigger another sync to keep animations running...
- w->window->requestUpdate();
- emit timeToIncubate();
- } else if (w->updateDuringSync) {
- w->window->requestUpdate();
+ if (Q_UNLIKELY(debug_time())) {
+ static QTime lastFrameTime = QTime::currentTime();
+ qDebug("Frame rendered with 'd3d12' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
+ int(swapTime / 1000000),
+ int(polishTime / 1000000),
+ int((syncTime - polishTime) / 1000000),
+ int((renderTime - syncTime) / 1000000),
+ int((swapTime - renderTime) / 10000000),
+ int(lastFrameTime.msecsTo(QTime::currentTime())));
+ lastFrameTime = QTime::currentTime();
}
- if (Q_UNLIKELY(debug_time()))
- qDebug().nospace()
- << "Frame prepared with 'd3d12' renderloop"
- << ", polish=" << (polishTime / 1000000)
- << ", lock=" << (waitTime - polishTime) / 1000000
- << ", blockedForSync=" << (syncTime - waitTime) / 1000000
- << ", animations=" << (timer.nsecsElapsed() - syncTime) / 1000000
- << " - (on gui thread) " << window;
-
- Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync);
+ // Simulate device loss if requested.
+ static int devLossTest = qEnvironmentVariableIntValue("QT_D3D_TEST_DEVICE_LOSS");
+ if (devLossTest > 0) {
+ static QElapsedTimer kt;
+ static bool timerRunning = false;
+ if (!timerRunning) {
+ kt.start();
+ timerRunning = true;
+ } else if (kt.elapsed() > 5000) {
+ --devLossTest;
+ kt.restart();
+ data.engine->simulateDeviceLoss();
+ }
+ }
}
-#include "qsgd3d12renderloop.moc"
+int QSGD3D12RenderLoop::flags() const
+{
+ return SupportsGrabWithoutExpose;
+}
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop_p.h
index 732f8dd5d2..c0333ffad0 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop_p.h
@@ -58,7 +58,6 @@ QT_BEGIN_NAMESPACE
class QSGD3D12Engine;
class QSGD3D12Context;
class QSGD3D12RenderContext;
-class QSGD3D12RenderThread;
class QSGD3D12RenderLoop : public QSGRenderLoop
{
@@ -80,7 +79,6 @@ public:
void update(QQuickWindow *window) override;
void maybeUpdate(QQuickWindow *window) override;
- void handleUpdateRequest(QQuickWindow *window) override;
QAnimationDriver *animationDriver() const override;
@@ -94,34 +92,37 @@ public:
bool interleaveIncubation() const override;
int flags() const override;
- bool event(QEvent *e) override;
+ bool event(QEvent *event) override;
public Q_SLOTS:
void onAnimationStarted();
void onAnimationStopped();
private:
+ void exposeWindow(QQuickWindow *window);
+ void obscureWindow(QQuickWindow *window);
+ void renderWindow(QQuickWindow *window);
+ void render();
+ void maybePostUpdateTimer();
+ bool somethingVisible() const;
+
+ QSGD3D12Context *sg;
+ QAnimationDriver *m_anims;
+ int m_vsyncDelta;
+ int m_updateTimer = 0;
+ int m_animationTimer = 0;
+
struct WindowData {
- QQuickWindow *window;
- QSGD3D12RenderThread *thread;
- uint updateDuringSync : 1;
- uint forceRenderPass : 1;
+ QSGD3D12RenderContext *rc = nullptr;
+ QSGD3D12Engine *engine = nullptr;
+ bool updatePending = false;
+ bool grabOnly = false;
+ bool exposed = false;
};
- void startOrStopAnimationTimer();
- void handleExposure(QQuickWindow *window);
- void handleObscurity(WindowData *w);
- void scheduleUpdate(WindowData *w);
- void handleResourceRelease(WindowData *w, bool destroying);
- void polishAndSync(WindowData *w, bool inExpose);
-
- QSGD3D12Context *sg;
- QAnimationDriver *anim;
- int animationTimer = 0;
- bool lockedForSync = false;
- QVector<WindowData> windows;
+ QHash<QQuickWindow *, WindowData> m_windows;
- friend class QSGD3D12RenderThread;
+ QImage m_grabContent;
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
index f77719f876..62771eb8f9 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
@@ -41,7 +41,9 @@
#include "qsgd3d12rendercontext_p.h"
#include "qsgd3d12texture_p.h"
#include "qsgd3d12engine_p.h"
+#include <QtCore/qthreadpool.h>
#include <QtCore/qfile.h>
+#include <QtCore/qfileselector.h>
#include <QtQml/qqmlfile.h>
#include <qsgtextureprovider.h>
@@ -59,7 +61,7 @@ QT_BEGIN_NAMESPACE
static bool debug_ ## variable() \
{ static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
-DECLARE_DEBUG_VAR(render)
+DECLARE_DEBUG_VAR(shader)
void QSGD3D12ShaderLinker::reset(const QByteArray &vertBlob, const QByteArray &fragBlob)
{
@@ -134,8 +136,7 @@ void QSGD3D12ShaderLinker::feedSamplers(const QSGShaderEffectNode::ShaderData &s
for (int i = 0; i < shader.shaderInfo.variables.count(); ++i) {
const auto &var(shader.shaderInfo.variables.at(i));
if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
- const auto &vd(shader.varData.at(i));
- Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Unused);
+ Q_ASSERT(shader.varData.at(i).specialType == QSGShaderEffectNode::VariableData::Unused);
samplers.insert(var.bindPoint);
}
}
@@ -597,7 +598,7 @@ QRectF QSGD3D12ShaderEffectNode::updateNormalizedTextureSubRect(bool supportsAtl
void QSGD3D12ShaderEffectNode::syncMaterial(SyncData *syncData)
{
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_shader()))
qDebug() << "shadereffect node sync" << syncData->dirty;
if (bool(m_material.flags() & QSGMaterial::Blending) != syncData->blending) {
@@ -714,7 +715,7 @@ void QSGD3D12ShaderEffectNode::syncMaterial(SyncData *syncData)
markDirty(QSGNode::DirtyMaterial);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_shader()))
m_material.linker.dump();
} else {
if (syncData->dirty & QSGShaderEffectNode::DirtyShaderConstant) {
@@ -723,7 +724,7 @@ void QSGD3D12ShaderEffectNode::syncMaterial(SyncData *syncData)
if (!syncData->fragment.dirtyConstants->isEmpty())
m_material.linker.feedConstants(*syncData->fragment.shader, syncData->fragment.dirtyConstants);
markDirty(QSGNode::DirtyMaterial);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_shader()))
m_material.linker.dump();
}
@@ -735,7 +736,7 @@ void QSGD3D12ShaderEffectNode::syncMaterial(SyncData *syncData)
m_material.linker.linkTextureSubRects();
m_material.updateTextureProviders(false);
markDirty(QSGNode::DirtyMaterial);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_shader()))
m_material.linker.dump();
}
}
@@ -777,12 +778,12 @@ bool QSGD3D12GuiThreadShaderEffectManager::hasSeparateSamplerAndTextureObjects()
QString QSGD3D12GuiThreadShaderEffectManager::log() const
{
- return QString();
+ return m_log;
}
QSGGuiThreadShaderEffectManager::Status QSGD3D12GuiThreadShaderEffectManager::status() const
{
- return Compiled;
+ return m_status;
}
struct RefGuard {
@@ -791,17 +792,101 @@ struct RefGuard {
IUnknown *p;
};
-bool QSGD3D12GuiThreadShaderEffectManager::reflect(const QByteArray &src, ShaderInfo *result)
+class QSGD3D12ShaderCompileTask : public QRunnable
{
- const QString fn = QQmlFile::urlToLocalFileOrQrc(src);
- QFile f(fn);
- if (!f.open(QIODevice::ReadOnly)) {
- qWarning("ShaderEffect: Failed to read %s", qPrintable(fn));
- return false;
+public:
+ QSGD3D12ShaderCompileTask(QSGD3D12GuiThreadShaderEffectManager *mgr,
+ QSGD3D12GuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
+ const QByteArray &src,
+ QSGD3D12GuiThreadShaderEffectManager::ShaderInfo *result)
+ : mgr(mgr), typeHint(typeHint), src(src), result(result) { }
+
+ void run() override;
+
+private:
+ QSGD3D12GuiThreadShaderEffectManager *mgr;
+ QSGD3D12GuiThreadShaderEffectManager::ShaderInfo::Type typeHint;
+ QByteArray src;
+ QSGD3D12GuiThreadShaderEffectManager::ShaderInfo *result;
+};
+
+void QSGD3D12ShaderCompileTask::run()
+{
+ const char *target = typeHint == QSGD3D12GuiThreadShaderEffectManager::ShaderInfo::TypeVertex ? "vs_5_0" : "ps_5_0";
+ ID3DBlob *bytecode = nullptr;
+ ID3DBlob *errors = nullptr;
+ HRESULT hr = D3DCompile(src.constData(), src.size(), nullptr, nullptr, nullptr,
+ "main", target, 0, 0, &bytecode, &errors);
+ if (FAILED(hr) || !bytecode) {
+ qWarning("HLSL shader compilation failed: 0x%x", hr);
+ if (errors) {
+ mgr->m_log += QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()), errors->GetBufferSize());
+ errors->Release();
+ }
+ mgr->m_status = QSGGuiThreadShaderEffectManager::Error;
+ emit mgr->shaderCodePrepared(false, typeHint, src, result);
+ emit mgr->logAndStatusChanged();
+ return;
}
- result->blob = f.readAll();
- f.close();
+ result->blob.resize(bytecode->GetBufferSize());
+ memcpy(result->blob.data(), bytecode->GetBufferPointer(), result->blob.size());
+ bytecode->Release();
+
+ const bool ok = mgr->reflect(result);
+ mgr->m_status = ok ? QSGGuiThreadShaderEffectManager::Compiled : QSGGuiThreadShaderEffectManager::Error;
+ emit mgr->shaderCodePrepared(ok, typeHint, src, result);
+ emit mgr->logAndStatusChanged();
+}
+
+static const int BYTECODE_MAGIC = 0x43425844; // 'DXBC'
+
+void QSGD3D12GuiThreadShaderEffectManager::prepareShaderCode(ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result)
+{
+ // The D3D12 backend's ShaderEffect implementation supports both HLSL
+ // source strings and bytecode or source in files as input. Bytecode is
+ // strongly recommended, but in order to make ShaderEffect users' (and
+ // anything that stiches shader strings together dynamically, e.g.
+ // qtgraphicaleffects) life easier, and since we link to d3dcompiler
+ // anyways, compiling from source is also supported.
+
+ QByteArray shaderSourceCode = src;
+ QUrl srcUrl(QString::fromUtf8(src));
+ if (!srcUrl.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) || srcUrl.isLocalFile()) {
+ if (!m_fileSelector) {
+ m_fileSelector = new QFileSelector(this);
+ m_fileSelector->setExtraSelectors(QStringList() << QStringLiteral("hlsl"));
+ }
+ const QString fn = m_fileSelector->select(QQmlFile::urlToLocalFileOrQrc(srcUrl));
+ QFile f(fn);
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning("ShaderEffect: Failed to read %s", qPrintable(fn));
+ emit shaderCodePrepared(false, typeHint, src, result);
+ return;
+ }
+ QByteArray blob = f.readAll();
+ f.close();
+ if (blob.size() > 4) {
+ const quint32 *p = reinterpret_cast<const quint32 *>(blob.constData());
+ if (*p == BYTECODE_MAGIC) {
+ // already compiled D3D bytecode, skip straight to reflection
+ result->blob = blob;
+ const bool ok = reflect(result);
+ m_status = ok ? Compiled : Error;
+ emit shaderCodePrepared(ok, typeHint, src, result);
+ emit logAndStatusChanged();
+ return;
+ }
+ // assume the file contained HLSL source code
+ shaderSourceCode = blob;
+ }
+ }
+
+ QThreadPool::globalInstance()->start(new QSGD3D12ShaderCompileTask(this, typeHint, shaderSourceCode, result));
+}
+
+bool QSGD3D12GuiThreadShaderEffectManager::reflect(ShaderInfo *result)
+{
ID3D12ShaderReflection *reflector;
HRESULT hr = D3DReflect(result->blob.constData(), result->blob.size(), IID_PPV_ARGS(&reflector));
if (FAILED(hr)) {
@@ -854,7 +939,7 @@ bool QSGD3D12GuiThreadShaderEffectManager::reflect(const QByteArray &src, Shader
return false;
}
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_shader()))
qDebug("Shader reflection size %d type %d v%u.%u input elems %d cbuffers %d boundres %d",
result->blob.size(), result->type, major, minor, ieCount, cbufferCount, boundResCount);
@@ -951,7 +1036,7 @@ bool QSGD3D12GuiThreadShaderEffectManager::reflect(const QByteArray &src, Shader
}
}
- if (Q_UNLIKELY(debug_render())) {
+ if (Q_UNLIKELY(debug_shader())) {
qDebug() << "Input:" << result->inputParameters;
qDebug() << "Variables:" << result->variables << "cbuffer size" << result->constantDataSize;
}
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
index edeaba899b..ee17e59130 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
@@ -60,6 +60,7 @@ class QSGD3D12RenderContext;
class QSGD3D12GuiThreadShaderEffectManager;
class QSGD3D12ShaderEffectNode;
class QSGD3D12Texture;
+class QFileSelector;
class QSGD3D12ShaderLinker
{
@@ -160,7 +161,15 @@ public:
QString log() const override;
Status status() const override;
- bool reflect(const QByteArray &src, ShaderInfo *result) override;
+ void prepareShaderCode(ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result) override;
+
+private:
+ bool reflect(ShaderInfo *result);
+ QString m_log;
+ Status m_status = Uncompiled;
+ QFileSelector *m_fileSelector = nullptr;
+
+ friend class QSGD3D12ShaderCompileTask;
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12spritenode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12spritenode.cpp
new file mode 100644
index 0000000000..bad222dbaa
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12spritenode.cpp
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12spritenode_p.h"
+#include "qsgd3d12material_p.h"
+
+#include "vs_sprite.hlslh"
+#include "ps_sprite.hlslh"
+
+QT_BEGIN_NAMESPACE
+
+struct SpriteVertex
+{
+ float x;
+ float y;
+ float tx;
+ float ty;
+};
+
+struct SpriteVertices
+{
+ SpriteVertex v1;
+ SpriteVertex v2;
+ SpriteVertex v3;
+ SpriteVertex v4;
+};
+
+class QSGD3D12SpriteMaterial : public QSGD3D12Material
+{
+public:
+ QSGD3D12SpriteMaterial();
+ ~QSGD3D12SpriteMaterial();
+
+ QSGMaterialType *type() const override { static QSGMaterialType type; return &type; }
+
+ int compare(const QSGMaterial *other) const override
+ {
+ return this - static_cast<const QSGD3D12SpriteMaterial *>(other);
+ }
+
+ int constantBufferSize() const override;
+ void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
+ UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
+ QSGD3D12PipelineState *pipelineState,
+ ExtraState *extraState,
+ quint8 *constantBuffer) override;
+
+ QSGTexture *texture;
+
+ float animT;
+ float animX1;
+ float animY1;
+ float animX2;
+ float animY2;
+ float animW;
+ float animH;
+};
+
+QSGD3D12SpriteMaterial::QSGD3D12SpriteMaterial()
+ : texture(nullptr),
+ animT(0.0f),
+ animX1(0.0f),
+ animY1(0.0f),
+ animX2(0.0f),
+ animY2(0.0f),
+ animW(1.0f),
+ animH(1.0f)
+{
+ setFlag(Blending, true);
+}
+
+QSGD3D12SpriteMaterial::~QSGD3D12SpriteMaterial()
+{
+ delete texture;
+}
+
+static const int SPRITE_CB_SIZE_0 = 16 * sizeof(float); // float4x4
+static const int SPRITE_CB_SIZE_1 = 4 * sizeof(float); // float4
+static const int SPRITE_CB_SIZE_2 = 3 * sizeof(float); // float3
+static const int SPRITE_CB_SIZE_3 = sizeof(float); // float
+static const int SPRITE_CB_SIZE = SPRITE_CB_SIZE_0 + SPRITE_CB_SIZE_1 + SPRITE_CB_SIZE_2 + SPRITE_CB_SIZE_3;
+
+int QSGD3D12SpriteMaterial::constantBufferSize() const
+{
+ return QSGD3D12Engine::alignedConstantBufferSize(SPRITE_CB_SIZE);
+}
+
+void QSGD3D12SpriteMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
+{
+ pipelineState->shaders.vs = g_VS_Sprite;
+ pipelineState->shaders.vsSize = sizeof(g_VS_Sprite);
+ pipelineState->shaders.ps = g_PS_Sprite;
+ pipelineState->shaders.psSize = sizeof(g_PS_Sprite);
+
+ pipelineState->shaders.rootSig.textureViewCount = 1;
+}
+
+QSGD3D12Material::UpdateResults QSGD3D12SpriteMaterial::updatePipeline(const QSGD3D12MaterialRenderState &state,
+ QSGD3D12PipelineState *,
+ ExtraState *,
+ quint8 *constantBuffer)
+{
+ QSGD3D12Material::UpdateResults r = UpdatedConstantBuffer;
+ quint8 *p = constantBuffer;
+
+ if (state.isMatrixDirty())
+ memcpy(p, state.combinedMatrix().constData(), SPRITE_CB_SIZE_0);
+ p += SPRITE_CB_SIZE_0;
+
+ {
+ const float v[] = { animX1, animY1, animX2, animY2 };
+ memcpy(p, v, SPRITE_CB_SIZE_1);
+ }
+ p += SPRITE_CB_SIZE_1;
+
+ {
+ const float v[] = { animW, animH, animT };
+ memcpy(p, v, SPRITE_CB_SIZE_2);
+ }
+ p += SPRITE_CB_SIZE_2;
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(p, &opacity, SPRITE_CB_SIZE_3);
+ }
+
+ texture->bind();
+
+ return r;
+}
+
+static QSGGeometry::Attribute Sprite_Attributes[] = {
+ QSGGeometry::Attribute::createWithSemantic(0, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::POSITION),
+ QSGGeometry::Attribute::createWithSemantic(1, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::TEXCOORD),
+};
+
+static QSGGeometry::AttributeSet Sprite_AttributeSet = { 2, 4 * sizeof(float), Sprite_Attributes };
+
+QSGD3D12SpriteNode::QSGD3D12SpriteNode()
+ : m_material(new QSGD3D12SpriteMaterial)
+ , m_geometryDirty(true)
+ , m_sheetSize(QSize(64, 64))
+{
+ m_geometry = new QSGGeometry(Sprite_AttributeSet, 4, 6);
+ m_geometry->setDrawingMode(QSGGeometry::DrawTriangles);
+
+ quint16 *indices = m_geometry->indexDataAsUShort();
+ indices[0] = 0;
+ indices[1] = 1;
+ indices[2] = 2;
+ indices[3] = 1;
+ indices[4] = 3;
+ indices[5] = 2;
+
+ setGeometry(m_geometry);
+ setMaterial(m_material);
+ setFlag(OwnsGeometry, true);
+ setFlag(OwnsMaterial, true);
+}
+
+void QSGD3D12SpriteNode::setTexture(QSGTexture *texture)
+{
+ m_material->texture = texture;
+ m_geometryDirty = true;
+ markDirty(DirtyMaterial);
+}
+
+void QSGD3D12SpriteNode::setTime(float time)
+{
+ m_material->animT = time;
+ markDirty(DirtyMaterial);
+}
+
+void QSGD3D12SpriteNode::setSourceA(const QPoint &source)
+{
+ if (m_sourceA != source) {
+ m_sourceA = source;
+ m_material->animX1 = static_cast<float>(source.x()) / m_sheetSize.width();
+ m_material->animY1 = static_cast<float>(source.y()) / m_sheetSize.height();
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGD3D12SpriteNode::setSourceB(const QPoint &source)
+{
+ if (m_sourceB != source) {
+ m_sourceB = source;
+ m_material->animX2 = static_cast<float>(source.x()) / m_sheetSize.width();
+ m_material->animY2 = static_cast<float>(source.y()) / m_sheetSize.height();
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGD3D12SpriteNode::setSpriteSize(const QSize &size)
+{
+ if (m_spriteSize != size) {
+ m_spriteSize = size;
+ m_material->animW = static_cast<float>(size.width()) / m_sheetSize.width();
+ m_material->animH = static_cast<float>(size.height()) / m_sheetSize.height();
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGD3D12SpriteNode::setSheetSize(const QSize &size)
+{
+ if (m_sheetSize != size) {
+ m_sheetSize = size;
+
+ // Update all dependent properties
+ m_material->animX1 = static_cast<float>(m_sourceA.x()) / m_sheetSize.width();
+ m_material->animY1 = static_cast<float>(m_sourceA.y()) / m_sheetSize.height();
+ m_material->animX2 = static_cast<float>(m_sourceB.x()) / m_sheetSize.width();
+ m_material->animY2 = static_cast<float>(m_sourceB.y()) / m_sheetSize.height();
+ m_material->animW = static_cast<float>(m_spriteSize.width()) / m_sheetSize.width();
+ m_material->animH = static_cast<float>(m_spriteSize.height()) / m_sheetSize.height();
+
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGD3D12SpriteNode::setSize(const QSizeF &size)
+{
+ if (m_size != size) {
+ m_size = size;
+ m_geometryDirty = true;
+ }
+}
+
+void QSGD3D12SpriteNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ m_material->texture->setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+void QSGD3D12SpriteNode::update()
+{
+ if (m_geometryDirty) {
+ m_geometryDirty = false;
+ updateGeometry();
+ }
+}
+
+void QSGD3D12SpriteNode::updateGeometry()
+{
+ if (!m_material->texture)
+ return;
+
+ SpriteVertices *p = static_cast<SpriteVertices *>(m_geometry->vertexData());
+ const QRectF texRect = m_material->texture->normalizedTextureSubRect();
+
+ p->v1.tx = texRect.topLeft().x();
+ p->v1.ty = texRect.topLeft().y();
+
+ p->v2.tx = texRect.topRight().x();
+ p->v2.ty = texRect.topRight().y();
+
+ p->v3.tx = texRect.bottomLeft().x();
+ p->v3.ty = texRect.bottomLeft().y();
+
+ p->v4.tx = texRect.bottomRight().x();
+ p->v4.ty = texRect.bottomRight().y();
+
+ p->v1.x = 0;
+ p->v1.y = 0;
+
+ p->v2.x = m_size.width();
+ p->v2.y = 0;
+
+ p->v3.x = 0;
+ p->v3.y = m_size.height();
+
+ p->v4.x = m_size.width();
+ p->v4.y = m_size.height();
+
+ markDirty(DirtyGeometry);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12spritenode_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12spritenode_p.h
new file mode 100644
index 0000000000..265bec7c78
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12spritenode_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12SPRITENODE_H
+#define QSGD3D12SPRITENODE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12SpriteMaterial;
+
+class QSGD3D12SpriteNode : public QSGSpriteNode
+{
+public:
+ QSGD3D12SpriteNode();
+
+ void setTexture(QSGTexture *texture) override;
+ void setTime(float time) override;
+ void setSourceA(const QPoint &source) override;
+ void setSourceB(const QPoint &source) override;
+ void setSpriteSize(const QSize &size) override;
+ void setSheetSize(const QSize &size) override;
+ void setSize(const QSizeF &size) override;
+ void setFiltering(QSGTexture::Filtering filtering) override;
+ void update() override;
+
+private:
+ void updateGeometry();
+
+ QSGD3D12SpriteMaterial *m_material;
+ QSGGeometry *m_geometry;
+ bool m_geometryDirty;
+ QPoint m_sourceA;
+ QPoint m_sourceB;
+ QSize m_spriteSize;
+ QSize m_sheetSize;
+ QSizeF m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12SPRITENODE_H
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp
index c4ba80bd48..a5f3eb7a31 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp
@@ -52,7 +52,13 @@ void QSGD3D12Texture::create(const QImage &image, uint flags)
const bool alphaRequest = flags & QSGRenderContext::CreateTexture_Alpha;
m_alphaWanted = alphaRequest && image.hasAlphaChannel();
- m_image = image;
+ // The engine maps 8-bit formats to R8. This is fine for glyphs and such
+ // but may not be what apps expect for ordinary image data. The OpenGL
+ // implementation maps these to ARGB32_Pre so let's follow suit.
+ if (image.depth() != 8)
+ m_image = image;
+ else
+ m_image = image.convertToFormat(m_alphaWanted ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
m_id = m_engine->genTexture();
Q_ASSERT(m_id);
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp
new file mode 100644
index 0000000000..a803f67380
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp
@@ -0,0 +1,1183 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12threadedrenderloop_p.h"
+#include "qsgd3d12engine_p.h"
+#include "qsgd3d12context_p.h"
+#include "qsgd3d12rendercontext_p.h"
+#include "qsgd3d12shadereffectnode_p.h"
+#include <private/qsgrenderer_p.h>
+#include <private/qquickwindow_p.h>
+#include <private/qquickanimatorcontroller_p.h>
+#include <private/qquickprofiler_p.h>
+#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmldebugconnector_p.h>
+#include <QElapsedTimer>
+#include <QQueue>
+#include <QGuiApplication>
+
+QT_BEGIN_NAMESPACE
+
+// NOTE: Avoid categorized logging. It is slow.
+
+#define DECLARE_DEBUG_VAR(variable) \
+ static bool debug_ ## variable() \
+ { static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
+
+DECLARE_DEBUG_VAR(loop)
+DECLARE_DEBUG_VAR(time)
+
+
+// NOTE: The threaded renderloop is not currently safe to use in practice as it
+// is prone to deadlocks, in particular when multiple windows are active. This
+// is because DXGI's limitation of relying on the gui message pump in certain
+// cases. See
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx#multithreading_and_dxgi
+//
+// This means that if swap chain functions like create, release, and
+// potentially even Present, are called outside the gui thread, then the
+// application must ensure the gui thread does not ever block and wait for the
+// render thread - since on the render thread a DXGI call may be in turn
+// waiting for the gui thread to deliver a window message...
+//
+// Ensuring this is impossible with the current design where the gui thread
+// must block at certain points, waiting for the render thread. Qt moves out
+// rendering from the main thread, in order to make application's life easier,
+// whereas the typical DXGI-compatible model would require moving work, but not
+// windowing and presenting, out to additional threads.
+
+
+/*
+ The D3D render loop mostly mirrors the threaded OpenGL render loop.
+
+ There are two classes here. QSGD3D12ThreadedRenderLoop and
+ QSGD3D12RenderThread. All communication between the two is based on event
+ passing and we have a number of custom events.
+
+ Render loop is per process, render thread is per window. The
+ QSGD3D12RenderContext and QSGD3D12Engine are per window as well. The former
+ is created (but not owned) by QQuickWindow. The D3D device is per process.
+
+ In this implementation, the render thread is never blocked and the GUI
+ thread will initiate a polishAndSync which will block and wait for the
+ render thread to pick it up and release the block only after the render
+ thread is done syncing. The reason for this is:
+
+ 1. Clear blocking paradigm. We only have one real "block" point
+ (polishAndSync()) and all blocking is initiated by GUI and picked up by
+ Render at specific times based on events. This makes the execution
+ deterministic.
+
+ 2. Render does not have to interact with GUI. This is done so that the
+ render thread can run its own animation system which stays alive even when
+ the GUI thread is blocked doing I/O, object instantiation, QPainter-painting
+ or any other non-trivial task.
+
+ The render thread has affinity to the GUI thread until a window is shown.
+ From that moment and until the window is destroyed, it will have affinity to
+ the render thread. (moved back at the end of run for cleanup).
+ */
+
+// Passed from the RL to the RT when a window is removed obscured and should be
+// removed from the render loop.
+const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1);
+
+// Passed from the RL to RT when GUI has been locked, waiting for sync.
+const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2);
+
+// Passed by the RT to itself to trigger another render pass. This is typically
+// a result of QQuickWindow::update().
+const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3);
+
+// Passed by the RL to the RT to maybe release resource if no windows are
+// rendering.
+const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4);
+
+// Passed by the RL to the RT when a QQuickWindow::grabWindow() is called.
+const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5);
+
+// Passed by the window when there is a render job to run.
+const QEvent::Type WM_PostJob = QEvent::Type(QEvent::User + 6);
+
+class QSGD3D12WindowEvent : public QEvent
+{
+public:
+ QSGD3D12WindowEvent(QQuickWindow *c, QEvent::Type type) : QEvent(type), window(c) { }
+ QQuickWindow *window;
+};
+
+class QSGD3D12TryReleaseEvent : public QSGD3D12WindowEvent
+{
+public:
+ QSGD3D12TryReleaseEvent(QQuickWindow *win, bool destroy)
+ : QSGD3D12WindowEvent(win, WM_TryRelease), destroying(destroy) { }
+ bool destroying;
+};
+
+class QSGD3D12SyncEvent : public QSGD3D12WindowEvent
+{
+public:
+ QSGD3D12SyncEvent(QQuickWindow *c, bool inExpose, bool force)
+ : QSGD3D12WindowEvent(c, WM_RequestSync)
+ , size(c->size())
+ , dpr(c->effectiveDevicePixelRatio())
+ , syncInExpose(inExpose)
+ , forceRenderPass(force) { }
+ QSize size;
+ float dpr;
+ bool syncInExpose;
+ bool forceRenderPass;
+};
+
+class QSGD3D12GrabEvent : public QSGD3D12WindowEvent
+{
+public:
+ QSGD3D12GrabEvent(QQuickWindow *c, QImage *result)
+ : QSGD3D12WindowEvent(c, WM_Grab), image(result) { }
+ QImage *image;
+};
+
+class QSGD3D12JobEvent : public QSGD3D12WindowEvent
+{
+public:
+ QSGD3D12JobEvent(QQuickWindow *c, QRunnable *postedJob)
+ : QSGD3D12WindowEvent(c, WM_PostJob), job(postedJob) { }
+ ~QSGD3D12JobEvent() { delete job; }
+ QRunnable *job;
+};
+
+class QSGD3D12EventQueue : public QQueue<QEvent *>
+{
+public:
+ void addEvent(QEvent *e) {
+ mutex.lock();
+ enqueue(e);
+ if (waiting)
+ condition.wakeOne();
+ mutex.unlock();
+ }
+
+ QEvent *takeEvent(bool wait) {
+ mutex.lock();
+ if (isEmpty() && wait) {
+ waiting = true;
+ condition.wait(&mutex);
+ waiting = false;
+ }
+ QEvent *e = dequeue();
+ mutex.unlock();
+ return e;
+ }
+
+ bool hasMoreEvents() {
+ mutex.lock();
+ bool has = !isEmpty();
+ mutex.unlock();
+ return has;
+ }
+
+private:
+ QMutex mutex;
+ QWaitCondition condition;
+ bool waiting = false;
+};
+
+static inline int qsgrl_animation_interval()
+{
+ const qreal refreshRate = QGuiApplication::primaryScreen() ? QGuiApplication::primaryScreen()->refreshRate() : 0;
+ return refreshRate < 1 ? 16 : int(1000 / refreshRate);
+}
+
+class QSGD3D12RenderThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ QSGD3D12RenderThread(QSGD3D12ThreadedRenderLoop *rl, QSGRenderContext *renderContext)
+ : renderLoop(rl)
+ {
+ rc = static_cast<QSGD3D12RenderContext *>(renderContext);
+ vsyncDelta = qsgrl_animation_interval();
+ }
+
+ ~QSGD3D12RenderThread()
+ {
+ delete rc;
+ }
+
+ bool event(QEvent *e);
+ void run();
+
+ void syncAndRender();
+ void sync(bool inExpose);
+
+ void requestRepaint()
+ {
+ if (sleeping)
+ stopEventProcessing = true;
+ if (exposedWindow)
+ pendingUpdate |= RepaintRequest;
+ }
+
+ void processEventsAndWaitForMore();
+ void processEvents();
+ void postEvent(QEvent *e);
+
+ enum UpdateRequest {
+ SyncRequest = 0x01,
+ RepaintRequest = 0x02,
+ ExposeRequest = 0x04 | RepaintRequest | SyncRequest
+ };
+
+ QSGD3D12Engine *engine = nullptr;
+ QSGD3D12ThreadedRenderLoop *renderLoop;
+ QSGD3D12RenderContext *rc;
+ QAnimationDriver *rtAnim = nullptr;
+ volatile bool active = false;
+ uint pendingUpdate = 0;
+ bool sleeping = false;
+ bool syncResultedInChanges = false;
+ float vsyncDelta;
+ QMutex mutex;
+ QWaitCondition waitCondition;
+ QQuickWindow *exposedWindow = nullptr;
+ bool stopEventProcessing = false;
+ QSGD3D12EventQueue eventQueue;
+ QElapsedTimer threadTimer;
+ qint64 syncTime;
+ qint64 renderTime;
+ qint64 sinceLastTime;
+
+public slots:
+ void onSceneGraphChanged() {
+ syncResultedInChanges = true;
+ }
+};
+
+bool QSGD3D12RenderThread::event(QEvent *e)
+{
+ switch (e->type()) {
+
+ case WM_Obscure:
+ Q_ASSERT(!exposedWindow || exposedWindow == static_cast<QSGD3D12WindowEvent *>(e)->window);
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "RT - WM_Obscure" << exposedWindow;
+ mutex.lock();
+ if (exposedWindow) {
+ QQuickWindowPrivate::get(exposedWindow)->fireAboutToStop();
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_Obscure - window removed");
+ exposedWindow = nullptr;
+ }
+ waitCondition.wakeOne();
+ mutex.unlock();
+ return true;
+
+ case WM_RequestSync: {
+ QSGD3D12SyncEvent *wme = static_cast<QSGD3D12SyncEvent *>(e);
+ if (sleeping)
+ stopEventProcessing = true;
+ // One thread+engine for each window. However, the native window may
+ // change in some (quite artificial) cases, e.g. due to a hide -
+ // destroy - show on the QWindow.
+ bool needsWindow = !engine->window();
+ if (engine->window() && engine->window() != wme->window->winId()) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_RequestSync - native window handle changes for active engine");
+ engine->waitGPU();
+ QQuickWindowPrivate::get(wme->window)->cleanupNodesOnShutdown();
+ QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
+ rc->invalidate();
+ engine->releaseResources();
+ needsWindow = true;
+ }
+ if (needsWindow) {
+ // Must only ever get here when there is no window or releaseResources() has been called.
+ const int samples = wme->window->format().samples();
+ const bool alpha = wme->window->format().alphaBufferSize() > 0;
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "RT - WM_RequestSync - initializing D3D12 engine" << wme->window
+ << wme->size << wme->dpr << samples << alpha;
+ engine->attachToWindow(wme->window->winId(), wme->size, wme->dpr, samples, alpha);
+ }
+ exposedWindow = wme->window;
+ engine->setWindowSize(wme->size, wme->dpr);
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "RT - WM_RequestSync" << exposedWindow;
+ pendingUpdate |= SyncRequest;
+ if (wme->syncInExpose) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_RequestSync - triggered from expose");
+ pendingUpdate |= ExposeRequest;
+ }
+ if (wme->forceRenderPass) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_RequestSync - repaint regardless");
+ pendingUpdate |= RepaintRequest;
+ }
+ return true;
+ }
+
+ case WM_TryRelease: {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_TryRelease");
+ mutex.lock();
+ renderLoop->lockedForSync = true;
+ QSGD3D12TryReleaseEvent *wme = static_cast<QSGD3D12TryReleaseEvent *>(e);
+ // Only when no windows are exposed anymore or we are shutting down.
+ if (!exposedWindow || wme->destroying) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_TryRelease - invalidating rc");
+ if (wme->window) {
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window);
+ if (wme->destroying) {
+ // QSGNode destruction may release graphics resources in use so wait first.
+ engine->waitGPU();
+ // Bye bye nodes...
+ wd->cleanupNodesOnShutdown();
+ QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
+ }
+ rc->invalidate();
+ QCoreApplication::processEvents();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ if (wme->destroying)
+ delete wd->animationController;
+ }
+ if (wme->destroying)
+ active = false;
+ if (sleeping)
+ stopEventProcessing = true;
+ } else {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_TryRelease - not releasing because window is still active");
+ }
+ waitCondition.wakeOne();
+ renderLoop->lockedForSync = false;
+ mutex.unlock();
+ return true;
+ }
+
+ case WM_Grab: {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_Grab");
+ QSGD3D12GrabEvent *wme = static_cast<QSGD3D12GrabEvent *>(e);
+ Q_ASSERT(wme->window);
+ Q_ASSERT(wme->window == exposedWindow || !exposedWindow);
+ mutex.lock();
+ if (wme->window) {
+ // Grabbing is generally done by rendering a frame and reading the
+ // color buffer contents back, without presenting, and then
+ // creating a QImage from the returned data. It is terribly
+ // inefficient since it involves a full blocking wait for the GPU.
+ // However, our hands are tied by the existing, synchronous APIs of
+ // QQuickWindow and such.
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window);
+ rc->initialize(nullptr);
+ wd->syncSceneGraph();
+ wd->renderSceneGraph(wme->window->size());
+ *wme->image = engine->executeAndWaitReadbackRenderTarget();
+ }
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_Grab - waking gui to handle result");
+ waitCondition.wakeOne();
+ mutex.unlock();
+ return true;
+ }
+
+ case WM_PostJob: {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_PostJob");
+ QSGD3D12JobEvent *wme = static_cast<QSGD3D12JobEvent *>(e);
+ Q_ASSERT(wme->window == exposedWindow);
+ if (exposedWindow) {
+ wme->job->run();
+ delete wme->job;
+ wme->job = nullptr;
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_PostJob - job done");
+ }
+ return true;
+ }
+
+ case WM_RequestRepaint:
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - WM_RequestPaint");
+ // When GUI posts this event, it is followed by a polishAndSync, so we
+ // must not exit the event loop yet.
+ pendingUpdate |= RepaintRequest;
+ break;
+
+ default:
+ break;
+ }
+
+ return QThread::event(e);
+}
+
+void QSGD3D12RenderThread::postEvent(QEvent *e)
+{
+ eventQueue.addEvent(e);
+}
+
+void QSGD3D12RenderThread::processEvents()
+{
+ while (eventQueue.hasMoreEvents()) {
+ QEvent *e = eventQueue.takeEvent(false);
+ event(e);
+ delete e;
+ }
+}
+
+void QSGD3D12RenderThread::processEventsAndWaitForMore()
+{
+ stopEventProcessing = false;
+ while (!stopEventProcessing) {
+ QEvent *e = eventQueue.takeEvent(true);
+ event(e);
+ delete e;
+ }
+}
+
+void QSGD3D12RenderThread::run()
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - run()");
+
+ engine = new QSGD3D12Engine;
+ rc->setEngine(engine);
+
+ rtAnim = rc->sceneGraphContext()->createAnimationDriver(nullptr);
+ rtAnim->install();
+
+ if (QQmlDebugConnector::service<QQmlProfilerService>())
+ QQuickProfiler::registerAnimationCallback();
+
+ while (active) {
+ if (exposedWindow)
+ syncAndRender();
+
+ processEvents();
+ QCoreApplication::processEvents();
+
+ if (pendingUpdate == 0 || !exposedWindow) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - done drawing, sleep");
+ sleeping = true;
+ processEventsAndWaitForMore();
+ sleeping = false;
+ }
+ }
+
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - run() exiting");
+
+ delete rtAnim;
+ rtAnim = nullptr;
+
+ rc->moveToThread(renderLoop->thread());
+ moveToThread(renderLoop->thread());
+
+ rc->setEngine(nullptr);
+ delete engine;
+ engine = nullptr;
+}
+
+void QSGD3D12RenderThread::sync(bool inExpose)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - sync");
+
+ mutex.lock();
+ Q_ASSERT_X(renderLoop->lockedForSync, "QSGD3D12RenderThread::sync()", "sync triggered with gui not locked");
+
+ // Recover from device loss.
+ if (!engine->hasResources()) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - sync - device was lost, resetting scenegraph");
+ QQuickWindowPrivate::get(exposedWindow)->cleanupNodesOnShutdown();
+ QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
+ rc->invalidate();
+ }
+
+ if (engine->window()) {
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow);
+ bool hadRenderer = wd->renderer != nullptr;
+ // If the scene graph was touched since the last sync() make sure it sends the
+ // changed signal.
+ if (wd->renderer)
+ wd->renderer->clearChangedFlag();
+
+ rc->initialize(nullptr);
+ wd->syncSceneGraph();
+
+ if (!hadRenderer && wd->renderer) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - created renderer");
+ syncResultedInChanges = true;
+ connect(wd->renderer, &QSGRenderer::sceneGraphChanged, this,
+ &QSGD3D12RenderThread::onSceneGraphChanged, Qt::DirectConnection);
+ }
+
+ // Process deferred deletes now, directly after the sync as deleteLater
+ // on the GUI must now also have resulted in SG changes and the delete
+ // is a safe operation.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ }
+
+ if (!inExpose) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - sync complete, waking gui");
+ waitCondition.wakeOne();
+ mutex.unlock();
+ }
+}
+
+void QSGD3D12RenderThread::syncAndRender()
+{
+ if (Q_UNLIKELY(debug_time())) {
+ sinceLastTime = threadTimer.nsecsElapsed();
+ threadTimer.start();
+ }
+ Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ QElapsedTimer waitTimer;
+ waitTimer.start();
+
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - syncAndRender()");
+
+ syncResultedInChanges = false;
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow);
+
+ const bool repaintRequested = (pendingUpdate & RepaintRequest) || wd->customRenderStage;
+ const bool syncRequested = pendingUpdate & SyncRequest;
+ const bool exposeRequested = (pendingUpdate & ExposeRequest) == ExposeRequest;
+ pendingUpdate = 0;
+
+ if (syncRequested)
+ sync(exposeRequested);
+
+#ifndef QSG_NO_RENDER_TIMING
+ if (Q_UNLIKELY(debug_time()))
+ syncTime = threadTimer.nsecsElapsed();
+#endif
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ if (!syncResultedInChanges && !repaintRequested) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - no changes, render aborted");
+ int waitTime = vsyncDelta - (int) waitTimer.elapsed();
+ if (waitTime > 0)
+ msleep(waitTime);
+ return;
+ }
+
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - rendering started");
+
+ if (rtAnim->isRunning()) {
+ wd->animationController->lock();
+ rtAnim->advance();
+ wd->animationController->unlock();
+ }
+
+ bool canRender = wd->renderer != nullptr;
+ // Recover from device loss.
+ if (!engine->hasResources()) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - syncAndRender - device was lost, posting FullUpdateRequest");
+ // Cannot do anything here because gui is not locked. Request a new
+ // sync+render round on the gui thread and let the sync handle it.
+ QCoreApplication::postEvent(exposedWindow, new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)));
+ canRender = false;
+ }
+
+ if (canRender) {
+ wd->renderSceneGraph(engine->windowSize());
+ if (Q_UNLIKELY(debug_time()))
+ renderTime = threadTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ // The engine is able to have multiple frames in flight. This in effect is
+ // similar to BufferQueueingOpenGL. Provide an env var to force the
+ // traditional blocking swap behavior, just in case.
+ static bool blockOnEachFrame = qEnvironmentVariableIntValue("QT_D3D_BLOCKING_PRESENT") != 0;
+
+ if (!wd->customRenderStage || !wd->customRenderStage->swap())
+ engine->present();
+
+ if (blockOnEachFrame)
+ engine->waitGPU();
+
+ // The concept of "frame swaps" is quite misleading by default, when
+ // blockOnEachFrame is not used, but emit it for compatibility.
+ wd->fireFrameSwapped();
+ } else {
+ Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame, 1);
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - window not ready, skipping render");
+ }
+
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - rendering done");
+
+ if (exposeRequested) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("RT - wake gui after initial expose");
+ waitCondition.wakeOne();
+ mutex.unlock();
+ }
+
+ if (Q_UNLIKELY(debug_time()))
+ qDebug("Frame rendered with 'd3d12' renderloop in %dms, sync=%d, render=%d, swap=%d - (on render thread)",
+ int(threadTimer.elapsed()),
+ int((syncTime/1000000)),
+ int((renderTime - syncTime) / 1000000),
+ int(threadTimer.elapsed() - renderTime / 1000000));
+
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ static int devLossTest = qEnvironmentVariableIntValue("QT_D3D_TEST_DEVICE_LOSS");
+ if (devLossTest > 0) {
+ static QElapsedTimer kt;
+ static bool timerRunning = false;
+ if (!timerRunning) {
+ kt.start();
+ timerRunning = true;
+ } else if (kt.elapsed() > 5000) {
+ --devLossTest;
+ kt.restart();
+ engine->simulateDeviceLoss();
+ }
+ }
+}
+
+template<class T> T *windowFor(const QVector<T> &list, QQuickWindow *window)
+{
+ for (const T &t : list) {
+ if (t.window == window)
+ return const_cast<T *>(&t);
+ }
+ return nullptr;
+}
+
+QSGD3D12ThreadedRenderLoop::QSGD3D12ThreadedRenderLoop()
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("d3d12 THREADED render loop ctor");
+
+ sg = new QSGD3D12Context;
+
+ anim = sg->createAnimationDriver(this);
+ connect(anim, &QAnimationDriver::started, this, &QSGD3D12ThreadedRenderLoop::onAnimationStarted);
+ connect(anim, &QAnimationDriver::stopped, this, &QSGD3D12ThreadedRenderLoop::onAnimationStopped);
+ anim->install();
+}
+
+QSGD3D12ThreadedRenderLoop::~QSGD3D12ThreadedRenderLoop()
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("d3d12 THREADED render loop dtor");
+
+ delete sg;
+}
+
+void QSGD3D12ThreadedRenderLoop::show(QQuickWindow *window)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "show" << window;
+}
+
+void QSGD3D12ThreadedRenderLoop::hide(QQuickWindow *window)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "hide" << window;
+
+ if (window->isExposed())
+ handleObscurity(windowFor(windows, window));
+
+ releaseResources(window);
+}
+
+void QSGD3D12ThreadedRenderLoop::resize(QQuickWindow *window)
+{
+ if (!window->isExposed() || window->size().isEmpty())
+ return;
+
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "resize" << window << window->size();
+}
+
+void QSGD3D12ThreadedRenderLoop::windowDestroyed(QQuickWindow *window)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "window destroyed" << window;
+
+ WindowData *w = windowFor(windows, window);
+ if (!w)
+ return;
+
+ handleObscurity(w);
+ handleResourceRelease(w, true);
+
+ QSGD3D12RenderThread *thread = w->thread;
+ while (thread->isRunning())
+ QThread::yieldCurrentThread();
+
+ Q_ASSERT(thread->thread() == QThread::currentThread());
+ delete thread;
+
+ for (int i = 0; i < windows.size(); ++i) {
+ if (windows.at(i).window == window) {
+ windows.removeAt(i);
+ break;
+ }
+ }
+}
+
+void QSGD3D12ThreadedRenderLoop::exposureChanged(QQuickWindow *window)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "exposure changed" << window;
+
+ if (window->isExposed()) {
+ handleExposure(window);
+ } else {
+ WindowData *w = windowFor(windows, window);
+ if (w)
+ handleObscurity(w);
+ }
+}
+
+QImage QSGD3D12ThreadedRenderLoop::grab(QQuickWindow *window)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "grab" << window;
+
+ WindowData *w = windowFor(windows, window);
+ // Have to support invisible (but created()'ed) windows as well.
+ // Unlike with GL, leaving that case for QQuickWindow to handle is not feasible.
+ const bool tempExpose = !w;
+ if (tempExpose) {
+ handleExposure(window);
+ w = windowFor(windows, window);
+ Q_ASSERT(w);
+ }
+
+ if (!w->thread->isRunning())
+ return QImage();
+
+ if (!window->handle())
+ window->create();
+
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ wd->polishItems();
+
+ QImage result;
+ w->thread->mutex.lock();
+ lockedForSync = true;
+ w->thread->postEvent(new QSGD3D12GrabEvent(window, &result));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ lockedForSync = false;
+ w->thread->mutex.unlock();
+
+ result.setDevicePixelRatio(window->effectiveDevicePixelRatio());
+
+ if (tempExpose)
+ handleObscurity(w);
+
+ return result;
+}
+
+void QSGD3D12ThreadedRenderLoop::update(QQuickWindow *window)
+{
+ WindowData *w = windowFor(windows, window);
+ if (!w)
+ return;
+
+ if (w->thread == QThread::currentThread()) {
+ w->thread->requestRepaint();
+ return;
+ }
+
+ // We set forceRenderPass because we want to make sure the QQuickWindow
+ // actually does a full render pass after the next sync.
+ w->forceRenderPass = true;
+ scheduleUpdate(w);
+}
+
+void QSGD3D12ThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
+{
+ WindowData *w = windowFor(windows, window);
+ if (w)
+ scheduleUpdate(w);
+}
+
+// called in response to window->requestUpdate()
+void QSGD3D12ThreadedRenderLoop::handleUpdateRequest(QQuickWindow *window)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "handleUpdateRequest" << window;
+
+ WindowData *w = windowFor(windows, window);
+ if (w)
+ polishAndSync(w, false);
+}
+
+QAnimationDriver *QSGD3D12ThreadedRenderLoop::animationDriver() const
+{
+ return anim;
+}
+
+QSGContext *QSGD3D12ThreadedRenderLoop::sceneGraphContext() const
+{
+ return sg;
+}
+
+QSGRenderContext *QSGD3D12ThreadedRenderLoop::createRenderContext(QSGContext *) const
+{
+ return sg->createRenderContext();
+}
+
+void QSGD3D12ThreadedRenderLoop::releaseResources(QQuickWindow *window)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "releaseResources" << window;
+
+ WindowData *w = windowFor(windows, window);
+ if (w)
+ handleResourceRelease(w, false);
+}
+
+void QSGD3D12ThreadedRenderLoop::postJob(QQuickWindow *window, QRunnable *job)
+{
+ WindowData *w = windowFor(windows, window);
+ if (w && w->thread && w->thread->exposedWindow)
+ w->thread->postEvent(new QSGD3D12JobEvent(window, job));
+ else
+ delete job;
+}
+
+QSurface::SurfaceType QSGD3D12ThreadedRenderLoop::windowSurfaceType() const
+{
+ return QSurface::OpenGLSurface;
+}
+
+bool QSGD3D12ThreadedRenderLoop::interleaveIncubation() const
+{
+ bool somethingVisible = false;
+ for (const WindowData &w : windows) {
+ if (w.window->isVisible() && w.window->isExposed()) {
+ somethingVisible = true;
+ break;
+ }
+ }
+ return somethingVisible && anim->isRunning();
+}
+
+int QSGD3D12ThreadedRenderLoop::flags() const
+{
+ return SupportsGrabWithoutExpose;
+}
+
+bool QSGD3D12ThreadedRenderLoop::event(QEvent *e)
+{
+ if (e->type() == QEvent::Timer) {
+ QTimerEvent *te = static_cast<QTimerEvent *>(e);
+ if (te->timerId() == animationTimer) {
+ anim->advance();
+ emit timeToIncubate();
+ return true;
+ }
+ }
+
+ return QObject::event(e);
+}
+
+void QSGD3D12ThreadedRenderLoop::onAnimationStarted()
+{
+ startOrStopAnimationTimer();
+
+ for (const WindowData &w : qAsConst(windows))
+ w.window->requestUpdate();
+}
+
+void QSGD3D12ThreadedRenderLoop::onAnimationStopped()
+{
+ startOrStopAnimationTimer();
+}
+
+void QSGD3D12ThreadedRenderLoop::startOrStopAnimationTimer()
+{
+ int exposedWindowCount = 0;
+ const WindowData *exposed = nullptr;
+
+ for (int i = 0; i < windows.size(); ++i) {
+ const WindowData &w(windows[i]);
+ if (w.window->isVisible() && w.window->isExposed()) {
+ ++exposedWindowCount;
+ exposed = &w;
+ }
+ }
+
+ if (animationTimer && (exposedWindowCount == 1 || !anim->isRunning())) {
+ killTimer(animationTimer);
+ animationTimer = 0;
+ // If animations are running, make sure we keep on animating
+ if (anim->isRunning())
+ exposed->window->requestUpdate();
+ } else if (!animationTimer && exposedWindowCount != 1 && anim->isRunning()) {
+ animationTimer = startTimer(qsgrl_animation_interval());
+ }
+}
+
+void QSGD3D12ThreadedRenderLoop::handleExposure(QQuickWindow *window)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "handleExposure" << window;
+
+ WindowData *w = windowFor(windows, window);
+ if (!w) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("adding window to list");
+ WindowData win;
+ win.window = window;
+ QSGRenderContext *rc = QQuickWindowPrivate::get(window)->context; // will transfer ownership
+ win.thread = new QSGD3D12RenderThread(this, rc);
+ win.updateDuringSync = false;
+ win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt
+ windows.append(win);
+ w = &windows.last();
+ }
+
+ // set this early as we'll be rendering shortly anyway and this avoids
+ // special casing exposure in polishAndSync.
+ w->thread->exposedWindow = window;
+
+ if (w->window->size().isEmpty()
+ || (w->window->isTopLevel() && !w->window->geometry().intersects(w->window->screen()->availableGeometry()))) {
+#ifndef QT_NO_DEBUG
+ qWarning().noquote().nospace() << "QSGD3D12ThreadedRenderLoop: expose event received for window "
+ << w->window << " with invalid geometry: " << w->window->geometry()
+ << " on " << w->window->screen();
+#endif
+ }
+
+ if (!w->window->handle())
+ w->window->create();
+
+ // Start render thread if it is not running
+ if (!w->thread->isRunning()) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("starting render thread");
+ // Push a few things to the render thread.
+ QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController;
+ if (controller->thread() != w->thread)
+ controller->moveToThread(w->thread);
+ if (w->thread->thread() == QThread::currentThread()) {
+ w->thread->rc->moveToThread(w->thread);
+ w->thread->moveToThread(w->thread);
+ }
+
+ w->thread->active = true;
+ w->thread->start();
+
+ if (!w->thread->isRunning())
+ qFatal("Render thread failed to start, aborting application.");
+ }
+
+ polishAndSync(w, true);
+
+ startOrStopAnimationTimer();
+}
+
+void QSGD3D12ThreadedRenderLoop::handleObscurity(WindowData *w)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "handleObscurity" << w->window;
+
+ if (w->thread->isRunning()) {
+ w->thread->mutex.lock();
+ w->thread->postEvent(new QSGD3D12WindowEvent(w->window, WM_Obscure));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ w->thread->mutex.unlock();
+ }
+
+ startOrStopAnimationTimer();
+}
+
+void QSGD3D12ThreadedRenderLoop::scheduleUpdate(WindowData *w)
+{
+ if (!QCoreApplication::instance())
+ return;
+
+ if (!w || !w->thread->isRunning())
+ return;
+
+ QThread *current = QThread::currentThread();
+ if (current != QCoreApplication::instance()->thread() && (current != w->thread || !lockedForSync)) {
+ qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()";
+ return;
+ }
+
+ if (current == w->thread) {
+ w->updateDuringSync = true;
+ return;
+ }
+
+ w->window->requestUpdate();
+}
+
+void QSGD3D12ThreadedRenderLoop::handleResourceRelease(WindowData *w, bool destroying)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "handleResourceRelease" << (destroying ? "destroying" : "hide/releaseResources") << w->window;
+
+ w->thread->mutex.lock();
+ if (w->thread->isRunning() && w->thread->active) {
+ QQuickWindow *window = w->window;
+
+ // Note that window->handle() is typically null by this time because
+ // the platform window is already destroyed. This should not be a
+ // problem for the D3D cleanup.
+
+ w->thread->postEvent(new QSGD3D12TryReleaseEvent(window, destroying));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+
+ // Avoid a shutdown race condition.
+ // If SG is invalidated and 'active' becomes false, the thread's run()
+ // method will exit. handleExposure() relies on QThread::isRunning() (because it
+ // potentially needs to start the thread again) and our mutex cannot be used to
+ // track the thread stopping, so we wait a few nanoseconds extra so the thread
+ // can exit properly.
+ if (!w->thread->active)
+ w->thread->wait();
+ }
+ w->thread->mutex.unlock();
+}
+
+void QSGD3D12ThreadedRenderLoop::polishAndSync(WindowData *w, bool inExpose)
+{
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug() << "polishAndSync" << (inExpose ? "(in expose)" : "(normal)") << w->window;
+
+ QQuickWindow *window = w->window;
+ if (!w->thread || !w->thread->exposedWindow) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("polishAndSync - not exposed, abort");
+ return;
+ }
+
+ // Flush pending touch events.
+ QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
+ // The delivery of the event might have caused the window to stop rendering
+ w = windowFor(windows, window);
+ if (!w || !w->thread || !w->thread->exposedWindow) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("polishAndSync - removed after touch event flushing, abort");
+ return;
+ }
+
+ QElapsedTimer timer;
+ qint64 polishTime = 0;
+ qint64 waitTime = 0;
+ qint64 syncTime = 0;
+ if (Q_UNLIKELY(debug_time()))
+ timer.start();
+ Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync);
+
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ wd->polishItems();
+
+ if (Q_UNLIKELY(debug_time()))
+ polishTime = timer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
+
+ w->updateDuringSync = false;
+
+ emit window->afterAnimating();
+
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("polishAndSync - lock for sync");
+ w->thread->mutex.lock();
+ lockedForSync = true;
+ w->thread->postEvent(new QSGD3D12SyncEvent(window, inExpose, w->forceRenderPass));
+ w->forceRenderPass = false;
+
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("polishAndSync - wait for sync");
+ if (Q_UNLIKELY(debug_time()))
+ waitTime = timer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ lockedForSync = false;
+ w->thread->mutex.unlock();
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("polishAndSync - unlock after sync");
+
+ if (Q_UNLIKELY(debug_time()))
+ syncTime = timer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
+
+ if (!animationTimer && anim->isRunning()) {
+ if (Q_UNLIKELY(debug_loop()))
+ qDebug("polishAndSync - advancing animations");
+ anim->advance();
+ // We need to trigger another sync to keep animations running...
+ w->window->requestUpdate();
+ emit timeToIncubate();
+ } else if (w->updateDuringSync) {
+ w->window->requestUpdate();
+ }
+
+ if (Q_UNLIKELY(debug_time()))
+ qDebug().nospace()
+ << "Frame prepared with 'd3d12' renderloop"
+ << ", polish=" << (polishTime / 1000000)
+ << ", lock=" << (waitTime - polishTime) / 1000000
+ << ", blockedForSync=" << (syncTime - waitTime) / 1000000
+ << ", animations=" << (timer.nsecsElapsed() - syncTime) / 1000000
+ << " - (on gui thread) " << window;
+
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync);
+}
+
+#include "qsgd3d12threadedrenderloop.moc"
+
+QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop_p.h
new file mode 100644
index 0000000000..46f62948f1
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop_p.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12THREADEDRENDERLOOP_P_H
+#define QSGD3D12THREADEDRENDERLOOP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgrenderloop_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12Engine;
+class QSGD3D12Context;
+class QSGD3D12RenderContext;
+class QSGD3D12RenderThread;
+
+class QSGD3D12ThreadedRenderLoop : public QSGRenderLoop
+{
+ Q_OBJECT
+
+public:
+ QSGD3D12ThreadedRenderLoop();
+ ~QSGD3D12ThreadedRenderLoop();
+
+ void show(QQuickWindow *window) override;
+ void hide(QQuickWindow *window) override;
+ void resize(QQuickWindow *window) override;
+
+ void windowDestroyed(QQuickWindow *window) override;
+
+ void exposureChanged(QQuickWindow *window) override;
+
+ QImage grab(QQuickWindow *window) override;
+
+ void update(QQuickWindow *window) override;
+ void maybeUpdate(QQuickWindow *window) override;
+ void handleUpdateRequest(QQuickWindow *window) override;
+
+ QAnimationDriver *animationDriver() const override;
+
+ QSGContext *sceneGraphContext() const override;
+ QSGRenderContext *createRenderContext(QSGContext *) const override;
+
+ void releaseResources(QQuickWindow *window) override;
+ void postJob(QQuickWindow *window, QRunnable *job) override;
+
+ QSurface::SurfaceType windowSurfaceType() const override;
+ bool interleaveIncubation() const override;
+ int flags() const override;
+
+ bool event(QEvent *e) override;
+
+public Q_SLOTS:
+ void onAnimationStarted();
+ void onAnimationStopped();
+
+private:
+ struct WindowData {
+ QQuickWindow *window;
+ QSGD3D12RenderThread *thread;
+ uint updateDuringSync : 1;
+ uint forceRenderPass : 1;
+ };
+
+ void startOrStopAnimationTimer();
+ void handleExposure(QQuickWindow *window);
+ void handleObscurity(WindowData *w);
+ void scheduleUpdate(WindowData *w);
+ void handleResourceRelease(WindowData *w, bool destroying);
+ void polishAndSync(WindowData *w, bool inExpose);
+
+ QSGD3D12Context *sg;
+ QAnimationDriver *anim;
+ int animationTimer = 0;
+ bool lockedForSync = false;
+ QVector<WindowData> windows;
+
+ friend class QSGD3D12RenderThread;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12THREADEDRENDERLOOP_P_H
diff --git a/src/plugins/scenegraph/d3d12/shaders/shaders.pri b/src/plugins/scenegraph/d3d12/shaders/shaders.pri
index 41f0ee80f7..963f4c5d8c 100644
--- a/src/plugins/scenegraph/d3d12/shaders/shaders.pri
+++ b/src/plugins/scenegraph/d3d12/shaders/shaders.pri
@@ -108,6 +108,16 @@ shadereffectdefault_pshader.header = ps_shadereffectdefault.hlslh
shadereffectdefault_pshader.entry = PS_DefaultShaderEffect
shadereffectdefault_pshader.type = ps_5_0
+sprite_VSPS = $$PWD/sprite.hlsl
+sprite_vshader.input = sprite_VSPS
+sprite_vshader.header = vs_sprite.hlslh
+sprite_vshader.entry = VS_Sprite
+sprite_vshader.type = vs_5_0
+sprite_pshader.input = sprite_VSPS
+sprite_pshader.header = ps_sprite.hlslh
+sprite_pshader.entry = PS_Sprite
+sprite_pshader.type = ps_5_0
+
tdr_CS = $$PWD/tdr.hlsl
tdr_cshader.input = tdr_CS
tdr_cshader.header = cs_tdr.hlslh
@@ -125,6 +135,7 @@ HLSL_SHADERS = \
textmask_vshader textmask_pshader24 textmask_pshader32 textmask_pshader8 \
styledtext_vshader styledtext_pshader outlinedtext_vshader outlinedtext_pshader \
shadereffectdefault_vshader shadereffectdefault_pshader \
+ sprite_vshader sprite_pshader \
tdr_cshader
load(hlsl_bytecode_header)
diff --git a/src/plugins/scenegraph/d3d12/shaders/sprite.hlsl b/src/plugins/scenegraph/d3d12/shaders/sprite.hlsl
new file mode 100644
index 0000000000..d4e3b066ee
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/shaders/sprite.hlsl
@@ -0,0 +1,43 @@
+struct VSInput
+{
+ float4 position : POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 mvp;
+ float4 animPos;
+ float3 animData;
+ float opacity;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float4 fTexS : TEXCOORD0;
+ float progress : TEXCOORD1;
+};
+
+Texture2D tex : register(t0);
+SamplerState samp : register(s0);
+
+PSInput VS_Sprite(VSInput input)
+{
+ PSInput result;
+
+ result.position = mul(mvp, input.position);
+ result.progress = animData.z;
+
+ // Calculate frame location in texture
+ result.fTexS.xy = animPos.xy + input.coord.xy * animData.xy;
+ // Next frame is also passed, for interpolation
+ result.fTexS.zw = animPos.zw + input.coord.xy * animData.xy;
+
+ return result;
+}
+
+float4 PS_Sprite(PSInput input) : SV_TARGET
+{
+ return lerp(tex.Sample(samp, input.fTexS.xy), tex.Sample(samp, input.fTexS.zw), input.progress) * opacity;
+}
diff --git a/src/plugins/scenegraph/d3d12/shaders/textmask.hlsl b/src/plugins/scenegraph/d3d12/shaders/textmask.hlsl
index f9d92e8ee9..bb9381e7c0 100644
--- a/src/plugins/scenegraph/d3d12/shaders/textmask.hlsl
+++ b/src/plugins/scenegraph/d3d12/shaders/textmask.hlsl
@@ -45,7 +45,7 @@ float4 PS_TextMask32(PSInput input) : SV_TARGET
float4 PS_TextMask8(PSInput input) : SV_TARGET
{
- return colorVec * tex.Sample(samp, input.coord).r;
+ return colorVec * tex.Sample(samp, input.coord).a;
}
struct StyledPSInput
@@ -66,8 +66,8 @@ StyledPSInput VS_StyledText(VSInput input)
float4 PS_StyledText(StyledPSInput input) : SV_TARGET
{
- float glyph = tex.Sample(samp, input.coord).r;
- float style = clamp(tex.Sample(samp, input.shiftedCoord).r - glyph, 0.0, 1.0);
+ float glyph = tex.Sample(samp, input.coord).a;
+ float style = clamp(tex.Sample(samp, input.shiftedCoord).a - glyph, 0.0, 1.0);
return style * styleColor + glyph * colorVec;
}
@@ -95,10 +95,10 @@ OutlinedPSInput VS_OutlinedText(VSInput input)
float4 PS_OutlinedText(OutlinedPSInput input) : SV_TARGET
{
- float glyph = tex.Sample(samp, input.coord).r;
- float outline = clamp(clamp(tex.Sample(samp, input.coordUp).r
- + tex.Sample(samp, input.coordDown).r
- + tex.Sample(samp, input.coordLeft).r
- + tex.Sample(samp, input.coordRight).r, 0.0, 1.0) - glyph, 0.0, 1.0);
+ float glyph = tex.Sample(samp, input.coord).a;
+ float outline = clamp(clamp(tex.Sample(samp, input.coordUp).a
+ + tex.Sample(samp, input.coordDown).a
+ + tex.Sample(samp, input.coordLeft).a
+ + tex.Sample(samp, input.coordRight).a, 0.0, 1.0) - glyph, 0.0, 1.0);
return outline * styleColor + glyph * colorVec;
}
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index 9bcd63127a..26965c0264 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -75,7 +75,7 @@ public:
//called by QAbstractAnimationJob
virtual void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
protected:
- void topLevelAnimationLoopChanged();
+ void topLevelAnimationLoopChanged() override;
virtual void animationInserted(QAbstractAnimationJob*) { }
virtual void animationRemoved(QAbstractAnimationJob*, QAbstractAnimationJob*, QAbstractAnimationJob*);
diff --git a/src/qml/animations/qparallelanimationgroupjob_p.h b/src/qml/animations/qparallelanimationgroupjob_p.h
index 3e914c3e76..358b95ce53 100644
--- a/src/qml/animations/qparallelanimationgroupjob_p.h
+++ b/src/qml/animations/qparallelanimationgroupjob_p.h
@@ -62,14 +62,14 @@ public:
QParallelAnimationGroupJob();
~QParallelAnimationGroupJob();
- int duration() const;
+ int duration() const override;
protected:
- void updateCurrentTime(int currentTime);
- void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
- void updateDirection(QAbstractAnimationJob::Direction direction);
- void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
- void debugAnimation(QDebug d) const;
+ void updateCurrentTime(int currentTime) override;
+ void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) override;
+ void updateDirection(QAbstractAnimationJob::Direction direction) override;
+ void uncontrolledAnimationFinished(QAbstractAnimationJob *animation) override;
+ void debugAnimation(QDebug d) const override;
private:
bool shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const;
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 585fef7603..e49f5c40a5 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -26,12 +26,21 @@ SOURCES += \
HEADERS += \
$$PWD/qqmltypecompiler_p.h \
$$PWD/qv4isel_moth_p.h \
- $$PWD/qv4instr_moth_p.h
+ $$PWD/qv4instr_moth_p.h \
+ $$PWD/qqmlpropertycachecreator_p.h \
+ $$PWD/qqmlpropertyvalidator_p.h \
+ $$PWD/qv4compilationunitmapper_p.h
SOURCES += \
$$PWD/qqmltypecompiler.cpp \
$$PWD/qv4instr_moth.cpp \
- $$PWD/qv4isel_moth.cpp
+ $$PWD/qv4isel_moth.cpp \
+ $$PWD/qqmlpropertycachecreator.cpp \
+ $$PWD/qqmlpropertyvalidator.cpp \
+ $$PWD/qv4compilationunitmapper.cpp
+
+unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
+else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index c9a4e21ddd..89fa86c857 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -44,12 +44,12 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljslexer_p.h>
#include <QCoreApplication>
+#include <QCryptographicHash>
#ifndef V4_BOOTSTRAP
#include <private/qqmlglobal_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qqmlcompiler_p.h>
#endif
#ifdef CONST
@@ -194,7 +194,7 @@ void Object::appendFunction(QmlIR::Function *f)
QString Object::appendBinding(Binding *b, bool isListBinding)
{
- const bool bindingToDefaultProperty = (b->propertyNameIndex == 0);
+ const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
if (!isListBinding && !bindingToDefaultProperty
&& b->type != QV4::CompiledData::Binding::Type_GroupProperty
&& b->type != QV4::CompiledData::Binding::Type_AttachedProperty
@@ -252,31 +252,6 @@ static void replaceWithSpace(QString &str, int idx, int n)
*data++ = space;
}
-void Document::collectTypeReferences()
-{
- foreach (Object *obj, objects) {
- if (obj->inheritedTypeNameIndex != emptyStringIndex) {
- QV4::CompiledData::TypeReference &r = typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
- r.needsCreation = true;
- r.errorWhenNotFound = true;
- }
-
- for (const Property *prop = obj->firstProperty(); prop; prop = prop->next) {
- if (prop->type >= QV4::CompiledData::Property::Custom) {
- // ### FIXME: We could report the more accurate location here by using prop->location, but the old
- // compiler can't and the tests expect it to be the object location right now.
- QV4::CompiledData::TypeReference &r = typeReferences.add(prop->customTypeNameIndex, obj->location);
- r.errorWhenNotFound = true;
- }
- }
-
- for (const Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
- typeReferences.add(binding->propertyNameIndex, binding->location);
- }
- }
-}
-
void Document::removeScriptPragmas(QString &script)
{
const QLatin1String pragma("pragma");
@@ -327,7 +302,6 @@ Document::Document(bool debugMode)
, program(0)
, indexOfRootObject(0)
, jsGenerator(&jsModule)
- , unitFlags(0)
{
}
@@ -388,10 +362,11 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
QQmlJS::Parser parser(&output->jsParserEngine);
- if (! parser.parse() || !parser.diagnosticMessages().isEmpty()) {
-
+ const bool parseResult = parser.parse();
+ const auto diagnosticMessages = parser.diagnosticMessages();
+ if (!parseResult || !diagnosticMessages.isEmpty()) {
// Extract errors from the parser
- foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message));
@@ -666,7 +641,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
}
if (node->versionToken.isValid()) {
- extractVersion(textRefAt(node->versionToken), &import->majorVersion, &import->minorVersion);
+ int major, minor;
+ extractVersion(textRefAt(node->versionToken), &major, &minor);
+ import->majorVersion = major;
+ import->minorVersion = minor;
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version"));
return false;
@@ -842,7 +820,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
const QStringRef &name = node->name;
bool typeFound = false;
- QV4::CompiledData::Property::Type type;
+ QV4::CompiledData::Property::Type type = QV4::CompiledData::Property::Var;
for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
const TypeNameToType *t = propTypeNameToTypes + ii;
@@ -912,7 +890,8 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
// process QML-like initializers (e.g. property Object o: Object {})
QQmlJS::AST::Node::accept(node->binding, this);
} else if (node->statement) {
- appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
+ if (!isRedundantNullInitializerForPropertyDeclaration(_propertyDeclaration, node->statement))
+ appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
}
qSwap(_propertyDeclaration, property);
}
@@ -937,6 +916,16 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
f->location.column = loc.startColumn;
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
+
+ int formalsCount = 0;
+ for (QQmlJS::AST::FormalParameterList *it = funDecl->formals; it; it = it->next)
+ ++formalsCount;
+ f->formals.allocate(pool, formalsCount);
+
+ int i = 0;
+ for (QQmlJS::AST::FormalParameterList *it = funDecl->formals; it; it = it->next, ++i)
+ f->formals[i] = registerString(it->name.toString());
+
_object->appendFunction(f);
} else {
recordError(node->firstSourceLocation(), QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element"));
@@ -1012,13 +1001,13 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
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->value.d = lit->value;
+ binding->setNumberValueInternal(lit->value);
} 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->value.d = -lit->value;
+ binding->setNumberValueInternal(-lit->value);
}
}
}
@@ -1030,7 +1019,8 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
expr->node = statement;
- expr->nameIndex = registerString(QStringLiteral("expression for ") + stringAt(binding->propertyNameIndex));
+ expr->nameIndex = registerString(QLatin1String("expression for ")
+ + stringAt(binding->propertyNameIndex));
expr->disableAcceleratedLookups = false;
const int index = bindingsTarget()->functionsAndExpressions->append(expr);
binding->value.compiledScriptIndex = index;
@@ -1258,7 +1248,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
// If it's a namespace, prepend the qualifier and we'll resolve it later to the correct type.
QString currentName = qualifiedIdElement->name.toString();
if (qualifiedIdElement->next) {
- foreach (const QV4::CompiledData::Import* import, _imports)
+ for (const QV4::CompiledData::Import* import : qAsConst(_imports))
if (import->qualifierIndex != emptyStringIndex
&& stringAt(import->qualifierIndex) == currentName) {
qualifiedIdElement = qualifiedIdElement->next;
@@ -1360,7 +1350,18 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
return true;
}
-QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
+bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
+{
+ if (property->type != QV4::CompiledData::Property::Custom)
+ return false;
+ QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
+ if (!exprStmt)
+ return false;
+ QQmlJS::AST::ExpressionNode * const expr = exprStmt->expression;
+ return QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr);
+}
+
+QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, QQmlEngine *engine, const QV4::CompiledData::ResolvedTypeReferenceMap &dependentTypes)
{
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = output.javaScriptCompilationUnit;
QV4::CompiledData::Unit *jsUnit = compilationUnit->createUnitData(&output);
@@ -1372,7 +1373,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
QHash<const Object*, quint32> objectOffsets;
int objectsSize = 0;
- foreach (Object *o, output.objects) {
+ for (Object *o : qAsConst(output.objects)) {
objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize);
objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
@@ -1393,7 +1394,6 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(data);
qmlUnit->unitSize = totalSize;
- qmlUnit->flags |= output.unitFlags;
qmlUnit->flags |= QV4::CompiledData::Unit::IsQml;
qmlUnit->offsetToImports = unitSize;
qmlUnit->nImports = output.imports.count();
@@ -1403,9 +1403,23 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
qmlUnit->offsetToStringTable = totalSize - output.jsGenerator.stringTable.sizeOfTableAndData();
qmlUnit->stringTableSize = output.jsGenerator.stringTable.stringCount();
+#ifndef V4_BOOTSTRAP
+ if (!dependentTypes.isEmpty()) {
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ if (dependentTypes.addToHash(&hash, engine)) {
+ QByteArray checksum = hash.result();
+ Q_ASSERT(checksum.size() == sizeof(qmlUnit->dependencyMD5Checksum));
+ memcpy(qmlUnit->dependencyMD5Checksum, checksum.constData(), sizeof(qmlUnit->dependencyMD5Checksum));
+ }
+ }
+#else
+ Q_UNUSED(dependentTypes);
+ Q_UNUSED(engine);
+#endif
+
// write imports
char *importPtr = data + qmlUnit->offsetToImports;
- foreach (const QV4::CompiledData::Import *imp, output.imports) {
+ for (const QV4::CompiledData::Import *imp : qAsConst(output.imports)) {
QV4::CompiledData::Import *importToWrite = reinterpret_cast<QV4::CompiledData::Import*>(importPtr);
*importToWrite = *imp;
importPtr += sizeof(QV4::CompiledData::Import);
@@ -1510,7 +1524,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
}
// enable flag if we encountered pragma Singleton
- foreach (Pragma *p, output.pragmas) {
+ for (Pragma *p : qAsConst(output.pragmas)) {
if (p->type == Pragma::PragmaSingleton) {
qmlUnit->flags |= QV4::CompiledData::Unit::IsSingleton;
break;
@@ -1574,7 +1588,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
ScanFunctions scan(this, sourceCode, GlobalCode);
scan.enterEnvironment(0, QmlBinding);
scan.enterQmlScope(qmlRoot, QStringLiteral("context scope"));
- foreach (const CompiledFunctionOrExpression &f, functions) {
+ for (const CompiledFunctionOrExpression &f : functions) {
Q_ASSERT(f.node != qmlRoot);
QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node);
@@ -1698,7 +1712,7 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
if (tdata->isComplete()) {
auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
newResolver->owner = resolver->owner;
- initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId));
+ initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compilationUnit()->metaTypeId));
newResolver->flags |= AllPropertiesAreFinal;
return newResolver->resolveMember(qmlEngine, newResolver, member);
}
@@ -1711,7 +1725,11 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
member->kind = QV4::IR::Member::MemberOfSingletonObject;
return newResolver->resolveMember(qmlEngine, newResolver, member);
}
- } else if (const QMetaObject *attachedMeta = type->attachedPropertiesType(qmlEngine)) {
+ }
+#if 0
+ else if (const QMetaObject *attachedMeta = type->attachedPropertiesType(qmlEngine)) {
+ // Right now the attached property IDs are not stable and cannot be embedded in the
+ // code that is cached on disk.
QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta);
auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
newResolver->owner = resolver->owner;
@@ -1719,6 +1737,7 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
member->setAttachedPropertiesId(type->attachedPropertiesId(qmlEngine));
return newResolver->resolveMember(qmlEngine, newResolver, member);
}
+#endif
return result;
}
@@ -1826,20 +1845,20 @@ static QV4::IR::DiscoveredType resolveMetaObjectProperty(
if (property->isEnum())
return QV4::IR::VarType;
- switch (property->propType) {
+ switch (property->propType()) {
case QMetaType::Bool: result = QV4::IR::BoolType; break;
case QMetaType::Int: result = QV4::IR::SInt32Type; break;
case QMetaType::Double: result = QV4::IR::DoubleType; break;
case QMetaType::QString: result = QV4::IR::StringType; break;
default:
if (property->isQObject()) {
- if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType)) {
+ if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType())) {
auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
newResolver->owner = resolver->owner;
initMetaObjectResolver(newResolver, cache);
return QV4::IR::DiscoveredType(newResolver);
}
- } else if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType)) {
+ } else if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType())) {
if (QQmlPropertyCache *cache = qmlEngine->cache(valueTypeMetaObject)) {
auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
newResolver->owner = resolver->owner;
@@ -1904,9 +1923,11 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
// with the correct QML context.
// Look for IDs first.
- foreach (const IdMapping &mapping, _idObjects)
+ for (const IdMapping &mapping : qAsConst(_idObjects))
if (name == mapping.name) {
- _function->idObjectDependencies.insert(mapping.idIndex);
+ if (_function->isQmlBinding)
+ _function->idObjectDependencies.insert(mapping.idIndex);
+
QV4::IR::Expr *s = _block->MEMBER(_block->TEMP(_qmlContextTemp), _function->newString(name), 0, QV4::IR::Member::MemberOfIdObjectsArray, mapping.idIndex);
QV4::IR::Temp *result = _block->TEMP(_block->newTemp());
_block->MOVE(result, s);
@@ -1991,7 +2012,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
#ifndef V4_BOOTSTRAP
-QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check)
+QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check) const
{
if (notInRevision) *notInRevision = false;
@@ -2010,7 +2031,7 @@ QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRev
}
-QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision)
+QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision) const
{
if (notInRevision) *notInRevision = false;
@@ -2032,7 +2053,7 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis
d = property(propName, notInRevision);
if (d)
- return cache->signal(d->notifyIndex);
+ return cache->signal(d->notifyIndex());
}
return 0;
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index db17c93222..95756845c3 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -161,6 +161,43 @@ struct PoolList
}
return result;
}
+
+ struct Iterator {
+ T *ptr;
+
+ explicit Iterator(T *p) : ptr(p) {}
+
+ T *operator->() {
+ return ptr;
+ }
+
+ const T *operator->() const {
+ return ptr;
+ }
+
+ T &operator*() {
+ return *ptr;
+ }
+
+ const T &operator*() const {
+ return *ptr;
+ }
+
+ void operator++() {
+ ptr = ptr->next;
+ }
+
+ bool operator==(const Iterator &rhs) const {
+ return ptr == rhs.ptr;
+ }
+
+ bool operator!=(const Iterator &rhs) const {
+ return ptr != rhs.ptr;
+ }
+ };
+
+ Iterator begin() { return Iterator(first); }
+ Iterator end() { return Iterator(nullptr); }
};
template <typename T>
@@ -175,6 +212,12 @@ public:
, count(0)
{}
+ void allocate(QQmlJS::MemoryPool *pool, int size)
+ {
+ count = size;
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+ }
+
void allocate(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
{
count = vector.count();
@@ -215,6 +258,9 @@ public:
return i;
return -1;
}
+
+ const T *begin() const { return data; }
+ const T *end() const { return data + count; }
};
struct Object;
@@ -232,6 +278,10 @@ struct Signal
QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const;
+ int parameterCount() const { return parameters->count; }
+ PoolList<SignalParameter>::Iterator parametersBegin() const { return parameters->begin(); }
+ PoolList<SignalParameter>::Iterator parametersEnd() const { return parameters->end(); }
+
Signal *next;
};
@@ -261,6 +311,13 @@ struct Function
QV4::CompiledData::Location location;
int nameIndex;
quint32 index; // index in parsedQML::functions
+ FixedPoolArray<int> formals;
+
+ // --- QQmlPropertyCacheCreator interface
+ const int *formalsBegin() const { return formals.begin(); }
+ const int *formalsEnd() const { return formals.end(); }
+ // ---
+
Function *next;
};
@@ -293,7 +350,7 @@ public:
int id;
int indexOfDefaultPropertyOrAlias;
bool defaultPropertyIsAlias;
- int flags;
+ quint32 flags;
QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty;
@@ -309,6 +366,17 @@ public:
const Function *firstFunction() const { return functions->first; }
int functionCount() const { return functions->count; }
+ PoolList<Binding>::Iterator bindingsBegin() const { return bindings->begin(); }
+ PoolList<Binding>::Iterator bindingsEnd() const { return bindings->end(); }
+ PoolList<Property>::Iterator propertiesBegin() const { return properties->begin(); }
+ PoolList<Property>::Iterator propertiesEnd() const { return properties->end(); }
+ PoolList<Alias>::Iterator aliasesBegin() const { return aliases->begin(); }
+ PoolList<Alias>::Iterator aliasesEnd() const { return aliases->end(); }
+ PoolList<Signal>::Iterator signalsBegin() const { return qmlSignals->begin(); }
+ PoolList<Signal>::Iterator signalsEnd() const { return qmlSignals->end(); }
+ PoolList<Function>::Iterator functionsBegin() const { return functions->begin(); }
+ PoolList<Function>::Iterator functionsEnd() const { return functions->end(); }
+
// If set, then declarations for this object (and init bindings for these) should go into the
// specified object. Used for declarations inside group properties.
Object *declarationsOverride;
@@ -332,6 +400,8 @@ public:
FixedPoolArray<int> runtimeFunctionIndices;
FixedPoolArray<quint32> namedObjectsInComponent;
+ int namedObjectsInComponentCount() const { return namedObjectsInComponent.count; }
+ const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
private:
friend struct IRLoader;
@@ -363,15 +433,10 @@ struct Q_QML_PRIVATE_EXPORT Document
QList<Pragma*> pragmas;
QQmlJS::AST::UiProgram *program;
int indexOfRootObject;
- QList<Object*> objects;
+ QVector<Object*> objects;
QV4::Compiler::JSUnitGenerator jsGenerator;
- quint32 unitFlags;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> javaScriptCompilationUnit;
- QHash<int, QStringList> extraSignalParameters;
-
- QV4::CompiledData::TypeReferenceMap typeReferences;
- void collectTypeReferences();
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
@@ -388,9 +453,9 @@ struct Q_QML_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directive
QList<const QV4::CompiledData::Import *> imports;
bool hasPragmaLibrary;
- virtual void pragmaLibrary();
- virtual void importFile(const QString &jsfile, const QString &module, int lineNumber, int column);
- virtual void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column);
+ void pragmaLibrary() override;
+ void importFile(const QString &jsfile, const QString &module, int lineNumber, int column) override;
+ void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column) override;
};
struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
@@ -405,21 +470,21 @@ public:
using QQmlJS::AST::Visitor::visit;
using QQmlJS::AST::Visitor::endVisit;
- virtual bool visit(QQmlJS::AST::UiArrayMemberList *ast);
- virtual bool visit(QQmlJS::AST::UiImport *ast);
- virtual bool visit(QQmlJS::AST::UiPragma *ast);
- virtual bool visit(QQmlJS::AST::UiHeaderItemList *ast);
- virtual bool visit(QQmlJS::AST::UiObjectInitializer *ast);
- virtual bool visit(QQmlJS::AST::UiObjectMemberList *ast);
- virtual bool visit(QQmlJS::AST::UiParameterList *ast);
- virtual bool visit(QQmlJS::AST::UiProgram *);
- virtual bool visit(QQmlJS::AST::UiQualifiedId *ast);
- virtual bool visit(QQmlJS::AST::UiArrayBinding *ast);
- virtual bool visit(QQmlJS::AST::UiObjectBinding *ast);
- virtual bool visit(QQmlJS::AST::UiObjectDefinition *ast);
- virtual bool visit(QQmlJS::AST::UiPublicMember *ast);
- virtual bool visit(QQmlJS::AST::UiScriptBinding *ast);
- virtual bool visit(QQmlJS::AST::UiSourceElement *ast);
+ bool visit(QQmlJS::AST::UiArrayMemberList *ast) override;
+ bool visit(QQmlJS::AST::UiImport *ast) override;
+ bool visit(QQmlJS::AST::UiPragma *ast) override;
+ bool visit(QQmlJS::AST::UiHeaderItemList *ast) override;
+ bool visit(QQmlJS::AST::UiObjectInitializer *ast) override;
+ bool visit(QQmlJS::AST::UiObjectMemberList *ast) override;
+ bool visit(QQmlJS::AST::UiParameterList *ast) override;
+ bool visit(QQmlJS::AST::UiProgram *) override;
+ bool visit(QQmlJS::AST::UiQualifiedId *ast) override;
+ bool visit(QQmlJS::AST::UiArrayBinding *ast) override;
+ bool visit(QQmlJS::AST::UiObjectBinding *ast) override;
+ bool visit(QQmlJS::AST::UiObjectDefinition *ast) override;
+ bool visit(QQmlJS::AST::UiPublicMember *ast) override;
+ bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
+ bool visit(QQmlJS::AST::UiSourceElement *ast) override;
void accept(QQmlJS::AST::Node *node);
@@ -461,6 +526,7 @@ public:
QString stringAt(int index) const { return jsGenerator->stringForIndex(index); }
static bool isStatementNodeScript(QQmlJS::AST::Statement *statement);
+ static bool isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement);
QList<QQmlJS::DiagnosticMessage> errors;
@@ -468,7 +534,7 @@ public:
QList<const QV4::CompiledData::Import *> _imports;
QList<Pragma*> _pragmas;
- QList<Object*> _objects;
+ QVector<Object*> _objects;
QV4::CompiledData::TypeReferenceMap _typeReferences;
@@ -482,7 +548,7 @@ public:
struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
{
- QV4::CompiledData::Unit *generate(Document &output);
+ QV4::CompiledData::Unit *generate(Document &output, QQmlEngine *engine, const QV4::CompiledData::ResolvedTypeReferenceMap &dependentTypes);
private:
typedef bool (Binding::*BindingFilter)() const;
@@ -492,11 +558,11 @@ private:
#ifndef V4_BOOTSTRAP
struct Q_QML_EXPORT PropertyResolver
{
- PropertyResolver(QQmlPropertyCache *cache)
+ PropertyResolver(const QQmlPropertyCache *cache)
: cache(cache)
{}
- QQmlPropertyData *property(int index)
+ QQmlPropertyData *property(int index) const
{
return cache->property(index);
}
@@ -506,12 +572,12 @@ struct Q_QML_EXPORT PropertyResolver
IgnoreRevision
};
- QQmlPropertyData *property(const QString &name, bool *notInRevision = 0, RevisionCheck check = CheckRevision);
+ QQmlPropertyData *property(const QString &name, bool *notInRevision = 0, RevisionCheck check = CheckRevision) const;
// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
- QQmlPropertyData *signal(const QString &name, bool *notInRevision);
+ QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
- QQmlPropertyCache *cache;
+ const QQmlPropertyCache *cache;
};
#endif
@@ -536,8 +602,8 @@ struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QQmlJS::Codegen
QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
protected:
- virtual void beginFunctionBodyHook();
- virtual QV4::IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
+ void beginFunctionBodyHook() override;
+ QV4::IR::Expr *fallbackNameLookup(const QString &name, int line, int col) override;
private:
QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup = 0);
diff --git a/src/qml/compiler/qqmlpropertycachecreator.cpp b/src/qml/compiler/qqmlpropertycachecreator.cpp
new file mode 100644
index 0000000000..f8d63ec634
--- /dev/null
+++ b/src/qml/compiler/qqmlpropertycachecreator.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 "qqmlpropertycachecreator_p.h"
+
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
+
+QQmlBindingInstantiationContext::QQmlBindingInstantiationContext()
+ : referencingObjectIndex(-1)
+ , instantiatingBinding(nullptr)
+ , instantiatingProperty(nullptr)
+{
+
+}
+
+QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, const QQmlPropertyCache *referencingObjectPropertyCache)
+ : referencingObjectIndex(referencingObjectIndex)
+ , instantiatingBinding(instantiatingBinding)
+ , instantiatingProperty(nullptr)
+{
+ if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ Q_ASSERT(referencingObjectIndex >= 0);
+ Q_ASSERT(referencingObjectPropertyCache);
+ Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
+
+ bool notInRevision = false;
+ instantiatingProperty = QmlIR::PropertyResolver(referencingObjectPropertyCache).property(instantiatingPropertyName, &notInRevision);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
new file mode 100644
index 0000000000..10bcd1dbc1
--- /dev/null
+++ b/src/qml/compiler/qqmlpropertycachecreator_p.h
@@ -0,0 +1,741 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQMLPROPERTYCACHECREATOR_P_H
+#define QQMLPROPERTYCACHECREATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmltypecompiler_p.h"
+#include <private/qqmlvaluetype_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQmlBindingInstantiationContext {
+ QQmlBindingInstantiationContext();
+ QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, const QQmlPropertyCache *referencingObjectPropertyCache);
+ int referencingObjectIndex;
+ const QV4::CompiledData::Binding *instantiatingBinding;
+ QQmlPropertyData *instantiatingProperty;
+};
+
+struct QQmlPropertyCacheCreatorBase
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase)
+public:
+ static QAtomicInt classIndexCounter;
+};
+
+template <typename ObjectContainer>
+class QQmlPropertyCacheCreator : public QQmlPropertyCacheCreatorBase
+{
+public:
+ typedef typename ObjectContainer::CompiledObject CompiledObject;
+
+ QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports);
+
+ QQmlCompileError buildMetaObjects();
+
+protected:
+ QQmlCompileError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
+ QQmlPropertyCache *propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const;
+ QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, QQmlPropertyCache *baseTypeCache);
+
+ QString stringAt(int index) const { return objectContainer->stringAt(index); }
+
+ QQmlEnginePrivate * const enginePrivate;
+ const ObjectContainer * const objectContainer;
+ const QQmlImports * const imports;
+ QQmlPropertyCacheVector *propertyCaches;
+};
+
+template <typename ObjectContainer>
+inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports)
+ : enginePrivate(enginePrivate)
+ , objectContainer(objectContainer)
+ , imports(imports)
+ , propertyCaches(propertyCaches)
+{
+ propertyCaches->resize(objectContainer->objectCount());
+}
+
+template <typename ObjectContainer>
+inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
+{
+ QQmlBindingInstantiationContext context;
+ return buildMetaObjectRecursively(objectContainer->rootObjectIndex(), context);
+}
+
+template <typename ObjectContainer>
+inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
+{
+ const CompiledObject *obj = objectContainer->objectAt(objectIndex);
+
+ bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
+ if (!needVMEMetaObject) {
+ for (auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding) {
+ 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
+ // because interceptors can't go to the shared value type instances.
+ if (context.instantiatingProperty && QQmlValueTypeFactory::isValueType(context.instantiatingProperty->propType())) {
+ if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
+ const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
+ auto *typeRef = objectContainer->resolvedTypes.value(obj->inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+ QQmlPropertyCache *baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ QQmlCompileError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
+ if (error.isSet())
+ return error;
+ }
+ } else {
+ // On assignments are implemented using value interceptors, which require a VME meta object.
+ needVMEMetaObject = true;
+ }
+ break;
+ }
+ }
+ }
+
+ QQmlPropertyCache *baseTypeCache;
+ {
+ QQmlCompileError error;
+ baseTypeCache = propertyCacheForObject(obj, context, &error);
+ if (error.isSet())
+ return error;
+ }
+
+ if (baseTypeCache) {
+ if (needVMEMetaObject) {
+ QQmlCompileError error = createMetaObject(objectIndex, obj, baseTypeCache);
+ if (error.isSet())
+ return error;
+ } else {
+ propertyCaches->set(objectIndex, baseTypeCache);
+ }
+ }
+
+ if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) {
+ for (auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding)
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
+ QQmlCompileError error = buildMetaObjectRecursively(binding->value.objectIndex, context);
+ if (error.isSet())
+ return error;
+ }
+ }
+
+ QQmlCompileError noError;
+ return noError;
+}
+
+template <typename ObjectContainer>
+inline QQmlPropertyCache *QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const
+{
+ if (context.instantiatingProperty) {
+ if (context.instantiatingProperty->isQObject()) {
+ return enginePrivate->rawPropertyCacheForType(context.instantiatingProperty->propType());
+ } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(context.instantiatingProperty->propType())) {
+ return enginePrivate->cache(vtmo);
+ }
+ } else if (obj->inheritedTypeNameIndex != 0) {
+ auto *typeRef = objectContainer->resolvedTypes.value(obj->inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+
+ if (typeRef->isFullyDynamicType) {
+ if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
+ *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
+ return nullptr;
+ }
+ if (obj->signalCount() > 0) {
+ *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals."));
+ return nullptr;
+ }
+ if (obj->functionCount() > 0) {
+ *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions."));
+ return nullptr;
+ }
+ }
+
+ return typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ } else if (context.instantiatingBinding && context.instantiatingBinding->isAttachedProperty()) {
+ auto *typeRef = objectContainer->resolvedTypes.value(context.instantiatingBinding->propertyNameIndex);
+ Q_ASSERT(typeRef);
+ QQmlType *qmltype = typeRef->type;
+ if (!qmltype) {
+ QString propertyName = stringAt(context.instantiatingBinding->propertyNameIndex);
+ if (imports->resolveType(propertyName, &qmltype, 0, 0, 0)) {
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ auto compilationUnit = tdata->compilationUnit();
+ qmltype = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
+
+ tdata->release();
+ }
+ }
+ }
+
+ const QMetaObject *attachedMo = qmltype ? qmltype->attachedPropertiesType(enginePrivate) : 0;
+ if (!attachedMo) {
+ *error = QQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
+ return nullptr;
+ }
+ return enginePrivate->cache(attachedMo);
+ }
+ return nullptr;
+}
+
+template <typename ObjectContainer>
+inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, QQmlPropertyCache *baseTypeCache)
+{
+ QQmlRefPointer<QQmlPropertyCache> cache;
+ cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
+ obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
+ obj->signalCount() + obj->propertyCount() + obj->aliasCount()));
+
+ propertyCaches->set(objectIndex, cache);
+ propertyCaches->setNeedsVMEMetaObject(objectIndex);
+
+ struct TypeData {
+ QV4::CompiledData::Property::Type dtype;
+ int metaType;
+ } builtinTypes[] = {
+ { QV4::CompiledData::Property::Var, QMetaType::QVariant },
+ { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
+ { QV4::CompiledData::Property::Int, QMetaType::Int },
+ { QV4::CompiledData::Property::Bool, QMetaType::Bool },
+ { QV4::CompiledData::Property::Real, QMetaType::Double },
+ { QV4::CompiledData::Property::String, QMetaType::QString },
+ { QV4::CompiledData::Property::Url, QMetaType::QUrl },
+ { QV4::CompiledData::Property::Color, QMetaType::QColor },
+ { QV4::CompiledData::Property::Font, QMetaType::QFont },
+ { QV4::CompiledData::Property::Time, QMetaType::QTime },
+ { QV4::CompiledData::Property::Date, QMetaType::QDate },
+ { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
+ { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
+ { QV4::CompiledData::Property::Point, QMetaType::QPointF },
+ { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
+ { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
+ { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
+ { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
+ { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
+ { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
+};
+ static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
+
+ QByteArray newClassName;
+
+ if (objectIndex == objectContainer->rootObjectIndex()) {
+ const QString path = objectContainer->url().path();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash > -1) {
+ const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
+ if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
+ newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
+ QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
+ }
+ }
+ if (newClassName.isEmpty()) {
+ newClassName = QQmlMetaObject(baseTypeCache).className();
+ newClassName.append("_QML_");
+ newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
+ }
+
+ cache->_dynamicClassName = newClassName;
+
+ int varPropCount = 0;
+
+ QmlIR::PropertyResolver resolver(baseTypeCache);
+
+ for (auto p = obj->propertiesBegin(), end = obj->propertiesEnd(); p != end; ++p) {
+ if (p->type == QV4::CompiledData::Property::Var)
+ varPropCount++;
+
+ bool notInRevision = false;
+ QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
+ if (d && d->isFinal())
+ return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
+ }
+
+ for (auto a = obj->aliasesBegin(), end = obj->aliasesEnd(); a != end; ++a) {
+ bool notInRevision = false;
+ QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
+ if (d && d->isFinal())
+ return QQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
+ }
+
+ int effectivePropertyIndex = cache->propertyIndexCacheStart;
+ int effectiveMethodIndex = cache->methodIndexCacheStart;
+
+ // For property change signal override detection.
+ // We prepopulate a set of signal names which already exist in the object,
+ // and throw an error if there is a signal/method defined as an override.
+ QSet<QString> seenSignals;
+ seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
+ QQmlPropertyCache *parentCache = cache;
+ while ((parentCache = parentCache->parent())) {
+ if (int pSigCount = parentCache->signalCount()) {
+ int pSigOffset = parentCache->signalOffset();
+ for (int i = pSigOffset; i < pSigCount; ++i) {
+ QQmlPropertyData *currPSig = parentCache->signal(i);
+ // XXX TODO: find a better way to get signal name from the property data :-/
+ for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
+ iter != parentCache->stringCache.end(); ++iter) {
+ if (currPSig == (*iter).second) {
+ seenSignals.insert(iter.key());
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Set up notify signals for properties - first normal, then alias
+ for (auto p = obj->propertiesBegin(), end = obj->propertiesEnd(); p != end; ++p) {
+ auto flags = QQmlPropertyData::defaultSignalFlags();
+
+ QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
+ seenSignals.insert(changedSigName);
+
+ cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
+ }
+
+ for (auto a = obj->aliasesBegin(), end = obj->aliasesEnd(); a != end; ++a) {
+ auto flags = QQmlPropertyData::defaultSignalFlags();
+
+ QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
+ seenSignals.insert(changedSigName);
+
+ cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
+ }
+
+ // Dynamic signals
+ for (auto s = obj->signalsBegin(), end = obj->signalsEnd(); s != end; ++s) {
+ const int paramCount = s->parameterCount();
+
+ QList<QByteArray> names;
+ names.reserve(paramCount);
+ QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
+
+ if (paramCount) {
+ paramTypes[0] = paramCount;
+
+ int i = 0;
+ for (auto param = s->parametersBegin(), end = s->parametersEnd(); param != end; ++param, ++i) {
+ names.append(stringAt(param->nameIndex).toUtf8());
+ if (param->type < builtinTypeCount) {
+ // built-in type
+ paramTypes[i + 1] = builtinTypes[param->type].metaType;
+ } else {
+ // lazily resolved type
+ Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
+ const QString customTypeName = stringAt(param->customTypeNameIndex);
+ QQmlType *qmltype = 0;
+ if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0))
+ return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
+
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ auto compilationUnit = tdata->compilationUnit();
+
+ paramTypes[i + 1] = compilationUnit->metaTypeId;
+
+ tdata->release();
+ } else {
+ paramTypes[i + 1] = qmltype->typeId();
+ }
+ }
+ }
+ }
+
+ auto flags = QQmlPropertyData::defaultSignalFlags();
+ if (paramCount)
+ flags.hasArguments = true;
+
+ QString signalName = stringAt(s->nameIndex);
+ if (seenSignals.contains(signalName))
+ return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
+ seenSignals.insert(signalName);
+
+ cache->appendSignal(signalName, flags, effectiveMethodIndex++,
+ paramCount?paramTypes.constData():0, names);
+ }
+
+
+ // Dynamic slots
+ for (auto function = objectContainer->objectFunctionsBegin(obj), end = objectContainer->objectFunctionsEnd(obj); function != end; ++function) {
+ auto flags = QQmlPropertyData::defaultSlotFlags();
+
+ const QString slotName = stringAt(function->nameIndex);
+ if (seenSignals.contains(slotName))
+ return QQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
+ // Note: we don't append slotName to the seenSignals list, since we don't
+ // protect against overriding change signals or methods with properties.
+
+ QList<QByteArray> parameterNames;
+ for (auto formal = function->formalsBegin(), end = function->formalsEnd(); formal != end; ++formal) {
+ flags.hasArguments = true;
+ parameterNames << stringAt(*formal).toUtf8();
+ }
+
+ cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
+ }
+
+
+ // Dynamic properties
+ int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
+ int propertyIdx = 0;
+ for (auto p = obj->propertiesBegin(), end = obj->propertiesEnd(); p != end; ++p, ++propertyIdx) {
+ int propertyType = 0;
+ QQmlPropertyData::Flags propertyFlags;
+
+ if (p->type == QV4::CompiledData::Property::Var) {
+ propertyType = QMetaType::QVariant;
+ propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
+ } else if (p->type < builtinTypeCount) {
+ propertyType = builtinTypes[p->type].metaType;
+
+ if (p->type == QV4::CompiledData::Property::Variant)
+ propertyFlags.type = QQmlPropertyData::Flags::QVariantType;
+ } else {
+ Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
+ p->type == QV4::CompiledData::Property::Custom);
+
+ QQmlType *qmltype = 0;
+ if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) {
+ return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
+ }
+
+ Q_ASSERT(qmltype);
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ auto compilationUnit = tdata->compilationUnit();
+
+ if (p->type == QV4::CompiledData::Property::Custom) {
+ propertyType = compilationUnit->metaTypeId;
+ } else {
+ propertyType = compilationUnit->listMetaTypeId;
+ }
+
+ tdata->release();
+ } else {
+ if (p->type == QV4::CompiledData::Property::Custom) {
+ propertyType = qmltype->typeId();
+ } else {
+ propertyType = qmltype->qListTypeId();
+ }
+ }
+
+ if (p->type == QV4::CompiledData::Property::Custom)
+ propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
+ else
+ propertyFlags.type = QQmlPropertyData::Flags::QListType;
+ }
+
+ if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
+ propertyFlags.isWritable = true;
+
+
+ QString propertyName = stringAt(p->nameIndex);
+ if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
+ cache->_defaultPropertyName = propertyName;
+ cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
+ propertyType, effectiveSignalIndex);
+
+ effectiveSignalIndex++;
+ }
+
+ QQmlCompileError noError;
+ return noError;
+}
+
+template <typename ObjectContainer>
+class QQmlPropertyCacheAliasCreator
+{
+public:
+ typedef typename ObjectContainer::CompiledObject CompiledObject;
+
+ QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
+
+ void appendAliasPropertiesToMetaObjects();
+
+ void appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
+
+private:
+ void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex);
+ void propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, QQmlPropertyRawData::Flags *propertyFlags);
+
+ void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
+
+ int objectForId(const CompiledObject &component, int id) const;
+
+ QQmlPropertyCacheVector *propertyCaches;
+ const ObjectContainer *objectContainer;
+};
+
+template <typename ObjectContainer>
+inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
+ : propertyCaches(propertyCaches)
+ , objectContainer(objectContainer)
+{
+
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects()
+{
+ for (int i = 0; i < objectContainer->objectCount(); ++i) {
+ const CompiledObject &component = *objectContainer->objectAt(i);
+ if (!(component.flags & QV4::CompiledData::Object::IsComponent))
+ continue;
+
+ const auto rootBinding = component.bindingsBegin();
+ appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex);
+ }
+
+ const int rootObjectIndex = objectContainer->rootObjectIndex();
+ appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex);
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex)
+{
+ QVector<int> objectsWithAliases;
+ collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
+ if (objectsWithAliases.isEmpty())
+ return;
+
+ const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) {
+ for (auto alias = object.aliasesBegin(), end = object.aliasesEnd(); alias != end; ++alias) {
+ Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+
+ const int targetObjectIndex = objectForId(component, alias->targetObjectId);
+ Q_ASSERT(targetObjectIndex >= 0);
+
+ if (alias->aliasToLocalAlias)
+ continue;
+
+ if (alias->encodedMetaPropertyIndex == -1)
+ continue;
+
+ const QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
+ Q_ASSERT(targetCache);
+
+ int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
+ QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
+ if (!targetProperty)
+ return false;
+ }
+ return true;
+ };
+
+ do {
+ QVector<int> pendingObjects;
+
+ for (int objectIndex: qAsConst(objectsWithAliases)) {
+ const CompiledObject &object = *objectContainer->objectAt(objectIndex);
+
+ if (allAliasTargetsExist(object)) {
+ appendAliasesToPropertyCache(component, objectIndex);
+ } else {
+ pendingObjects.append(objectIndex);
+ }
+
+ }
+ qSwap(objectsWithAliases, pendingObjects);
+ } while (!objectsWithAliases.isEmpty());
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const
+{
+ const CompiledObject &object = *objectContainer->objectAt(objectIndex);
+ if (object.aliasCount() > 0)
+ objectsWithAliases->append(objectIndex);
+
+ // Stop at Component boundary
+ if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != objectContainer->rootObjectIndex())
+ return;
+
+ for (auto binding = object.bindingsBegin(), end = object.bindingsEnd(); 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);
+ }
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
+ const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type,
+ QQmlPropertyData::Flags *propertyFlags)
+{
+ const int targetObjectIndex = objectForId(component, alias.targetObjectId);
+ Q_ASSERT(targetObjectIndex >= 0);
+
+ const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
+
+ *type = 0;
+ bool writable = false;
+ bool resettable = false;
+
+ propertyFlags->isAlias = true;
+
+ if (alias.aliasToLocalAlias) {
+ auto targetAlias = targetObject.aliasesBegin();
+ for (uint i = 0; i < alias.localAliasIndex; ++i)
+ ++targetAlias;
+ propertyDataForAlias(component, *targetAlias, type, propertyFlags);
+ return;
+ } else if (alias.encodedMetaPropertyIndex == -1) {
+ Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
+ auto *typeRef = objectContainer->resolvedTypes.value(targetObject.inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+
+ if (typeRef->type)
+ *type = typeRef->type->typeId();
+ else
+ *type = typeRef->compilationUnit->metaTypeId;
+
+ propertyFlags->type = QQmlPropertyData::Flags::QObjectDerivedType;
+ } else {
+ int coreIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).coreIndex();
+ int valueTypeIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).valueTypeIndex();
+
+ QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
+ Q_ASSERT(targetCache);
+ QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
+ Q_ASSERT(targetProperty);
+
+ *type = targetProperty->propType();
+
+ writable = targetProperty->isWritable();
+ resettable = targetProperty->isResettable();
+
+ if (valueTypeIndex != -1) {
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
+ if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
+ *type = QVariant::Int;
+ else
+ *type = valueTypeMetaObject->property(valueTypeIndex).userType();
+ } else {
+ if (targetProperty->isEnum()) {
+ *type = QVariant::Int;
+ } else {
+ // Copy type flags
+ propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
+
+ if (targetProperty->isVarProperty())
+ propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
+ }
+ }
+ }
+
+ propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable;
+ propertyFlags->isResettable = resettable;
+}
+
+template <typename ObjectContainer>
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
+ const CompiledObject &component, int objectIndex)
+{
+ const CompiledObject &object = *objectContainer->objectAt(objectIndex);
+ if (!object.aliasCount())
+ return;
+
+ QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
+ Q_ASSERT(propertyCache);
+
+ int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
+ int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
+
+ int aliasIndex = 0;
+ for (auto alias = object.aliasesBegin(), end = object.aliasesEnd(); alias != end; ++alias, ++aliasIndex) {
+ Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+
+ int type = 0;
+ QQmlPropertyData::Flags propertyFlags;
+ propertyDataForAlias(component, *alias, &type, &propertyFlags);
+
+ const QString propertyName = objectContainer->stringAt(alias->nameIndex);
+
+ if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
+ propertyCache->_defaultPropertyName = propertyName;
+
+ propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
+ type, effectiveSignalIndex++);
+ }
+}
+
+template <typename ObjectContainer>
+inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
+{
+ 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)
+ return candidateIndex;
+ }
+ return -1;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYCACHECREATOR_P_H
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
new file mode 100644
index 0000000000..45379d5155
--- /dev/null
+++ b/src/qml/compiler/qqmlpropertyvalidator.cpp
@@ -0,0 +1,703 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 "qqmlpropertyvalidator_p.h"
+
+#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, QV4::CompiledData::CompilationUnit *compilationUnit)
+ : enginePrivate(enginePrivate)
+ , imports(imports)
+ , qmlUnit(compilationUnit->data)
+ , resolvedTypes(compilationUnit->resolvedTypes)
+ , propertyCaches(compilationUnit->propertyCaches)
+ , bindingPropertyDataPerObject(&compilationUnit->bindingPropertyDataPerObject)
+{
+ bindingPropertyDataPerObject->resize(qmlUnit->nObjects);
+}
+
+QVector<QQmlCompileError> QQmlPropertyValidator::validate()
+{
+ return validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0);
+}
+
+typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector;
+
+struct BindingFinder
+{
+ bool operator()(quint32 name, const QV4::CompiledData::Binding *binding) const
+ {
+ return name < binding->propertyNameIndex;
+ }
+ bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const
+ {
+ return binding->propertyNameIndex < name;
+ }
+ bool operator()(const QV4::CompiledData::Binding *lhs, const QV4::CompiledData::Binding *rhs) const
+ {
+ return lhs->propertyNameIndex < rhs->propertyNameIndex;
+ }
+};
+
+QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
+{
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
+
+ if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ Q_ASSERT(obj->nBindings == 1);
+ const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
+ Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ return validateObject(componentBinding->value.objectIndex, componentBinding);
+ }
+
+ QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
+ if (!propertyCache)
+ return QVector<QQmlCompileError>();
+
+ QStringList deferredPropertyNames;
+ {
+ const QMetaObject *mo = propertyCache->firstCppMetaObject();
+ const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
+ if (namesIndex != -1) {
+ QMetaClassInfo classInfo = mo->classInfo(namesIndex);
+ deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
+ }
+ }
+
+ QQmlCustomParser *customParser = 0;
+ if (auto typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ if (typeRef->type)
+ customParser = typeRef->type->customParser();
+ }
+
+ QList<const QV4::CompiledData::Binding*> customBindings;
+
+ // Collect group properties first for sanity checking
+ // vector values are sorted by property name string index.
+ GroupPropertyVector groupProperties;
+ const QV4::CompiledData::Binding *binding = obj->bindingTable();
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
+ if (!binding->isGroupProperty())
+ continue;
+
+ if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ continue;
+
+ if (populatingValueTypeGroupProperty) {
+ return recordError(binding->location, tr("Property assignment expected"));
+ }
+
+ GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
+ groupProperties.insert(pos, binding);
+ }
+
+ QmlIR::PropertyResolver propertyResolver(propertyCache);
+
+ QString defaultPropertyName;
+ QQmlPropertyData *defaultProperty = 0;
+ if (obj->indexOfDefaultPropertyOrAlias != -1) {
+ QQmlPropertyCache *cache = propertyCache->parent();
+ defaultPropertyName = cache->defaultPropertyName();
+ defaultProperty = cache->defaultProperty();
+ } else {
+ defaultPropertyName = propertyCache->defaultPropertyName();
+ defaultProperty = propertyCache->defaultProperty();
+ }
+
+ QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
+
+ binding = obj->bindingTable();
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
+ QString name = stringAt(binding->propertyNameIndex);
+
+ if (customParser) {
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
+ customBindings << binding;
+ continue;
+ }
+ } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
+ && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
+ customBindings << binding;
+ continue;
+ }
+ }
+
+ bool bindingToDefaultProperty = false;
+ bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
+
+ bool notInRevision = false;
+ QQmlPropertyData *pd = 0;
+ if (!name.isEmpty()) {
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ pd = propertyResolver.signal(name, &notInRevision);
+ else
+ pd = propertyResolver.property(name, &notInRevision, isGroupProperty ? QmlIR::PropertyResolver::IgnoreRevision : QmlIR::PropertyResolver::CheckRevision);
+
+ if (notInRevision) {
+ QString typeName = stringAt(obj->inheritedTypeNameIndex);
+ auto *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ if (objectType && objectType->type) {
+ return recordError(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type->module()).arg(objectType->majorVersion).arg(objectType->minorVersion));
+ } else {
+ return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
+ }
+ }
+ } else {
+ if (isGroupProperty)
+ return recordError(binding->location, tr("Cannot assign a value directly to a grouped property"));
+
+ pd = defaultProperty;
+ name = defaultPropertyName;
+ bindingToDefaultProperty = true;
+ }
+
+ if (pd)
+ collectedBindingPropertyData[i] = pd;
+
+ if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
+ QQmlType *type = 0;
+ QQmlImportNamespace *typeNamespace = 0;
+ imports.resolveType(stringAt(binding->propertyNameIndex), &type, 0, 0, &typeNamespace);
+ if (typeNamespace)
+ return recordError(binding->location, tr("Invalid use of namespace"));
+ return recordError(binding->location, tr("Invalid attached object assignment"));
+ }
+
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
+ const QVector<QQmlCompileError> subObjectValidatorErrors = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType()));
+ if (!subObjectValidatorErrors.isEmpty())
+ return subObjectValidatorErrors;
+ }
+
+ // 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)
+ continue;
+
+ 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"));
+ }
+ continue;
+ }
+
+ if (pd) {
+ GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
+ const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
+
+ if (!pd->isWritable()
+ && !pd->isQList()
+ && !binding->isGroupProperty()
+ && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+ ) {
+
+ if (assigningToGroupProperty && binding->type < 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)) {
+ QString error;
+ if (pd->propType() == qMetaTypeId<QQmlScriptString>())
+ error = tr( "Cannot assign multiple values to a script property");
+ else
+ error = tr( "Cannot assign multiple values to a singular property");
+ return recordError(binding->valueLocation, error);
+ }
+
+ if (!bindingToDefaultProperty
+ && !binding->isGroupProperty()
+ && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ && assigningToGroupProperty) {
+ QV4::CompiledData::Location loc = binding->valueLocation;
+ if (loc < (*assignedGroupProperty)->valueLocation)
+ loc = (*assignedGroupProperty)->valueLocation;
+
+ if (pd && QQmlValueTypeFactory::isValueType(pd->propType()))
+ return recordError(loc, tr("Property has already been assigned a value"));
+ return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
+ }
+
+ if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ QQmlCompileError bindingError = validateLiteralBinding(propertyCache, pd, binding);
+ if (bindingError.isSet())
+ return recordError(bindingError);
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ QQmlCompileError bindingError = validateObjectBinding(pd, name, binding);
+ if (bindingError.isSet())
+ return recordError(bindingError);
+ } else if (binding->isGroupProperty()) {
+ if (QQmlValueTypeFactory::isValueType(pd->propType())) {
+ if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())) {
+ if (!pd->isWritable()) {
+ return recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
+ }
+ } else {
+ return recordError(binding->location, tr("Invalid grouped property access"));
+ }
+ } else {
+ if (!enginePrivate->propertyCacheForType(pd->propType())) {
+ return recordError(binding->location, tr("Invalid grouped property access"));
+ }
+ }
+ }
+ } else {
+ if (customParser) {
+ customBindings << binding;
+ continue;
+ }
+ if (bindingToDefaultProperty) {
+ return recordError(binding->location, tr("Cannot assign to non-existent default property"));
+ } else {
+ return recordError(binding->location, tr("Cannot assign to non-existent property \"%1\"").arg(name));
+ }
+ }
+ }
+
+ if (obj->idNameIndex) {
+ bool notInRevision = false;
+ collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
+ }
+
+ if (customParser && !customBindings.isEmpty()) {
+ customParser->clearErrors();
+ customParser->validator = this;
+ customParser->engine = enginePrivate;
+ customParser->imports = &imports;
+ customParser->verifyBindings(qmlUnit, customBindings);
+ customParser->validator = 0;
+ customParser->engine = 0;
+ customParser->imports = (QQmlImports*)0;
+ QVector<QQmlCompileError> parserErrors = customParser->errors();
+ if (!parserErrors.isEmpty())
+ return parserErrors;
+ }
+
+ (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
+
+ QVector<QQmlCompileError> noError;
+ return noError;
+}
+
+QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
+{
+ if (property->isQList()) {
+ return QQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
+ }
+
+ QQmlCompileError noError;
+
+ if (property->isEnum()) {
+ if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
+ return noError;
+
+ QString value = binding->valueAsString(qmlUnit);
+ QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex());
+ bool ok;
+ if (p.isFlagType()) {
+ p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
+ } else
+ p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
+
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
+ }
+ return noError;
+ }
+
+ switch (property->propType()) {
+ case QMetaType::QVariant:
+ break;
+ case QVariant::String: {
+ if (!binding->evaluatesToString()) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string expected"));
+ }
+ }
+ break;
+ case QVariant::StringList: {
+ if (!binding->evaluatesToString()) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or string list expected"));
+ }
+ }
+ break;
+ case QVariant::ByteArray: {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: byte array expected"));
+ }
+ }
+ break;
+ case QVariant::Url: {
+ if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url expected"));
+ }
+ }
+ break;
+ case QVariant::UInt: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double d = binding->valueAsNumber();
+ if (double(uint(d)) == d)
+ return noError;
+ }
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected"));
+ }
+ break;
+ case QVariant::Int: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double d = binding->valueAsNumber();
+ if (double(int(d)) == d)
+ return noError;
+ }
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: int expected"));
+ }
+ break;
+ case QMetaType::Float: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+ }
+ }
+ break;
+ case QVariant::Double: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+ }
+ }
+ break;
+ case QVariant::Color: {
+ bool ok = false;
+ QQmlStringConverters::rgbaFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: color expected"));
+ }
+ }
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date: {
+ bool ok = false;
+ QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: date expected"));
+ }
+ }
+ break;
+ case QVariant::Time: {
+ bool ok = false;
+ QQmlStringConverters::timeFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: time expected"));
+ }
+ }
+ break;
+ case QVariant::DateTime: {
+ bool ok = false;
+ QQmlStringConverters::dateTimeFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: datetime expected"));
+ }
+ }
+ break;
+#endif // QT_NO_DATESTRING
+ case QVariant::Point: {
+ bool ok = false;
+ QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::PointF: {
+ bool ok = false;
+ QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::Size: {
+ bool ok = false;
+ QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+ }
+ }
+ break;
+ case QVariant::SizeF: {
+ bool ok = false;
+ QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+ }
+ }
+ break;
+ case QVariant::Rect: {
+ bool ok = false;
+ QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: rect expected"));
+ }
+ }
+ break;
+ case QVariant::RectF: {
+ bool ok = false;
+ QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok);
+ if (!ok) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::Bool: {
+ if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: boolean expected"));
+ }
+ }
+ break;
+ case QVariant::Vector2D: {
+ struct {
+ float xp;
+ float yp;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected"));
+ }
+ }
+ break;
+ case QVariant::Vector3D: {
+ struct {
+ float xp;
+ float yp;
+ float zy;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected"));
+ }
+ }
+ break;
+ case QVariant::Vector4D: {
+ struct {
+ float xp;
+ float yp;
+ float zy;
+ float wp;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected"));
+ }
+ }
+ break;
+ case QVariant::Quaternion: {
+ struct {
+ float wp;
+ float xp;
+ float yp;
+ float zp;
+ } vec;
+ if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: quaternion expected"));
+ }
+ }
+ break;
+ case QVariant::RegExp:
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+ 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) {
+ return QQmlCompileError(binding->valueLocation, 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);
+ if (ok) {
+ double n = binding->valueAsNumber();
+ if (double(int(n)) != n)
+ ok = false;
+ }
+ if (!ok)
+ return QQmlCompileError(binding->valueLocation, 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) {
+ return QQmlCompileError(binding->valueLocation, 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) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected"));
+ }
+ break;
+ } else if (property->propType() == qMetaTypeId<QList<QString> >()) {
+ if (!binding->evaluatesToString()) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected"));
+ }
+ break;
+ } else if (property->propType() == qMetaTypeId<QJSValue>()) {
+ break;
+ } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
+ break;
+ }
+
+ // otherwise, try a custom type assignment
+ QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
+ if (!converter) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType()))));
+ }
+ }
+ break;
+ }
+ return noError;
+}
+
+/*!
+ Returns true if from can be assigned to a (QObject) property of type
+ to.
+*/
+bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
+{
+ QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
+
+ while (fromMo) {
+ if (fromMo == toMo)
+ return true;
+ fromMo = fromMo->parent();
+ }
+ return false;
+}
+
+QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
+{
+ QVector<QQmlCompileError> errors;
+ errors.append(QQmlCompileError(location, description));
+ return errors;
+}
+
+QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QQmlCompileError &error) const
+{
+ QVector<QQmlCompileError> errors;
+ errors.append(error);
+ return errors;
+}
+
+QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
+{
+ QQmlCompileError noError;
+
+ if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
+
+ bool isValueSource = false;
+ bool isPropertyInterceptor = false;
+
+ QQmlType *qmlType = 0;
+ const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(binding->value.objectIndex);
+ if (auto *typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex)) {
+ QQmlPropertyCache *cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ const QMetaObject *mo = cache->firstCppMetaObject();
+ while (mo && !qmlType) {
+ qmlType = QQmlMetaType::qmlType(mo);
+ mo = mo->superClass();
+ }
+ Q_ASSERT(qmlType);
+ }
+
+ if (qmlType) {
+ isValueSource = qmlType->propertyValueSourceCast() != -1;
+ isPropertyInterceptor = qmlType->propertyValueInterceptorCast() != -1;
+ }
+
+ if (!isValueSource && !isPropertyInterceptor) {
+ return QQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
+ }
+
+ return noError;
+ }
+
+ if (QQmlMetaType::isInterface(property->propType())) {
+ // Can only check at instantiation time if the created sub-object successfully casts to the
+ // target interface.
+ return noError;
+ } else if (property->propType() == QMetaType::QVariant) {
+ // We can convert everything to QVariant :)
+ return noError;
+ } else if (property->isQList()) {
+ const int listType = enginePrivate->listType(property->propType());
+ if (!QQmlMetaType::isInterface(listType)) {
+ QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
+ if (!canCoerce(listType, source)) {
+ return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
+ }
+ }
+ return noError;
+ } else if (qmlUnit->objectAt(binding->value.objectIndex)->flags & QV4::CompiledData::Object::IsComponent) {
+ return noError;
+ } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
+ return noError;
+ } else if (QQmlValueTypeFactory::isValueType(property->propType())) {
+ return QQmlCompileError(binding->location, tr("Unexpected object assignment"));
+ } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
+ return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
+ } else {
+ // We want to raw metaObject here as the raw metaobject is the
+ // actual property type before we applied any extensions that might
+ // effect the properties on the type, but don't effect assignability
+ QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType());
+
+ // Will be true if the assgned type inherits propertyMetaObject
+ bool isAssignable = false;
+ // Determine isAssignable value
+ if (propertyMetaObject) {
+ QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
+ while (c && !isAssignable) {
+ isAssignable |= c == propertyMetaObject;
+ c = c->parent();
+ }
+ }
+
+ if (!isAssignable) {
+ return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to property"));
+ }
+ }
+ return noError;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertyvalidator_p.h b/src/qml/compiler/qqmlpropertyvalidator_p.h
new file mode 100644
index 0000000000..d0bd314461
--- /dev/null
+++ b/src/qml/compiler/qqmlpropertyvalidator_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQMLPROPERTYVALIDATOR_P_H
+#define QQMLPROPERTYVALIDATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypecompiler_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlPropertyValidator
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
+public:
+ QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, QV4::CompiledData::CompilationUnit *compilationUnit);
+
+ QVector<QQmlCompileError> validate();
+
+private:
+ QVector<QQmlCompileError> validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const;
+ QQmlCompileError validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
+ QQmlCompileError validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
+
+ bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
+
+ QVector<QQmlCompileError> recordError(const QV4::CompiledData::Location &location, const QString &description) const Q_REQUIRED_RESULT;
+ QVector<QQmlCompileError> recordError(const QQmlCompileError &error) const Q_REQUIRED_RESULT;
+ QString stringAt(int index) const { return qmlUnit->stringAt(index); }
+
+ QQmlEnginePrivate *enginePrivate;
+ const QQmlImports &imports;
+ const QV4::CompiledData::Unit *qmlUnit;
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
+ const QQmlPropertyCacheVector &propertyCaches;
+
+ QVector<QV4::CompiledData::BindingPropertyData> * const bindingPropertyDataPerObject;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYVALIDATOR_P_H
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 19beb13e45..5e05485b93 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -44,9 +44,10 @@
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlstringconverters_p.h>
#include <private/qv4ssa_p.h>
+#include "qqmlpropertycachecreator_p.h"
+
#define COMPILE_EXCEPTION(token, desc) \
{ \
recordError((token)->location, desc); \
@@ -55,82 +56,22 @@
QT_BEGIN_NAMESPACE
-QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QmlIR::Document *parsedQML)
- : engine(engine)
- , compiledData(compiledData)
+QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
+ QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
+ : resolvedTypes(resolvedTypeCache)
+ , engine(engine)
, typeData(typeData)
+ , importCache(importCache)
, document(parsedQML)
{
}
-bool QQmlTypeCompiler::compile()
+QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
{
- importCache = new QQmlTypeNameCache;
-
- foreach (const QString &ns, typeData->namespaces())
- importCache->add(ns);
-
- // Add any Composite Singletons that were used to the import cache
- foreach (const QQmlTypeData::TypeReference &singleton, typeData->compositeSingletons())
- importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
-
- typeData->imports().populateCache(importCache.data());
-
- const QHash<int, QQmlTypeData::TypeReference> &resolvedTypes = typeData->resolvedTypeRefs();
- for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
- resolvedType != end; ++resolvedType) {
- QScopedPointer<QQmlCompiledData::TypeReference> ref(new QQmlCompiledData::TypeReference);
- QQmlType *qmlType = resolvedType->type;
- if (resolvedType->typeData) {
- if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) {
- QQmlError error;
- QString reason = tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName());
- error.setDescription(reason);
- error.setColumn(resolvedType->location.column);
- error.setLine(resolvedType->location.line);
- recordError(error);
- return false;
- }
- ref->component = resolvedType->typeData->compiledData();
- ref->component->addref();
- } else if (qmlType) {
- ref->type = qmlType;
- Q_ASSERT(ref->type);
-
- if (resolvedType->needsCreation && !ref->type->isCreatable()) {
- QQmlError error;
- QString reason = ref->type->noCreationReason();
- if (reason.isEmpty())
- reason = tr("Element is not creatable.");
- error.setDescription(reason);
- error.setColumn(resolvedType->location.column);
- error.setLine(resolvedType->location.line);
- recordError(error);
- return false;
- }
-
- if (ref->type->containsRevisionedAttributes()) {
- ref->typePropertyCache = engine->cache(ref->type,
- resolvedType->minorVersion);
- if (!ref->typePropertyCache) {
- QQmlError cacheError;
- cacheError.setColumn(resolvedType->location.column);
- cacheError.setLine(resolvedType->location.line);
- recordError(cacheError);
- return false;
- }
- ref->typePropertyCache->addref();
- }
- }
- ref->majorVersion = resolvedType->majorVersion;
- ref->minorVersion = resolvedType->minorVersion;
- ref->doDynamicTypeCheck();
- compiledData->resolvedTypes.insert(resolvedType.key(), ref.take());
- }
-
// Build property caches and VME meta object data
- for (QHash<int, QQmlCompiledData::TypeReference*>::ConstIterator it = compiledData->resolvedTypes.constBegin(), end = compiledData->resolvedTypes.constEnd();
+ for (auto it = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
it != end; ++it) {
QQmlCustomParser *customParser = (*it)->type ? (*it)->type->customParser() : 0;
if (customParser)
@@ -138,9 +79,12 @@ bool QQmlTypeCompiler::compile()
}
{
- QQmlPropertyCacheCreator propertyCacheBuilder(this);
- if (!propertyCacheBuilder.buildMetaObjects())
- return false;
+ QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, engine, this, imports());
+ QQmlCompileError error = propertyCacheBuilder.buildMetaObjects();
+ if (error.isSet()) {
+ recordError(error);
+ return nullptr;
+ }
}
{
@@ -151,13 +95,13 @@ bool QQmlTypeCompiler::compile()
{
SignalHandlerConverter converter(this);
if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations())
- return false;
+ return nullptr;
}
{
QQmlEnumTypeResolver enumResolver(this);
if (!enumResolver.resolveEnumBindings())
- return false;
+ return nullptr;
}
{
@@ -170,41 +114,19 @@ bool QQmlTypeCompiler::compile()
annotator.annotateBindingsToAliases();
}
- // Collect imported scripts
- const QList<QQmlTypeData::ScriptReference> &scripts = typeData->resolvedScripts();
- QVector<QQmlScriptData *> dependentScripts;
- dependentScripts.reserve(scripts.count());
- for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) {
- const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex);
-
- QStringRef qualifier(&script.qualifier);
- QString enclosingNamespace;
-
- const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
- if (lastDotIndex != -1) {
- enclosingNamespace = qualifier.left(lastDotIndex).toString();
- qualifier = qualifier.mid(lastDotIndex+1);
- }
-
- importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
- QQmlScriptData *scriptData = script.script->scriptData();
- scriptData->addref();
- dependentScripts << scriptData;
- }
-
// Resolve component boundaries and aliases
{
// Scan for components, determine their scopes and resolve aliases within the scope.
QQmlComponentAndAliasResolver resolver(this);
if (!resolver.resolve())
- return false;
+ return nullptr;
}
{
QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
if (!deferredAndCustomParserBindingScanner.scanObject())
- return false;
+ return nullptr;
}
// Compile JS binding expressions and signal handlers
@@ -219,7 +141,7 @@ bool QQmlTypeCompiler::compile()
QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
- return false;
+ return nullptr;
QQmlJavaScriptBindingExpressionSimplificationPass pass(this);
pass.reduceTranslationBindings();
@@ -234,73 +156,45 @@ bool QQmlTypeCompiler::compile()
// Generate QML compiled type data structures
QmlIR::QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::Unit *qmlUnit = qmlGenerator.generate(*document);
+ QV4::CompiledData::Unit *qmlUnit = qmlGenerator.generate(*document, QQmlEnginePrivate::get(engine), resolvedTypes);
Q_ASSERT(document->javaScriptCompilationUnit);
// The js unit owns the data and will free the qml unit.
document->javaScriptCompilationUnit->data = qmlUnit;
- compiledData->compilationUnit = document->javaScriptCompilationUnit;
- compiledData->compilationUnit->propertyCaches = m_propertyCaches;
- compiledData->compilationUnit->importCache = importCache;
- compiledData->compilationUnit->dependentScripts = dependentScripts;
-
- // Add to type registry of composites
- if (compiledData->compilationUnit->isCompositeType())
- engine->registerInternalCompositeType(compiledData);
- else {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
- QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- if (typeRef->component) {
- compiledData->metaTypeId = typeRef->component->metaTypeId;
- compiledData->listMetaTypeId = typeRef->component->listMetaTypeId;
- } else {
- compiledData->metaTypeId = typeRef->type->typeId();
- compiledData->listMetaTypeId = typeRef->type->qListTypeId();
- }
- }
-
- // Sanity check property bindings
- QQmlPropertyValidator validator(this);
- if (!validator.validate())
- return false;
+ QV4::CompiledData::CompilationUnit *compilationUnit = document->javaScriptCompilationUnit;
+ compilationUnit = document->javaScriptCompilationUnit;
+ compilationUnit->importCache = importCache;
+ compilationUnit->resolvedTypes = resolvedTypes;
+ compilationUnit->propertyCaches = std::move(m_propertyCaches);
+ Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->data->nObjects));
- // Collect some data for instantiation later.
- int bindingCount = 0;
- int parserStatusCount = 0;
- int objectCount = 0;
- for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
- bindingCount += obj->nBindings;
- if (QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex)) {
- if (QQmlType *qmlType = typeRef->type) {
- if (qmlType->parserStatusCast() != -1)
- ++parserStatusCount;
- }
- ++objectCount;
- if (typeRef->component) {
- bindingCount += typeRef->component->compilationUnit->totalBindingsCount;
- parserStatusCount += typeRef->component->compilationUnit->totalParserStatusCount;
- objectCount += typeRef->component->compilationUnit->totalObjectCount;
- }
- }
- }
- compiledData->compilationUnit->totalBindingsCount = bindingCount;
- compiledData->compilationUnit->totalParserStatusCount = parserStatusCount;
- compiledData->compilationUnit->totalObjectCount = objectCount;
+ if (errors.isEmpty())
+ return compilationUnit;
+ else
+ return nullptr;
+}
- Q_ASSERT(compiledData->compilationUnit->propertyCaches.count() == static_cast<int>(compiledData->compilationUnit->data->nObjects));
+void QQmlTypeCompiler::recordError(QQmlError error)
+{
+ error.setUrl(url());
+ errors << error;
+}
- return errors.isEmpty();
+void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
+{
+ QQmlError error;
+ error.setLine(location.line);
+ error.setColumn(location.column);
+ error.setDescription(description);
+ error.setUrl(url());
+ errors << error;
}
-void QQmlTypeCompiler::recordError(const QQmlError &error)
+void QQmlTypeCompiler::recordError(const QQmlCompileError &error)
{
- QQmlError e = error;
- e.setUrl(url());
- errors << e;
+ recordError(error.location, error.description);
}
QString QQmlTypeCompiler::stringAt(int idx) const
@@ -320,7 +214,7 @@ QV4::IR::Module *QQmlTypeCompiler::jsIRModule() const
const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
{
- return compiledData->compilationUnit->data;
+ return document->javaScriptCompilationUnit->data;
}
const QQmlImports *QQmlTypeCompiler::imports() const
@@ -328,12 +222,7 @@ const QQmlImports *QQmlTypeCompiler::imports() const
return &typeData->imports();
}
-QHash<int, QQmlCompiledData::TypeReference*> *QQmlTypeCompiler::resolvedTypes()
-{
- return &compiledData->resolvedTypes;
-}
-
-QList<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects()
+QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
{
return &document->objects;
}
@@ -343,15 +232,20 @@ int QQmlTypeCompiler::rootObjectIndex() const
return document->indexOfRootObject;
}
-void QQmlTypeCompiler::setPropertyCaches(const QQmlPropertyCacheVector &caches)
+void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches)
+{
+ m_propertyCaches = std::move(caches);
+ Q_ASSERT(m_propertyCaches.count() >= document->indexOfRootObject);
+}
+
+const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
{
- m_propertyCaches = caches;
- Q_ASSERT(caches.count() >= document->indexOfRootObject);
+ return &m_propertyCaches;
}
-const QQmlPropertyCacheVector &QQmlTypeCompiler::propertyCaches() const
+QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches()
{
- return m_propertyCaches;
+ return std::move(m_propertyCaches);
}
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
@@ -371,7 +265,7 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData)
{
- compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData;
+ document->javaScriptCompilationUnit->bindingPropertyDataPerObject = propertyData;
}
QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
@@ -379,462 +273,34 @@ QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scrip
return object->bindingAsString(document, scriptIndex);
}
-QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
- : compiler(typeCompiler)
-{
-}
-
-void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, const QString &description) const
-{
- QQmlError error;
- error.setLine(location.line);
- error.setColumn(location.column);
- error.setDescription(description);
- compiler->recordError(error);
-}
-
-static QAtomicInt classIndexCounter(0);
-
-QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , qmlObjects(*typeCompiler->qmlObjects())
- , imports(typeCompiler->imports())
- , resolvedTypes(typeCompiler->resolvedTypes())
-{
-}
-
-QQmlPropertyCacheCreator::~QQmlPropertyCacheCreator()
-{
- for (int i = 0; i < propertyCaches.count(); ++i)
- if (QQmlPropertyCache *cache = propertyCaches.at(i).data())
- cache->release();
- propertyCaches.clear();
-}
-
-bool QQmlPropertyCacheCreator::buildMetaObjects()
-{
- propertyCaches.resize(qmlObjects.count());
-
- if (!buildMetaObjectRecursively(compiler->rootObjectIndex(), /*referencing object*/-1, /*instantiating binding*/0))
- return false;
-
- compiler->setPropertyCaches(propertyCaches);
- propertyCaches.clear();
-
- return true;
-}
-
-bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding)
+void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion)
{
- const QmlIR::Object *obj = qmlObjects.at(objectIndex);
-
- QQmlPropertyCache *baseTypeCache = 0;
- QQmlPropertyData *instantiatingProperty = 0;
- if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
- Q_ASSERT(referencingObjectIndex >= 0);
- QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex).data();
- Q_ASSERT(parentCache);
- Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
-
- bool notInRevision = false;
- instantiatingProperty = QmlIR::PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
- if (instantiatingProperty) {
- if (instantiatingProperty->isQObject()) {
- baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType);
- Q_ASSERT(baseTypeCache);
- } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType)) {
- baseTypeCache = enginePrivate->cache(vtmo);
- Q_ASSERT(baseTypeCache);
- }
- }
- }
-
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
- if (!needVMEMetaObject) {
- for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
-
- // On assignments are implemented using value interceptors, which require a VME meta object.
- needVMEMetaObject = true;
-
- // 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
- // because interceptors can't go to the shared value type instances.
- if (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) {
- needVMEMetaObject = false;
- if (!ensureVMEMetaObject(referencingObjectIndex))
- return false;
- }
- break;
- }
- }
- }
-
- if (obj->inheritedTypeNameIndex != 0) {
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
-
- if (typeRef->isFullyDynamicType) {
- if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
- recordError(obj->location, tr("Fully dynamic types cannot declare new properties."));
- return false;
- }
- if (obj->signalCount() > 0) {
- recordError(obj->location, tr("Fully dynamic types cannot declare new signals."));
- return false;
- }
- if (obj->functionCount() > 0) {
- recordError(obj->location, tr("Fully Dynamic types cannot declare new functions."));
- return false;
- }
- }
-
- baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- Q_ASSERT(baseTypeCache);
- } else if (instantiatingBinding && instantiatingBinding->isAttachedProperty()) {
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(instantiatingBinding->propertyNameIndex);
- Q_ASSERT(typeRef);
- QQmlType *qmltype = typeRef->type;
- if (!qmltype) {
- QString propertyName = stringAt(instantiatingBinding->propertyNameIndex);
- if (imports->resolveType(propertyName, &qmltype, 0, 0, 0)) {
- if (qmltype->isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- QQmlCompiledData *data = tdata->compiledData();
- qmltype = QQmlMetaType::qmlType(data->metaTypeId);
-
- tdata->release();
- }
- }
- }
-
- const QMetaObject *attachedMo = qmltype ? qmltype->attachedPropertiesType(enginePrivate) : 0;
- if (!attachedMo) {
- recordError(instantiatingBinding->location, tr("Non-existent attached object"));
- return false;
- }
- baseTypeCache = enginePrivate->cache(attachedMo);
- Q_ASSERT(baseTypeCache);
- }
-
- if (baseTypeCache) {
- if (needVMEMetaObject) {
- if (!createMetaObject(objectIndex, obj, baseTypeCache))
- return false;
- } else {
- if (QQmlPropertyCache *oldCache = propertyCaches.at(objectIndex).data())
- oldCache->release();
- propertyCaches[objectIndex] = baseTypeCache;
- baseTypeCache->addref();
- }
- }
+ const quint32 moduleIdx = registerString(module);
+ const quint32 qualifierIdx = registerString(qualifier);
- if (propertyCaches.at(objectIndex).data()) {
- for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next)
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding))
- return false;
- }
+ for (int i = 0, count = document->imports.count(); i < count; ++i) {
+ const QV4::CompiledData::Import *existingImport = document->imports.at(i);
+ if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
+ && existingImport->uriIndex == moduleIdx
+ && existingImport->qualifierIndex == qualifierIdx)
+ return;
}
-
- return true;
+ auto pool = memoryPool();
+ QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
+ import->type = QV4::CompiledData::Import::ImportLibrary;
+ import->majorVersion = majorVersion;
+ import->minorVersion = minorVersion;
+ import->uriIndex = moduleIdx;
+ import->qualifierIndex = qualifierIdx;
+ document->imports.append(import);
}
-bool QQmlPropertyCacheCreator::ensureVMEMetaObject(int objectIndex)
+QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
+ : compiler(typeCompiler)
{
- const bool willCreateVMEMetaObject = propertyCaches.at(objectIndex).flag();
- if (willCreateVMEMetaObject)
- return true;
- const QmlIR::Object *obj = qmlObjects.at(objectIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- QQmlPropertyCache *baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- return createMetaObject(objectIndex, obj, baseTypeCache);
-}
-
-bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache)
-{
- QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
- obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
- obj->signalCount() + obj->propertyCount() + obj->aliasCount());
-
- if (QQmlPropertyCache *oldCache = propertyCaches.at(objectIndex).data())
- oldCache->release();
- propertyCaches[objectIndex] = cache;
- // Indicate that this object also needs a VME meta-object at run-time
- propertyCaches[objectIndex].setFlag();
-
- struct TypeData {
- QV4::CompiledData::Property::Type dtype;
- int metaType;
- } builtinTypes[] = {
- { QV4::CompiledData::Property::Var, QMetaType::QVariant },
- { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
- { QV4::CompiledData::Property::Int, QMetaType::Int },
- { QV4::CompiledData::Property::Bool, QMetaType::Bool },
- { QV4::CompiledData::Property::Real, QMetaType::Double },
- { QV4::CompiledData::Property::String, QMetaType::QString },
- { QV4::CompiledData::Property::Url, QMetaType::QUrl },
- { QV4::CompiledData::Property::Color, QMetaType::QColor },
- { QV4::CompiledData::Property::Font, QMetaType::QFont },
- { QV4::CompiledData::Property::Time, QMetaType::QTime },
- { QV4::CompiledData::Property::Date, QMetaType::QDate },
- { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
- { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
- { QV4::CompiledData::Property::Point, QMetaType::QPointF },
- { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
- { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
- { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
- { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
- { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
- { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
- };
- static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
-
- QByteArray newClassName;
-
- if (objectIndex == compiler->rootObjectIndex()) {
- QString path = compiler->url().path();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- if (lastSlash > -1) {
- const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
- if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
- newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
- QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
- }
- }
- if (newClassName.isEmpty()) {
- newClassName = QQmlMetaObject(baseTypeCache).className();
- newClassName.append("_QML_");
- newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
- }
-
- cache->_dynamicClassName = newClassName;
-
- int varPropCount = 0;
-
- QmlIR::PropertyResolver resolver(baseTypeCache);
-
- for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
- if (p->type == QV4::CompiledData::Property::Var)
- varPropCount++;
-
- bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
- if (d && d->isFinal())
- COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
- }
-
- for (const QmlIR::Alias *a = obj->firstAlias(); a; a = a->next) {
- bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
- if (d && d->isFinal())
- COMPILE_EXCEPTION(a, tr("Cannot override FINAL property"));
- }
-
- int effectivePropertyIndex = cache->propertyIndexCacheStart;
- int effectiveMethodIndex = cache->methodIndexCacheStart;
-
- // For property change signal override detection.
- // We prepopulate a set of signal names which already exist in the object,
- // and throw an error if there is a signal/method defined as an override.
- QSet<QString> seenSignals;
- seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
- QQmlPropertyCache *parentCache = cache;
- while ((parentCache = parentCache->parent())) {
- if (int pSigCount = parentCache->signalCount()) {
- int pSigOffset = parentCache->signalOffset();
- for (int i = pSigOffset; i < pSigCount; ++i) {
- QQmlPropertyData *currPSig = parentCache->signal(i);
- // XXX TODO: find a better way to get signal name from the property data :-/
- for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
- iter != parentCache->stringCache.end(); ++iter) {
- if (currPSig == (*iter).second) {
- seenSignals.insert(iter.key());
- break;
- }
- }
- }
- }
- }
-
- // Set up notify signals for properties - first normal, then alias
- for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
- quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
- QQmlPropertyData::IsVMESignal;
-
- QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
-
- cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
- }
-
- for (const QmlIR::Alias *a = obj->firstAlias(); a; a = a->next) {
- quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
- QQmlPropertyData::IsVMESignal;
-
- QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
-
- cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
- }
-
- // Dynamic signals
- for (const QmlIR::Signal *s = obj->firstSignal(); s; s = s->next) {
- const int paramCount = s->parameters->count;
-
- QList<QByteArray> names;
- names.reserve(paramCount);
- QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
-
- if (paramCount) {
- paramTypes[0] = paramCount;
-
- QmlIR::SignalParameter *param = s->parameters->first;
- for (int i = 0; i < paramCount; ++i, param = param->next) {
- names.append(stringAt(param->nameIndex).toUtf8());
- if (param->type < builtinTypeCount) {
- // built-in type
- paramTypes[i + 1] = builtinTypes[param->type].metaType;
- } else {
- // lazily resolved type
- Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
- const QString customTypeName = stringAt(param->customTypeNameIndex);
- QQmlType *qmltype = 0;
- if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0))
- COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(customTypeName));
-
- if (qmltype->isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- QQmlCompiledData *data = tdata->compiledData();
-
- paramTypes[i + 1] = data->metaTypeId;
-
- tdata->release();
- } else {
- paramTypes[i + 1] = qmltype->typeId();
- }
- }
- }
- }
-
- quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
- QQmlPropertyData::IsVMESignal;
- if (paramCount)
- flags |= QQmlPropertyData::HasArguments;
-
- QString signalName = stringAt(s->nameIndex);
- if (seenSignals.contains(signalName))
- COMPILE_EXCEPTION(s, tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
- seenSignals.insert(signalName);
-
- cache->appendSignal(signalName, flags, effectiveMethodIndex++,
- paramCount?paramTypes.constData():0, names);
- }
-
-
- // Dynamic slots
- for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) {
- QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration;
-
- quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
-
- if (astFunction->formals)
- flags |= QQmlPropertyData::HasArguments;
-
- QString slotName = astFunction->name.toString();
- if (seenSignals.contains(slotName))
- COMPILE_EXCEPTION(s, tr("Duplicate method name: invalid override of property change signal or superclass signal"));
- // Note: we don't append slotName to the seenSignals list, since we don't
- // protect against overriding change signals or methods with properties.
-
- QList<QByteArray> parameterNames;
- QQmlJS::AST::FormalParameterList *param = astFunction->formals;
- while (param) {
- parameterNames << param->name.toUtf8();
- param = param->next;
- }
-
- cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
- }
-
-
- // Dynamic properties
- int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
- int propertyIdx = 0;
- for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
- int propertyType = 0;
- quint32 propertyFlags = 0;
-
- if (p->type == QV4::CompiledData::Property::Var) {
- propertyType = QMetaType::QVariant;
- propertyFlags = QQmlPropertyData::IsVarProperty;
- } else if (p->type < builtinTypeCount) {
- propertyType = builtinTypes[p->type].metaType;
-
- if (p->type == QV4::CompiledData::Property::Variant)
- propertyFlags |= QQmlPropertyData::IsQVariant;
- } else {
- Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
- p->type == QV4::CompiledData::Property::Custom);
-
- QQmlType *qmltype = 0;
- if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) {
- COMPILE_EXCEPTION(p, tr("Invalid property type"));
- }
-
- Q_ASSERT(qmltype);
- if (qmltype->isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- QQmlCompiledData *data = tdata->compiledData();
-
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = data->metaTypeId;
- } else {
- propertyType = data->listMetaTypeId;
- }
-
- tdata->release();
- } else {
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = qmltype->typeId();
- } else {
- propertyType = qmltype->qListTypeId();
- }
- }
-
- if (p->type == QV4::CompiledData::Property::Custom)
- propertyFlags |= QQmlPropertyData::IsQObjectDerived;
- else
- propertyFlags |= QQmlPropertyData::IsQList;
- }
-
- if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
- propertyFlags |= QQmlPropertyData::IsWritable;
-
-
- QString propertyName = stringAt(p->nameIndex);
- if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
- cache->_defaultPropertyName = propertyName;
- cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- propertyType, effectiveSignalIndex);
+}
- effectiveSignalIndex++;
- }
- return true;
-}
SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
@@ -842,7 +308,7 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
, qmlObjects(*typeCompiler->qmlObjects())
, imports(typeCompiler->imports())
, customParsers(typeCompiler->customParserCache())
- , resolvedTypes(*typeCompiler->resolvedTypes())
+ , resolvedTypes(typeCompiler->resolvedTypes)
, illegalNames(QV8Engine::get(QQmlEnginePrivate::get(typeCompiler->enginePrivate()))->illegalNames())
, propertyCaches(typeCompiler->propertyCaches())
{
@@ -852,7 +318,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
{
for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) {
const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- QQmlPropertyCache *cache = propertyCaches.at(objectIndex).data();
+ QQmlPropertyCache *cache = propertyCaches->at(objectIndex);
if (!cache)
continue;
if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
@@ -876,7 +342,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
// Attached property?
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(binding->propertyNameIndex);
+ auto *typeRef = resolvedTypes.value(binding->propertyNameIndex);
QQmlType *type = typeRef ? typeRef->type : 0;
if (!type) {
if (imports->resolveType(propertyName, &type, 0, 0, 0)) {
@@ -885,8 +351,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
- QQmlCompiledData *data = tdata->compiledData();
- type = QQmlMetaType::qmlType(data->metaTypeId);
+ auto compilationUnit = tdata->compilationUnit();
+ type = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
tdata->release();
}
@@ -924,7 +390,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
bool notInRevision = false;
QQmlPropertyData *signal = resolver.signal(propertyName, &notInRevision);
if (signal) {
- int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex);
+ int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
sigIndex = propertyCache->originalClone(sigIndex);
bool unnamedParameter = false;
@@ -949,7 +415,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
const QQmlType *type = typeRef ? typeRef->type : 0;
if (type) {
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type->module()).arg(type->majorVersion()).arg(type->minorVersion()));
@@ -1005,7 +471,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
QQmlJS::MemoryPool *pool = compiler->memoryPool();
QQmlJS::AST::FormalParameterList *paramList = 0;
- foreach (const QString &param, parameters) {
+ for (const QString &param : qAsConst(parameters)) {
QStringRef paramNameRef = compiler->newStringRef(param);
if (paramList)
@@ -1053,14 +519,14 @@ QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
, qmlObjects(*typeCompiler->qmlObjects())
, propertyCaches(typeCompiler->propertyCaches())
, imports(typeCompiler->imports())
- , resolvedTypes(typeCompiler->resolvedTypes())
+ , resolvedTypes(&typeCompiler->resolvedTypes)
{
}
bool QQmlEnumTypeResolver::resolveEnumBindings()
{
for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches.at(i).data();
+ QQmlPropertyCache *propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
@@ -1081,7 +547,7 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
if (!pd)
continue;
- if (!pd->isEnum() && pd->propType != QMetaType::Int)
+ if (!pd->isEnum() && pd->propType() != QMetaType::Int)
continue;
if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
@@ -1104,14 +570,14 @@ bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QS
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->value.d = (double)enumValue;
+ binding->setNumberValueInternal((double)enumValue);
binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
return true;
}
bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding)
{
- bool isIntProp = (prop->propType == QMetaType::Int) && !prop->isEnum();
+ bool isIntProp = (prop->propType() == QMetaType::Int) && !prop->isEnum();
if (!prop->isEnum() && !isIntProp)
return true;
@@ -1153,9 +619,9 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
int value = 0;
bool ok = false;
- QQmlCompiledData::TypeReference *tr = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ auto *tr = resolvedTypes->value(obj->inheritedTypeNameIndex);
if (type && tr && tr->type == type) {
- QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex);
+ QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
// When these two match, we can short cut the search
if (mprop.isFlagType()) {
@@ -1246,7 +712,7 @@ QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
void QQmlAliasAnnotator::annotateBindingsToAliases()
{
for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches.at(i).data();
+ QQmlPropertyCache *propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
@@ -1259,7 +725,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
if (!binding->isValueBinding())
continue;
bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
+ QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (pd && pd->isAlias())
binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
}
@@ -1278,7 +744,7 @@ void QQmlScriptStringScanner::scan()
{
const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>();
for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches.at(i).data();
+ QQmlPropertyCache *propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
@@ -1291,8 +757,8 @@ void QQmlScriptStringScanner::scan()
if (binding->type != QV4::CompiledData::Binding::Type_Script)
continue;
bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
- if (!pd || pd->propType != scriptStringMetaType)
+ QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
+ if (!pd || pd->propType() != scriptStringMetaType)
continue;
QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
@@ -1311,9 +777,8 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
, pool(typeCompiler->memoryPool())
, qmlObjects(typeCompiler->qmlObjects())
, indexOfRootObject(typeCompiler->rootObjectIndex())
- , _componentIndex(-1)
- , resolvedTypes(typeCompiler->resolvedTypes())
- , propertyCaches(typeCompiler->propertyCaches())
+ , resolvedTypes(&typeCompiler->resolvedTypes)
+ , propertyCaches(std::move(typeCompiler->takePropertyCaches()))
{
}
@@ -1330,18 +795,18 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
continue;
const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
- QQmlCompiledData::TypeReference *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
+ auto *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
Q_ASSERT(tr);
if (QQmlType *targetType = tr->type) {
if (targetType->metaObject() == &QQmlComponent::staticMetaObject)
continue;
- } else if (tr->component) {
- if (tr->component->compilationUnit->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
+ } else if (tr->compilationUnit) {
+ if (tr->compilationUnit->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
continue;
}
QQmlPropertyData *pd = 0;
- if (binding->propertyNameIndex != 0) {
+ if (binding->propertyNameIndex != quint32(0)) {
bool notInRevision = false;
pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
} else {
@@ -1350,8 +815,8 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
if (!pd || !pd->isQObject())
continue;
- QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType);
- const QMetaObject *mo = pc->firstCppMetaObject();
+ QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType());
+ const QMetaObject *mo = pc ? pc->firstCppMetaObject() : 0;
while (mo) {
if (mo == &QQmlComponent::staticMetaObject)
break;
@@ -1361,16 +826,20 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
if (!mo)
continue;
+ // emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}"
QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
Q_ASSERT(componentType);
+ const QString qualifier = QStringLiteral("QmlInternals");
+
+ compiler->addImport(componentType->module(), qualifier, componentType->majorVersion(), componentType->minorVersion());
QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
- syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
+ syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType->elementName()), compiler->registerString(QString()));
syntheticComponent->location = binding->valueLocation;
syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
- QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference;
+ auto typeRef = new QV4::CompiledData::ResolvedTypeReference;
typeRef->type = componentType;
typeRef->majorVersion = componentType->majorVersion();
typeRef->minorVersion = componentType->minorVersion();
@@ -1381,7 +850,6 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
const int componentIndex = qmlObjects->count() - 1;
// Keep property caches symmetric
QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject);
- componentCache->addref();
propertyCaches.append(componentCache);
QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
@@ -1406,14 +874,14 @@ bool QQmlComponentAndAliasResolver::resolve()
const int objCountWithoutSynthesizedComponents = qmlObjects->count();
for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
QmlIR::Object *obj = qmlObjects->at(i);
- QQmlPropertyCache *cache = propertyCaches.at(i).data();
+ QQmlPropertyCache *cache = propertyCaches.at(i);
if (obj->inheritedTypeNameIndex == 0 && !cache)
continue;
bool isExplicitComponent = false;
if (obj->inheritedTypeNameIndex) {
- QQmlCompiledData::TypeReference *tref = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ auto *tref = resolvedTypes->value(obj->inheritedTypeNameIndex);
Q_ASSERT(tref);
if (tref->type && tref->type->metaObject() == &QQmlComponent::staticMetaObject)
isExplicitComponent = true;
@@ -1457,7 +925,6 @@ bool QQmlComponentAndAliasResolver::resolve()
QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
const QmlIR::Binding *rootBinding = component->firstBinding();
- _componentIndex = i;
_idToObjectIndex.clear();
_objectsWithAliases.clear();
@@ -1465,27 +932,27 @@ bool QQmlComponentAndAliasResolver::resolve()
if (!collectIdsAndAliases(rootBinding->value.objectIndex))
return false;
- if (!resolveAliases())
- return false;
-
component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
+
+ if (!resolveAliases(componentRoots.at(i)))
+ return false;
}
// Collect ids and aliases for root
- _componentIndex = -1;
_idToObjectIndex.clear();
_objectsWithAliases.clear();
collectIdsAndAliases(indexOfRootObject);
- resolveAliases();
-
QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject);
rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
+ if (!resolveAliases(indexOfRootObject))
+ return false;
+
// Implicit component insertion may have added objects and thus we also need
// to extend the symmetric propertyCaches.
- compiler->setPropertyCaches(propertyCaches);
+ compiler->setPropertyCaches(std::move(propertyCaches));
compiler->setComponentRoots(componentRoots);
return true;
@@ -1524,139 +991,169 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
return true;
}
-bool QQmlComponentAndAliasResolver::resolveAliases()
+bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
{
- foreach (int objectIndex, _objectsWithAliases) {
- const QmlIR::Object *obj = qmlObjects->at(objectIndex);
+ if (_objectsWithAliases.isEmpty())
+ return true;
+
+ QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler);
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex).data();
- Q_ASSERT(propertyCache);
+ bool atLeastOneAliasResolved;
+ do {
+ atLeastOneAliasResolved = false;
+ QVector<int> pendingObjects;
- int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
- int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
+ for (int objectIndex: qAsConst(_objectsWithAliases)) {
- int aliasIndex = 0;
- for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
- const int idIndex = alias->idIndex;
- const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
- if (targetObjectIndex == -1) {
- recordError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ QQmlCompileError error;
+ const auto result = resolveAliasesInObject(objectIndex, &error);
+
+ if (error.isSet()) {
+ recordError(error);
return false;
}
- Q_ASSERT(!(alias->flags & QV4::CompiledData::Alias::Resolved));
- alias->flags |= QV4::CompiledData::Alias::Resolved;
- const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
- Q_ASSERT(targetObject->id >= 0);
- alias->targetObjectId = targetObject->id;
-
- const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
-
- QStringRef property;
- QStringRef subProperty;
-
- const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
- if (propertySeparator != -1) {
- property = aliasPropertyValue.leftRef(propertySeparator);
- subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
- } else
- property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
-
- int propIdx = -1;
- int type = 0;
- bool writable = false;
- bool resettable = false;
-
- quint32 propertyFlags = QQmlPropertyData::IsAlias;
-
- if (property.isEmpty()) {
- const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
-
- if (typeRef->type)
- type = typeRef->type->typeId();
- else
- type = typeRef->component->metaTypeId;
-
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
- propertyFlags |= QQmlPropertyData::IsQObjectDerived;
+
+ if (result == AllAliasesResolved) {
+ aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
+ atLeastOneAliasResolved = true;
+ } else if (result == SomeAliasesResolved) {
+ atLeastOneAliasResolved = true;
+ pendingObjects.append(objectIndex);
} else {
- QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex).data();
- Q_ASSERT(targetCache);
- QmlIR::PropertyResolver resolver(targetCache);
+ pendingObjects.append(objectIndex);
+ }
+ }
+ qSwap(_objectsWithAliases, pendingObjects);
+ } while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
- QQmlPropertyData *targetProperty = resolver.property(property.toString());
- if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
- recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
- return false;
- }
+ 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)) {
+ recordError(alias->location, tr("Circular alias reference detected"));
+ return false;
+ }
+ }
+ }
- propIdx = targetProperty->coreIndex;
- type = targetProperty->propType;
+ return true;
+}
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
+QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error)
+{
+ const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
+ if (!obj->aliasCount())
+ return AllAliasesResolved;
- if (!subProperty.isEmpty()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(type);
- if (!valueTypeMetaObject) {
- recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- return false;
- }
+ int numResolvedAliases = 0;
+ bool seenUnresolvedAlias = false;
- int valueTypeIndex =
- valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
- if (valueTypeIndex == -1) {
- recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- return false;
- }
- Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
+ for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
+ if (alias->flags & QV4::CompiledData::Alias::Resolved)
+ continue;
- propIdx = QQmlPropertyData::encodeValueTypePropertyIndex(propIdx, valueTypeIndex);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- type = QVariant::Int;
- else
- type = valueTypeMetaObject->property(valueTypeIndex).userType();
+ seenUnresolvedAlias = true;
- } else {
- if (targetProperty->isEnum()) {
- type = QVariant::Int;
- } else {
- // Copy type flags
- propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask;
+ const int idIndex = alias->idIndex;
+ const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
+ if (targetObjectIndex == -1) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ break;
+ }
+
+ const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
+ Q_ASSERT(targetObject->id >= 0);
+ alias->targetObjectId = targetObject->id;
+ alias->aliasToLocalAlias = false;
+
+ const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
- if (targetProperty->isVarProperty())
- propertyFlags |= QQmlPropertyData::IsQVariant;
+ QStringRef property;
+ QStringRef subProperty;
+
+ const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
+ if (propertySeparator != -1) {
+ property = aliasPropertyValue.leftRef(propertySeparator);
+ subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
+ } else
+ property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
- if (targetProperty->isQObject())
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ QQmlPropertyIndex propIdx;
+
+ if (property.isEmpty()) {
+ alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ } else {
+ QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
+ Q_ASSERT(targetCache);
+ QmlIR::PropertyResolver resolver(targetCache);
+
+ QQmlPropertyData *targetProperty = resolver.property(property.toString());
+
+ // If it's an alias that we haven't resolved yet, try again later.
+ if (!targetProperty) {
+ bool aliasPointsToOtherAlias = false;
+ int localAliasIndex = 0;
+ for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
+ if (stringAt(targetAlias->nameIndex) == property) {
+ aliasPointsToOtherAlias = true;
+ break;
}
}
- }
-
- alias->encodedMetaPropertyIndex = propIdx;
+ if (aliasPointsToOtherAlias) {
+ if (targetObjectIndex == objectIndex) {
+ alias->localAliasIndex = localAliasIndex;
+ alias->aliasToLocalAlias = true;
+ alias->flags |= QV4::CompiledData::Alias::Resolved;
+ ++numResolvedAliases;
+ continue;
+ }
- if (!(alias->flags & QV4::CompiledData::Property::IsReadOnly) && writable)
- propertyFlags |= QQmlPropertyData::IsWritable;
- else
- propertyFlags &= ~QQmlPropertyData::IsWritable;
+ // Try again later and resolve the target alias first.
+ _objectsWithAliases.append(objectIndex);
+ // restore
+ alias->idIndex = idIndex;
+ break;
+ }
+ }
- if (resettable)
- propertyFlags |= QQmlPropertyData::IsResettable;
- else
- propertyFlags &= ~QQmlPropertyData::IsResettable;
+ if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
+ break;
+ }
- QString propertyName = stringAt(alias->nameIndex);
+ propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
- if (obj->defaultPropertyIsAlias && aliasIndex == obj->indexOfDefaultPropertyOrAlias)
- propertyCache->_defaultPropertyName = propertyName;
+ if (!subProperty.isEmpty()) {
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType());
+ if (!valueTypeMetaObject) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ break;
+ }
- propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- type, effectiveSignalIndex++);
+ int valueTypeIndex =
+ valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
+ if (valueTypeIndex == -1) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ break;
+ }
+ Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
+ propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
+ } else {
+ if (targetProperty->isQObject())
+ alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ }
}
+
+ alias->encodedMetaPropertyIndex = propIdx.toEncoded();
+ alias->flags |= QV4::CompiledData::Alias::Resolved;
+ numResolvedAliases++;
}
- return true;
+
+ if (numResolvedAliases == 0)
+ return seenUnresolvedAlias ? NoAliasResolved : AllAliasesResolved;
+
+ return SomeAliasesResolved;
}
QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
@@ -1686,7 +1183,7 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
return scanObject(componentBinding->value.objectIndex);
}
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex).data();
+ QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
if (!propertyCache)
return true;
@@ -1778,675 +1275,9 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
return true;
}
-
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , qmlUnit(typeCompiler->qmlUnit())
- , resolvedTypes(*typeCompiler->resolvedTypes())
- , customParsers(typeCompiler->customParserCache())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-}
-
-bool QQmlPropertyValidator::validate()
-{
- _bindingPropertyDataPerObject.resize(qmlUnit->nObjects);
- if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0))
- return false;
- compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject);
- return true;
-}
-
-const QQmlImports &QQmlPropertyValidator::imports() const
-{
- return *compiler->imports();
-}
-
-typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector;
-
-struct BindingFinder
-{
- bool operator()(quint32 name, const QV4::CompiledData::Binding *binding) const
- {
- return name < binding->propertyNameIndex;
- }
- bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const
- {
- return binding->propertyNameIndex < name;
- }
- bool operator()(const QV4::CompiledData::Binding *lhs, const QV4::CompiledData::Binding *rhs) const
- {
- return lhs->propertyNameIndex < rhs->propertyNameIndex;
- }
-};
-
-bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
-{
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
-
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->nBindings == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return validateObject(componentBinding->value.objectIndex, componentBinding);
- }
-
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex).data();
- if (!propertyCache)
- return true;
-
- QStringList deferredPropertyNames;
- {
- const QMetaObject *mo = propertyCache->firstCppMetaObject();
- const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
- if (namesIndex != -1) {
- QMetaClassInfo classInfo = mo->classInfo(namesIndex);
- deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
- }
- }
-
- QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
- QList<const QV4::CompiledData::Binding*> customBindings;
-
- // Collect group properties first for sanity checking
- // vector values are sorted by property name string index.
- GroupPropertyVector groupProperties;
- const QV4::CompiledData::Binding *binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (!binding->isGroupProperty())
- continue;
-
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- continue;
-
- if (populatingValueTypeGroupProperty) {
- recordError(binding->location, tr("Property assignment expected"));
- return false;
- }
-
- GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
- groupProperties.insert(pos, binding);
- }
-
- QmlIR::PropertyResolver propertyResolver(propertyCache);
-
- QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = 0;
- if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
- defaultPropertyName = cache->defaultPropertyName();
- defaultProperty = cache->defaultProperty();
- } else {
- defaultPropertyName = propertyCache->defaultPropertyName();
- defaultProperty = propertyCache->defaultProperty();
- }
-
- QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
-
- binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- QString name = stringAt(binding->propertyNameIndex);
-
- if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- customBindings << binding;
- continue;
- }
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
- && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- customBindings << binding;
- continue;
- }
- }
-
- bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
-
- bool notInRevision = false;
- QQmlPropertyData *pd = 0;
- if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- pd = propertyResolver.signal(name, &notInRevision);
- else
- pd = propertyResolver.property(name, &notInRevision, isGroupProperty ? QmlIR::PropertyResolver::IgnoreRevision : QmlIR::PropertyResolver::CheckRevision);
-
- if (notInRevision) {
- QString typeName = stringAt(obj->inheritedTypeNameIndex);
- QQmlCompiledData::TypeReference *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex);
- if (objectType && objectType->type) {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type->module()).arg(objectType->majorVersion).arg(objectType->minorVersion));
- } else {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
- }
- }
- } else {
- if (isGroupProperty)
- COMPILE_EXCEPTION(binding, tr("Cannot assign a value directly to a grouped property"));
-
- pd = defaultProperty;
- name = defaultPropertyName;
- bindingToDefaultProperty = true;
- }
-
- if (pd)
- collectedBindingPropertyData[i] = pd;
-
- if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
- QQmlType *type = 0;
- QQmlImportNamespace *typeNamespace = 0;
- compiler->imports()->resolveType(stringAt(binding->propertyNameIndex), &type, 0, 0, &typeNamespace);
- if (typeNamespace)
- recordError(binding->location, tr("Invalid use of namespace"));
- else
- recordError(binding->location, tr("Invalid attached object assignment"));
- return false;
- }
-
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
- const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType));
- if (!subObjectValid)
- return false;
- }
-
- // 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)
- continue;
-
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
- recordError(binding->location, tr("Attached properties cannot be used here"));
- return false;
- }
- continue;
- }
-
- if (pd) {
- GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
- const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
-
- if (!pd->isWritable()
- && !pd->isQList()
- && !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
- ) {
-
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
- recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
- else
- recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
- return false;
- }
-
- if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
- QString error;
- if (pd->propType == qMetaTypeId<QQmlScriptString>())
- error = tr( "Cannot assign multiple values to a script property");
- else
- error = tr( "Cannot assign multiple values to a singular property");
- recordError(binding->valueLocation, error);
- return false;
- }
-
- if (!bindingToDefaultProperty
- && !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- && assigningToGroupProperty) {
- QV4::CompiledData::Location loc = binding->valueLocation;
- if (loc < (*assignedGroupProperty)->valueLocation)
- loc = (*assignedGroupProperty)->valueLocation;
-
- if (pd && QQmlValueTypeFactory::isValueType(pd->propType))
- recordError(loc, tr("Property has already been assigned a value"));
- else
- recordError(loc, tr("Cannot assign a value directly to a grouped property"));
- return false;
- }
-
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- if (!validateLiteralBinding(propertyCache, pd, binding))
- return false;
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- if (!validateObjectBinding(pd, name, binding))
- return false;
- } else if (binding->isGroupProperty()) {
- if (QQmlValueTypeFactory::isValueType(pd->propType)) {
- if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType)) {
- if (!pd->isWritable()) {
- recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
- return false;
- }
- } else {
- recordError(binding->location, tr("Invalid grouped property access"));
- return false;
- }
- } else {
- if (!enginePrivate->propertyCacheForType(pd->propType)) {
- recordError(binding->location, tr("Invalid grouped property access"));
- return false;
- }
- }
- }
- } else {
- if (customParser) {
- customBindings << binding;
- continue;
- }
- if (bindingToDefaultProperty) {
- COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property"));
- } else {
- COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
- }
- }
- }
-
- if (obj->idNameIndex) {
- bool notInRevision = false;
- collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
- }
-
- if (customParser && !customBindings.isEmpty()) {
- customParser->clearErrors();
- customParser->validator = this;
- customParser->engine = enginePrivate;
- customParser->imports = compiler->imports();
- customParser->verifyBindings(qmlUnit, customBindings);
- customParser->validator = 0;
- customParser->engine = 0;
- customParser->imports = (QQmlImports*)0;
- const QList<QQmlError> parserErrors = customParser->errors();
- if (!parserErrors.isEmpty()) {
- foreach (const QQmlError &error, parserErrors)
- compiler->recordError(error);
- return false;
- }
- }
-
- _bindingPropertyDataPerObject[objectIndex] = collectedBindingPropertyData;
-
- return true;
-}
-
-bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
-{
- if (property->isQList()) {
- recordError(binding->valueLocation, tr("Cannot assign primitives to lists"));
- return false;
- }
-
- if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
- return true;
-
- QString value = binding->valueAsString(qmlUnit);
- QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex);
- bool ok;
- if (p.isFlagType()) {
- p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
- } else
- p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
-
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
- return false;
- }
- return true;
- }
-
- switch (property->propType) {
- case QMetaType::QVariant:
- break;
- case QVariant::String: {
- if (!binding->evaluatesToString()) {
- recordError(binding->valueLocation, tr("Invalid property assignment: string expected"));
- return false;
- }
- }
- break;
- case QVariant::StringList: {
- if (!binding->evaluatesToString()) {
- recordError(binding->valueLocation, tr("Invalid property assignment: string or string list expected"));
- return false;
- }
- }
- break;
- case QVariant::ByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- recordError(binding->valueLocation, tr("Invalid property assignment: byte array expected"));
- return false;
- }
- }
- break;
- case QVariant::Url: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- recordError(binding->valueLocation, tr("Invalid property assignment: url expected"));
- return false;
- }
- }
- break;
- case QVariant::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = binding->valueAsNumber();
- if (double(uint(d)) == d)
- return true;
- }
- recordError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected"));
- return false;
- }
- break;
- case QVariant::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = binding->valueAsNumber();
- if (double(int(d)) == d)
- return true;
- }
- recordError(binding->valueLocation, tr("Invalid property assignment: int expected"));
- return false;
- }
- break;
- case QMetaType::Float: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- recordError(binding->valueLocation, tr("Invalid property assignment: number expected"));
- return false;
- }
- }
- break;
- case QVariant::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- recordError(binding->valueLocation, tr("Invalid property assignment: number expected"));
- return false;
- }
- }
- break;
- case QVariant::Color: {
- bool ok = false;
- QQmlStringConverters::rgbaFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: color expected"));
- return false;
- }
- }
- break;
-#ifndef QT_NO_DATESTRING
- case QVariant::Date: {
- bool ok = false;
- QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: date expected"));
- return false;
- }
- }
- break;
- case QVariant::Time: {
- bool ok = false;
- QQmlStringConverters::timeFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: time expected"));
- return false;
- }
- }
- break;
- case QVariant::DateTime: {
- bool ok = false;
- QQmlStringConverters::dateTimeFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: datetime expected"));
- return false;
- }
- }
- break;
-#endif // QT_NO_DATESTRING
- case QVariant::Point: {
- bool ok = false;
- QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
- return false;
- }
- }
- break;
- case QVariant::PointF: {
- bool ok = false;
- QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
- return false;
- }
- }
- break;
- case QVariant::Size: {
- bool ok = false;
- QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
- return false;
- }
- }
- break;
- case QVariant::SizeF: {
- bool ok = false;
- QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
- return false;
- }
- }
- break;
- case QVariant::Rect: {
- bool ok = false;
- QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: rect expected"));
- return false;
- }
- }
- break;
- case QVariant::RectF: {
- bool ok = false;
- QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok);
- if (!ok) {
- recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
- return false;
- }
- }
- break;
- case QVariant::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
- recordError(binding->valueLocation, tr("Invalid property assignment: boolean expected"));
- return false;
- }
- }
- break;
- case QVariant::Vector3D: {
- struct {
- float xp;
- float yp;
- float zy;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
- recordError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected"));
- return false;
- }
- }
- break;
- case QVariant::Vector4D: {
- struct {
- float xp;
- float yp;
- float zy;
- float wp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) {
- recordError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected"));
- return false;
- }
- }
- break;
- case QVariant::RegExp:
- recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
- return false;
- 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) {
- recordError(binding->valueLocation, tr("Invalid property assignment: number or array of numbers expected"));
- return false;
- }
- break;
- } else if (property->propType == qMetaTypeId<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
- if (ok) {
- double n = binding->valueAsNumber();
- if (double(int(n)) != n)
- ok = false;
- }
- if (!ok)
- recordError(binding->valueLocation, 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) {
- recordError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected"));
- return false;
- }
- break;
- } else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- recordError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected"));
- return false;
- }
- break;
- } else if (property->propType == qMetaTypeId<QList<QString> >()) {
- if (!binding->evaluatesToString()) {
- recordError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected"));
- return false;
- }
- break;
- } else if (property->propType == qMetaTypeId<QJSValue>()) {
- break;
- } else if (property->propType == qMetaTypeId<QQmlScriptString>()) {
- break;
- }
-
- // otherwise, try a custom type assignment
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType);
- if (!converter) {
- recordError(binding->valueLocation, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType))));
- return false;
- }
- }
- break;
- }
- return true;
-}
-
-/*!
- Returns true if from can be assigned to a (QObject) property of type
- to.
-*/
-bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
-{
- QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
-
- while (fromMo) {
- if (fromMo == toMo)
- return true;
- fromMo = fromMo->parent();
- }
- return false;
-}
-
-bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
-{
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
-
- bool isValueSource = false;
- bool isPropertyInterceptor = false;
-
- QQmlType *qmlType = 0;
- const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(binding->value.objectIndex);
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex);
- if (typeRef) {
- QQmlPropertyCache *cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- const QMetaObject *mo = cache->firstCppMetaObject();
- while (mo && !qmlType) {
- qmlType = QQmlMetaType::qmlType(mo);
- mo = mo->superClass();
- }
- Q_ASSERT(qmlType);
- }
-
- if (qmlType) {
- isValueSource = qmlType->propertyValueSourceCast() != -1;
- isPropertyInterceptor = qmlType->propertyValueInterceptorCast() != -1;
- }
-
- if (!isValueSource && !isPropertyInterceptor) {
- recordError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
- return false;
- }
-
- return true;
- }
-
- if (QQmlMetaType::isInterface(property->propType)) {
- // Can only check at instantiation time if the created sub-object successfully casts to the
- // target interface.
- return true;
- } else if (property->propType == QMetaType::QVariant) {
- // We can convert everything to QVariant :)
- return true;
- } else if (property->isQList()) {
- const int listType = enginePrivate->listType(property->propType);
- if (!QQmlMetaType::isInterface(listType)) {
- QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex).data();
- if (!canCoerce(listType, source)) {
- recordError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
- return false;
- }
- }
- return true;
- } else if (qmlUnit->objectAt(binding->value.objectIndex)->flags & QV4::CompiledData::Object::IsComponent) {
- return true;
- } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
- return true;
- } else if (QQmlValueTypeFactory::isValueType(property->propType)) {
- recordError(binding->location, tr("Unexpected object assignment"));
- return false;
- } else if (property->propType == qMetaTypeId<QQmlScriptString>()) {
- recordError(binding->valueLocation, tr("Invalid property assignment: script expected"));
- return false;
- } else {
- // We want to raw metaObject here as the raw metaobject is the
- // actual property type before we applied any extensions that might
- // effect the properties on the type, but don't effect assignability
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType);
-
- // Will be true if the assgned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
- if (propertyMetaObject) {
- QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex).data();
- while (c && !isAssignable) {
- isAssignable |= c == propertyMetaObject;
- c = c->parent();
- }
- }
-
- if (!isAssignable) {
- recordError(binding->valueLocation, tr("Cannot assign object to property"));
- return false;
- }
- }
- return true;
-}
-
QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
: QQmlCompilePass(typeCompiler)
- , resolvedTypes(*typeCompiler->resolvedTypes())
+ , resolvedTypes(typeCompiler->resolvedTypes)
, customParsers(typeCompiler->customParserCache())
, qmlObjects(*typeCompiler->qmlObjects())
, propertyCaches(typeCompiler->propertyCaches())
@@ -2483,15 +1314,15 @@ bool QQmlJSCodeGenerator::compileComponent(int contextObject)
const QmlIR::Object *obj = qmlObjects.at(objectIndex);
m.name = stringAt(obj->idNameIndex);
m.idIndex = obj->id;
- m.type = propertyCaches.at(objectIndex).data();
+ m.type = propertyCaches->at(objectIndex);
- QQmlCompiledData::TypeReference *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ auto *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
if (tref && tref->isFullyDynamicType)
m.type = 0;
idMapping << m;
}
- v4CodeGen->beginContextScope(idMapping, propertyCaches.at(contextObject).data());
+ v4CodeGen->beginContextScope(idMapping, propertyCaches->at(contextObject));
if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
return false;
@@ -2506,7 +1337,7 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
return true;
if (object->functionsAndExpressions->count > 0) {
- QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex).data();
+ QQmlPropertyCache *scopeObject = propertyCaches->at(scopeObjectIndex);
v4CodeGen->beginObjectScope(scopeObject);
QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
@@ -2517,9 +1348,9 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
functionsToCompile << *foe;
}
const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
- QList<QQmlError> jsErrors = v4CodeGen->qmlErrors();
+ const QList<QQmlError> jsErrors = v4CodeGen->qmlErrors();
if (!jsErrors.isEmpty()) {
- foreach (const QQmlError &e, jsErrors)
+ for (const QQmlError &e : jsErrors)
compiler->recordError(e);
return false;
}
@@ -2558,7 +1389,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties()
void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
{
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex).data();
+ QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
if (!propertyCache)
return;
@@ -2571,7 +1402,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
QmlIR::Binding *previousBinding = 0;
QmlIR::Binding *binding = object->firstBinding();
while (binding) {
- if (binding->propertyNameIndex == 0 || stringAt(binding->propertyNameIndex) != defaultProperty) {
+ if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
previousBinding = binding;
binding = binding->next;
continue;
@@ -2735,7 +1566,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR:
for (QV4::IR::BasicBlock *bb : function->basicBlocks()) {
for (QV4::IR::Stmt *s : bb->statements()) {
- s->accept(this);
+ visit(s);
if (!_canSimplify)
return false;
}
@@ -2902,23 +1733,44 @@ void QQmlIRFunctionCleanser::clean()
module->functions = newFunctions;
- foreach (QV4::IR::Function *function, module->functions) {
+ for (QV4::IR::Function *function : qAsConst(module->functions)) {
for (QV4::IR::BasicBlock *block : function->basicBlocks()) {
for (QV4::IR::Stmt *s : block->statements()) {
- s->accept(this);
+ visit(s);
}
}
}
- foreach (QmlIR::Object *obj, *compiler->qmlObjects()) {
+ for (QmlIR::Object *obj : qAsConst(*compiler->qmlObjects())) {
for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i)
obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)];
}
}
-void QQmlIRFunctionCleanser::visitClosure(QV4::IR::Closure *closure)
+void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s)
+{
+
+ switch (s->stmtKind) {
+ case QV4::IR::Stmt::PhiStmt:
+ // nothing to do
+ break;
+ default:
+ STMT_VISIT_ALL_KINDS(s);
+ break;
+ }
+}
+
+void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e)
{
- closure->value = newFunctionIndices.at(closure->value);
+ switch (e->exprKind) {
+ case QV4::IR::Expr::ClosureExpr: {
+ auto closure = e->asClosure();
+ closure->value = newFunctionIndices.at(closure->value);
+ } break;
+ default:
+ EXPR_VISIT_ALL_KINDS(e);
+ break;
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 5abfc7c18d..6ad6ad8557 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -53,13 +53,12 @@
#include <qglobal.h>
#include <qqmlerror.h>
#include <qhash.h>
-#include <private/qqmlcompiler_p.h>
+#include <private/qqmltypeloader_p.h>
#include <private/qqmlirbuilder_p.h>
QT_BEGIN_NAMESPACE
class QQmlEnginePrivate;
-class QQmlCompiledData;
class QQmlError;
class QQmlTypeData;
class QQmlImports;
@@ -75,18 +74,40 @@ struct Location;
}
}
+struct QQmlCompileError
+{
+ QQmlCompileError() {}
+ QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description)
+ : location(location), description(description) {}
+ QV4::CompiledData::Location location;
+ QString description;
+
+ bool isSet() const { return !description.isEmpty(); }
+};
+
struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QmlIR::Document *document);
+ QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+
+ // --- interface used by QQmlPropertyCacheCreator
+ typedef QmlIR::Object CompiledObject;
+ const QmlIR::Object *objectAt(int index) const { return document->objects.at(index); }
+ int objectCount() const { return document->objects.count(); }
+ QString stringAt(int idx) const;
+ QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); }
+ QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); }
+ QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypes;
+ // ---
- bool compile();
+ QV4::CompiledData::CompilationUnit *compile();
QList<QQmlError> compilationErrors() const { return errors; }
- void recordError(const QQmlError &error);
+ void recordError(QQmlError error);
+ void recordError(const QV4::CompiledData::Location &location, const QString &description);
+ void recordError(const QQmlCompileError &error);
- QString stringAt(int idx) const;
int registerString(const QString &str);
QV4::IR::Module *jsIRModule() const;
@@ -96,11 +117,11 @@ public:
QUrl url() const { return typeData->finalUrl(); }
QQmlEnginePrivate *enginePrivate() const { return engine; }
const QQmlImports *imports() const;
- QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes();
- QList<QmlIR::Object*> *qmlObjects();
+ QVector<QmlIR::Object *> *qmlObjects() const;
int rootObjectIndex() const;
- void setPropertyCaches(const QQmlPropertyCacheVector &caches);
- const QQmlPropertyCacheVector &propertyCaches() const;
+ void setPropertyCaches(QQmlPropertyCacheVector &&caches);
+ const QQmlPropertyCacheVector *propertyCaches() const;
+ QQmlPropertyCacheVector &&takePropertyCaches();
void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
const QVector<quint32> &componentRoots() const { return m_componentRoots; }
QQmlJS::MemoryPool *memoryPool();
@@ -112,10 +133,11 @@ public:
QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const;
+ void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion);
+
private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
- QQmlCompiledData *compiledData;
QQmlTypeData *typeData;
QQmlRefPointer<QQmlTypeNameCache> importCache;
QmlIR::Document *document;
@@ -129,37 +151,18 @@ private:
struct QQmlCompilePass
{
- virtual ~QQmlCompilePass() {}
-
QQmlCompilePass(QQmlTypeCompiler *typeCompiler);
QString stringAt(int idx) const { return compiler->stringAt(idx); }
protected:
- void recordError(const QV4::CompiledData::Location &location, const QString &description) const;
+ void recordError(const QV4::CompiledData::Location &location, const QString &description) const
+ { compiler->recordError(location, description); }
+ void recordError(const QQmlCompileError &error)
+ { compiler->recordError(error); }
QQmlTypeCompiler *compiler;
};
-class QQmlPropertyCacheCreator : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreator)
-public:
- QQmlPropertyCacheCreator(QQmlTypeCompiler *typeCompiler);
- ~QQmlPropertyCacheCreator();
-
- bool buildMetaObjects();
-protected:
- bool buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding);
- bool ensureVMEMetaObject(int objectIndex);
- bool createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache);
-
- QQmlEnginePrivate *enginePrivate;
- const QList<QmlIR::Object*> &qmlObjects;
- const QQmlImports *imports;
- QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
- QQmlPropertyCacheVector propertyCaches;
-};
-
// "Converts" signal expressions to full-fleged function declarations with
// parameters taken from the signal declarations
// It also updates the QV4::CompiledData::Binding objects to set the property name
@@ -176,12 +179,12 @@ private:
bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
QQmlEnginePrivate *enginePrivate;
- const QList<QmlIR::Object*> &qmlObjects;
+ const QVector<QmlIR::Object*> &qmlObjects;
const QQmlImports *imports;
const QHash<int, QQmlCustomParser*> &customParsers;
- const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
const QSet<QString> &illegalNames;
- const QQmlPropertyCacheVector &propertyCaches;
+ const QQmlPropertyCacheVector * const propertyCaches;
};
// ### This will go away when the codegen resolves all enums to constant expressions
@@ -207,10 +210,10 @@ private:
int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const;
- const QList<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
const QQmlImports *imports;
- QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes;
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes;
};
class QQmlCustomParserScriptIndexer: public QQmlCompilePass
@@ -223,7 +226,7 @@ public:
private:
void scanObjectRecursively(int objectIndex, bool annotateScriptBindings = false);
- const QList<QmlIR::Object*> &qmlObjects;
+ const QVector<QmlIR::Object*> &qmlObjects;
const QHash<int, QQmlCustomParser*> &customParsers;
};
@@ -235,8 +238,8 @@ public:
void annotateBindingsToAliases();
private:
- const QList<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
};
class QQmlScriptStringScanner : public QQmlCompilePass
@@ -247,8 +250,8 @@ public:
void scan();
private:
- const QList<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
};
class QQmlComponentAndAliasResolver : public QQmlCompilePass
@@ -262,22 +265,30 @@ public:
protected:
void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache);
bool collectIdsAndAliases(int objectIndex);
- bool resolveAliases();
+ bool resolveAliases(int componentIndex);
+ void propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags);
+
+ enum AliasResolutionResult {
+ NoAliasResolved,
+ SomeAliasesResolved,
+ AllAliasesResolved
+ };
+
+ AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error);
QQmlEnginePrivate *enginePrivate;
QQmlJS::MemoryPool *pool;
- QList<QmlIR::Object*> *qmlObjects;
+ QVector<QmlIR::Object*> *qmlObjects;
const int indexOfRootObject;
// indices of the objects that are actually Component {}
QVector<quint32> componentRoots;
- int _componentIndex;
QHash<int, int> _idToObjectIndex;
- QList<int> _objectsWithAliases;
+ QVector<int> _objectsWithAliases;
- QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes;
QQmlPropertyCacheVector propertyCaches;
};
@@ -291,41 +302,13 @@ public:
private:
bool scanObject(int objectIndex);
- QList<QmlIR::Object*> *qmlObjects;
- QQmlPropertyCacheVector propertyCaches;
+ QVector<QmlIR::Object*> *qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
const QHash<int, QQmlCustomParser*> &customParsers;
bool _seenObjectWithId;
};
-class QQmlPropertyValidator : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
-public:
- QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler);
-
- bool validate();
-
- const QQmlImports &imports() const;
- QQmlEnginePrivate *engine() const { return enginePrivate; }
-
-private:
- bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const;
- bool validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
- bool validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
-
- bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
-
- QQmlEnginePrivate *enginePrivate;
- const QV4::CompiledData::Unit *qmlUnit;
- const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
- const QHash<int, QQmlCustomParser*> &customParsers;
- const QQmlPropertyCacheVector &propertyCaches;
-
- // collected state variables, essentially write-only
- mutable QVector<QV4::CompiledData::BindingPropertyData> _bindingPropertyDataPerObject;
-};
-
// ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone.
class QQmlJSCodeGenerator : public QQmlCompilePass
{
@@ -338,10 +321,10 @@ private:
bool compileComponent(int componentRoot);
bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
- const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
const QHash<int, QQmlCustomParser*> &customParsers;
- const QList<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector &propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
QmlIR::JSCodeGen * const v4CodeGen;
};
@@ -355,11 +338,11 @@ public:
private:
void mergeDefaultProperties(int objectIndex);
- const QList<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector &propertyCaches;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QQmlPropertyCacheVector * const propertyCaches;
};
-class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass, public QV4::IR::StmtVisitor
+class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass
{
public:
QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler);
@@ -369,12 +352,30 @@ public:
private:
void reduceTranslationBindings(int objectIndex);
- virtual void visitMove(QV4::IR::Move *move);
- virtual void visitJump(QV4::IR::Jump *) {}
- virtual void visitCJump(QV4::IR::CJump *) { discard(); }
- virtual void visitExp(QV4::IR::Exp *) { discard(); }
- virtual void visitPhi(QV4::IR::Phi *) {}
- virtual void visitRet(QV4::IR::Ret *ret);
+ void visit(QV4::IR::Stmt *s)
+ {
+ switch (s->stmtKind) {
+ case QV4::IR::Stmt::MoveStmt:
+ visitMove(s->asMove());
+ break;
+ case QV4::IR::Stmt::RetStmt:
+ visitRet(s->asRet());
+ break;
+ case QV4::IR::Stmt::CJumpStmt:
+ discard();
+ break;
+ case QV4::IR::Stmt::ExpStmt:
+ discard();
+ break;
+ case QV4::IR::Stmt::JumpStmt:
+ break;
+ case QV4::IR::Stmt::PhiStmt:
+ break;
+ }
+ }
+
+ void visitMove(QV4::IR::Move *move);
+ void visitRet(QV4::IR::Ret *ret);
void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target);
@@ -383,7 +384,7 @@ private:
bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding);
bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding);
- const QList<QmlIR::Object*> &qmlObjects;
+ const QVector<QmlIR::Object*> &qmlObjects;
QV4::IR::Module *jsModule;
bool _canSimplify;
@@ -398,8 +399,7 @@ private:
QVector<int> irFunctionsToRemove;
};
-class QQmlIRFunctionCleanser : public QQmlCompilePass, public QV4::IR::StmtVisitor,
- public QV4::IR::ExprVisitor
+class QQmlIRFunctionCleanser : public QQmlCompilePass
{
public:
QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector<int> &functionsToRemove);
@@ -407,51 +407,13 @@ public:
void clean();
private:
- virtual void visitClosure(QV4::IR::Closure *closure);
-
- virtual void visitTemp(QV4::IR::Temp *) {}
- virtual void visitArgLocal(QV4::IR::ArgLocal *) {}
-
virtual void visitMove(QV4::IR::Move *s) {
- s->source->accept(this);
- s->target->accept(this);
- }
-
- virtual void visitConvert(QV4::IR::Convert *e) { e->expr->accept(this); }
- virtual void visitPhi(QV4::IR::Phi *) { }
-
- virtual void visitExp(QV4::IR::Exp *s) { s->expr->accept(this); }
-
- virtual void visitJump(QV4::IR::Jump *) {}
- virtual void visitCJump(QV4::IR::CJump *s) { s->cond->accept(this); }
- virtual void visitRet(QV4::IR::Ret *s) { s->expr->accept(this); }
-
- virtual void visitConst(QV4::IR::Const *) {}
- virtual void visitString(QV4::IR::String *) {}
- virtual void visitRegExp(QV4::IR::RegExp *) {}
- virtual void visitName(QV4::IR::Name *) {}
- virtual void visitUnop(QV4::IR::Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(QV4::IR::Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(QV4::IR::Call *e) {
- e->base->accept(this);
- for (QV4::IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
+ visit(s->source);
+ visit(s->target);
}
- virtual void visitNew(QV4::IR::New *e) {
- e->base->accept(this);
- for (QV4::IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitSubscript(QV4::IR::Subscript *e) {
- e->base->accept(this);
- e->index->accept(this);
- }
-
- virtual void visitMember(QV4::IR::Member *e) {
- e->base->accept(this);
- }
+ void visit(QV4::IR::Stmt *s);
+ void visit(QV4::IR::Expr *e);
private:
QV4::IR::Module *module;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index d08d2aafa2..e0def1021b 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1058,6 +1058,8 @@ bool Codegen::visit(ArrayLiteral *ast)
current->expr = _block->CONST(IR::MissingType, 0);
}
Result expr = expression(it->expression);
+ if (hasError)
+ return false;
IR::ExprList *arg = _function->New<IR::ExprList>();
if (!current) {
@@ -1100,6 +1102,8 @@ bool Codegen::visit(ArrayMemberExpression *ast)
Result base = expression(ast->base);
Result index = expression(ast->expression);
+ if (hasError)
+ return false;
_expr.code = subscript(*base, *index);
return false;
}
@@ -1139,10 +1143,16 @@ bool Codegen::visit(BinaryExpression *ast)
const unsigned r = _block->newTemp();
- move(_block->TEMP(r), *expression(ast->left));
+ Result lhs = expression(ast->left);
+ if (hasError)
+ return false;
+ move(_block->TEMP(r), *lhs);
setLocation(cjump(_block->TEMP(r), iftrue, endif), ast->operatorToken);
_block = iftrue;
- move(_block->TEMP(r), *expression(ast->right));
+ Result rhs = expression(ast->right);
+ if (hasError)
+ return false;
+ move(_block->TEMP(r), *rhs);
_block->JUMP(endif);
_expr.code = _block->TEMP(r);
@@ -1160,10 +1170,16 @@ bool Codegen::visit(BinaryExpression *ast)
IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler());
const unsigned r = _block->newTemp();
- move(_block->TEMP(r), *expression(ast->left));
+ Result lhs = expression(ast->left);
+ if (hasError)
+ return false;
+ move(_block->TEMP(r), *lhs);
setLocation(cjump(_block->TEMP(r), endif, iffalse), ast->operatorToken);
_block = iffalse;
- move(_block->TEMP(r), *expression(ast->right));
+ Result rhs = expression(ast->right);
+ if (hasError)
+ return false;
+ move(_block->TEMP(r), *rhs);
_block->JUMP(endif);
_block = endif;
@@ -1173,6 +1189,8 @@ bool Codegen::visit(BinaryExpression *ast)
}
IR::Expr* left = *expression(ast->left);
+ if (hasError)
+ return false;
switch (ast->op) {
case QSOperator::Or:
@@ -1182,17 +1200,19 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::Assign: {
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
return false;
- IR::Expr* right = *expression(ast->right);
+ Result right = expression(ast->right);
+ if (hasError)
+ return false;
if (!left->isLValue()) {
throwReferenceError(ast->operatorToken, QStringLiteral("left-hand side of assignment operator is not an lvalue"));
return false;
}
if (_expr.accept(nx)) {
- move(left, right);
+ move(left, *right);
} else {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), right);
+ move(_block->TEMP(t), *right);
move(left, _block->TEMP(t));
_expr.code = _block->TEMP(t);
}
@@ -1212,17 +1232,19 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::InplaceXor: {
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
return false;
- IR::Expr* right = *expression(ast->right);
+ Result right = expression(ast->right);
+ if (hasError)
+ return false;
if (!left->isLValue()) {
throwSyntaxError(ast->operatorToken, QStringLiteral("left-hand side of inplace operator is not an lvalue"));
return false;
}
if (_expr.accept(nx)) {
- move(left, right, baseOp(ast->op));
+ move(left, *right, baseOp(ast->op));
} else {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), right);
+ move(_block->TEMP(t), *right);
move(left, _block->TEMP(t), baseOp(ast->op));
_expr.code = left;
}
@@ -1245,12 +1267,14 @@ bool Codegen::visit(BinaryExpression *ast)
left = _block->TEMP(t);
}
- IR::Expr* right = *expression(ast->right);
+ Result right = expression(ast->right);
+ if (hasError)
+ return false;
if (_expr.accept(cx)) {
- setLocation(cjump(binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken);
+ setLocation(cjump(binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken);
} else {
- IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken);
+ IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken);
if (e->asConst() || e->asString())
_expr.code = e;
else {
@@ -1279,9 +1303,11 @@ bool Codegen::visit(BinaryExpression *ast)
left = _block->TEMP(t);
}
- IR::Expr* right = *expression(ast->right);
+ Result right = expression(ast->right);
+ if (hasError)
+ return false;
- IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken);
+ IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken);
if (e->asConst() || e->asString())
_expr.code = e;
else {
@@ -1306,11 +1332,15 @@ bool Codegen::visit(CallExpression *ast)
IR::ExprList *args = 0, **args_it = &args;
for (ArgumentList *it = ast->arguments; it; it = it->next) {
Result arg = expression(it->expression);
+ if (hasError)
+ return false;
IR::Expr *actual = argument(*arg);
*args_it = _function->New<IR::ExprList>();
(*args_it)->init(actual);
args_it = &(*args_it)->next;
}
+ if (hasError)
+ return false;
_expr.code = call(*base, args);
return false;
}
@@ -1329,11 +1359,17 @@ bool Codegen::visit(ConditionalExpression *ast)
condition(ast->expression, iftrue, iffalse);
_block = iftrue;
- move(_block->TEMP(t), *expression(ast->ok));
+ Result ok = expression(ast->ok);
+ if (hasError)
+ return false;
+ move(_block->TEMP(t), *ok);
_block->JUMP(endif);
_block = iffalse;
- move(_block->TEMP(t), *expression(ast->ko));
+ Result ko = expression(ast->ko);
+ if (hasError)
+ return false;
+ move(_block->TEMP(t), *ko);
_block->JUMP(endif);
_block = endif;
@@ -1349,6 +1385,8 @@ bool Codegen::visit(DeleteExpression *ast)
return false;
IR::Expr* expr = *expression(ast->expression);
+ if (hasError)
+ return false;
// Temporaries cannot be deleted
IR::ArgLocal *al = expr->asArgLocal();
if (al && al->index < static_cast<unsigned>(_env->members.size())) {
@@ -1410,7 +1448,8 @@ bool Codegen::visit(FieldMemberExpression *ast)
return false;
Result base = expression(ast->base);
- _expr.code = member(*base, _function->newString(ast->name.toString()));
+ if (!hasError)
+ _expr.code = member(*base, _function->newString(ast->name.toString()));
return false;
}
@@ -1501,6 +1540,8 @@ bool Codegen::visit(NewExpression *ast)
return false;
Result base = expression(ast->expression);
+ if (hasError)
+ return false;
IR::Expr *expr = *base;
if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) {
const unsigned t = _block->newTemp();
@@ -1517,6 +1558,8 @@ bool Codegen::visit(NewMemberExpression *ast)
return false;
Result base = expression(ast->base);
+ if (hasError)
+ return false;
IR::Expr *expr = *base;
if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) {
const unsigned t = _block->newTemp();
@@ -1527,6 +1570,8 @@ bool Codegen::visit(NewMemberExpression *ast)
IR::ExprList *args = 0, **args_it = &args;
for (ArgumentList *it = ast->arguments; it; it = it->next) {
Result arg = expression(it->expression);
+ if (hasError)
+ return false;
IR::Expr *actual = argument(*arg);
*args_it = _function->New<IR::ExprList>();
(*args_it)->init(actual);
@@ -1544,6 +1589,8 @@ bool Codegen::visit(NotExpression *ast)
return false;
Result expr = expression(ast->expression);
+ if (hasError)
+ return false;
const unsigned r = _block->newTemp();
setLocation(move(_block->TEMP(r), unop(IR::OpNot, *expr, ast->notToken)), ast->notToken);
_expr.code = _block->TEMP(r);
@@ -1601,6 +1648,8 @@ bool Codegen::visit(ObjectLiteral *ast)
QString name = it->assignment->name->asString();
if (PropertyNameAndValue *nv = AST::cast<AST::PropertyNameAndValue *>(it->assignment)) {
Result value = expression(nv->value);
+ if (hasError)
+ return false;
ObjectPropertyValue &v = valueMap[name];
if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value)) {
throwSyntaxError(nv->lastSourceLocation(),
@@ -1731,6 +1780,8 @@ bool Codegen::visit(PostDecrementExpression *ast)
return false;
Result expr = expression(ast->base);
+ if (hasError)
+ return false;
if (!expr->isLValue()) {
throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
return false;
@@ -1757,6 +1808,8 @@ bool Codegen::visit(PostIncrementExpression *ast)
return false;
Result expr = expression(ast->base);
+ if (hasError)
+ return false;
if (!expr->isLValue()) {
throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
return false;
@@ -1783,6 +1836,8 @@ bool Codegen::visit(PreDecrementExpression *ast)
return false;
Result expr = expression(ast->expression);
+ if (hasError)
+ return false;
if (!expr->isLValue()) {
throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
return false;
@@ -1808,6 +1863,8 @@ bool Codegen::visit(PreIncrementExpression *ast)
return false;
Result expr = expression(ast->expression);
+ if (hasError)
+ return false;
if (!expr->isLValue()) {
throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
return false;
@@ -1860,6 +1917,8 @@ bool Codegen::visit(TildeExpression *ast)
return false;
Result expr = expression(ast->expression);
+ if (hasError)
+ return false;
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), unop(IR::OpCompl, *expr, ast->tildeToken)), ast->tildeToken);
_expr.code = _block->TEMP(t);
@@ -1885,6 +1944,8 @@ bool Codegen::visit(TypeOfExpression *ast)
return false;
Result expr = expression(ast->expression);
+ if (hasError)
+ return false;
IR::ExprList *args = _function->New<IR::ExprList>();
args->init(reference(*expr));
_expr.code = call(_block->NAME(IR::Name::builtin_typeof, ast->typeofToken.startLine, ast->typeofToken.startColumn), args);
@@ -1897,6 +1958,8 @@ bool Codegen::visit(UnaryMinusExpression *ast)
return false;
Result expr = expression(ast->expression);
+ if (hasError)
+ return false;
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), unop(IR::OpUMinus, *expr, ast->minusToken)), ast->minusToken);
_expr.code = _block->TEMP(t);
@@ -1909,6 +1972,8 @@ bool Codegen::visit(UnaryPlusExpression *ast)
return false;
Result expr = expression(ast->expression);
+ if (hasError)
+ return false;
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), unop(IR::OpUPlus, *expr, ast->plusToken)), ast->plusToken);
_expr.code = _block->TEMP(t);
@@ -1961,6 +2026,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
function->isStrict = _env->isStrict;
function->isNamedExpression = _env->isNamedFunctionExpression;
+ function->isQmlBinding = _env->compilationMode == QmlBinding;
AST::SourceLocation loc = ast->firstSourceLocation();
function->line = loc.startLine;
@@ -1981,7 +2047,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
}
} else {
if (!_env->isStrict) {
- foreach (const QString &inheritedLocal, inheritedLocals) {
+ for (const QString &inheritedLocal : qAsConst(inheritedLocals)) {
function->LOCAL(inheritedLocal);
unsigned tempIndex = entryBlock->newTemp();
Environment::Member member = { Environment::UndefinedMember,
@@ -2023,7 +2089,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_function->RECEIVE(it->name.toString());
}
- foreach (const Environment::Member &member, _env->members) {
+ for (const Environment::Member &member : qAsConst(_env->members)) {
if (member.function) {
const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
member.function->body ? member.function->body->elements : 0);
@@ -2223,7 +2289,10 @@ bool Codegen::visit(ForEachStatement *ast)
IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler());
int objectToIterateOn = _block->newTemp();
- move(_block->TEMP(objectToIterateOn), *expression(ast->expression));
+ Result expr = expression(ast->expression);
+ if (hasError)
+ return false;
+ move(_block->TEMP(objectToIterateOn), *expr);
IR::ExprList *args = _function->New<IR::ExprList>();
args->init(_block->TEMP(objectToIterateOn));
@@ -2235,7 +2304,10 @@ bool Codegen::visit(ForEachStatement *ast)
_block = foreachbody;
int temp = _block->newTemp();
- move(*expression(ast->initialiser), _block->TEMP(temp));
+ Result init = expression(ast->initialiser);
+ if (hasError)
+ return false;
+ move(*init, _block->TEMP(temp));
statement(ast->statement);
_block->JUMP(foreachin);
@@ -2441,6 +2513,13 @@ bool Codegen::visit(ReturnStatement *ast)
Result expr = expression(ast->expression);
move(_block->TEMP(_returnAddress), *expr);
}
+
+ // Since we're leaving, don't let any finally statements we emit as part of the unwinding
+ // jump to exception handlers at run-time if they throw.
+ IR::BasicBlock *unwindBlock = _function->newBasicBlock(/*no exception handler*/Q_NULLPTR);
+ _block->JUMP(unwindBlock);
+ _block = unwindBlock;
+
unwindException(0);
_block->JUMP(_exitBlock);
@@ -2724,6 +2803,12 @@ bool Codegen::visit(WithStatement *ast)
_function->hasWith = true;
+ const int withObject = _block->newTemp();
+ Result src = expression(ast->expression);
+ if (hasError)
+ return false;
+ _block->MOVE(_block->TEMP(withObject), *src);
+
// need an exception handler for with to cleanup the with scope
IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(exceptionHandler());
withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(IR::Name::builtin_pop_scope, 0, 0), 0));
@@ -2738,8 +2823,6 @@ bool Codegen::visit(WithStatement *ast)
_block->JUMP(withBlock);
_block = withBlock;
- int withObject = _block->newTemp();
- _block->MOVE(_block->TEMP(withObject), *expression(ast->expression));
IR::ExprList *args = _function->New<IR::ExprList>();
args->init(_block->TEMP(withObject));
_block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_push_with_scope, 0, 0), args));
@@ -2857,7 +2940,7 @@ QList<QQmlError> Codegen::qmlErrors() const
qmlErrors.reserve(_errors.size());
QUrl url(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
- foreach (const QQmlJS::DiagnosticMessage &msg, _errors) {
+ for (const QQmlJS::DiagnosticMessage &msg: qAsConst(_errors)) {
QQmlError e;
e.setUrl(url);
e.setLine(msg.loc.startLine);
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 59199183bd..742ee79648 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -331,103 +331,103 @@ protected:
virtual void beginFunctionBodyHook() {}
// nodes
- virtual bool visit(AST::ArgumentList *ast);
- virtual bool visit(AST::CaseBlock *ast);
- virtual bool visit(AST::CaseClause *ast);
- virtual bool visit(AST::CaseClauses *ast);
- virtual bool visit(AST::Catch *ast);
- virtual bool visit(AST::DefaultClause *ast);
- virtual bool visit(AST::ElementList *ast);
- virtual bool visit(AST::Elision *ast);
- virtual bool visit(AST::Finally *ast);
- virtual bool visit(AST::FormalParameterList *ast);
- virtual bool visit(AST::FunctionBody *ast);
- virtual bool visit(AST::Program *ast);
- virtual bool visit(AST::PropertyNameAndValue *ast);
- virtual bool visit(AST::PropertyAssignmentList *ast);
- virtual bool visit(AST::PropertyGetterSetter *ast);
- virtual bool visit(AST::SourceElements *ast);
- virtual bool visit(AST::StatementList *ast);
- virtual bool visit(AST::UiArrayMemberList *ast);
- virtual bool visit(AST::UiImport *ast);
- virtual bool visit(AST::UiHeaderItemList *ast);
- virtual bool visit(AST::UiPragma *ast);
- virtual bool visit(AST::UiObjectInitializer *ast);
- virtual bool visit(AST::UiObjectMemberList *ast);
- virtual bool visit(AST::UiParameterList *ast);
- virtual bool visit(AST::UiProgram *ast);
- virtual bool visit(AST::UiQualifiedId *ast);
- virtual bool visit(AST::UiQualifiedPragmaId *ast);
- virtual bool visit(AST::VariableDeclaration *ast);
- virtual bool visit(AST::VariableDeclarationList *ast);
+ bool visit(AST::ArgumentList *ast) override;
+ bool visit(AST::CaseBlock *ast) override;
+ bool visit(AST::CaseClause *ast) override;
+ bool visit(AST::CaseClauses *ast) override;
+ bool visit(AST::Catch *ast) override;
+ bool visit(AST::DefaultClause *ast) override;
+ bool visit(AST::ElementList *ast) override;
+ bool visit(AST::Elision *ast) override;
+ bool visit(AST::Finally *ast) override;
+ bool visit(AST::FormalParameterList *ast) override;
+ bool visit(AST::FunctionBody *ast) override;
+ bool visit(AST::Program *ast) override;
+ bool visit(AST::PropertyNameAndValue *ast) override;
+ bool visit(AST::PropertyAssignmentList *ast) override;
+ bool visit(AST::PropertyGetterSetter *ast) override;
+ bool visit(AST::SourceElements *ast) override;
+ bool visit(AST::StatementList *ast) override;
+ bool visit(AST::UiArrayMemberList *ast) override;
+ bool visit(AST::UiImport *ast) override;
+ bool visit(AST::UiHeaderItemList *ast) override;
+ bool visit(AST::UiPragma *ast) override;
+ bool visit(AST::UiObjectInitializer *ast) override;
+ bool visit(AST::UiObjectMemberList *ast) override;
+ bool visit(AST::UiParameterList *ast) override;
+ bool visit(AST::UiProgram *ast) override;
+ bool visit(AST::UiQualifiedId *ast) override;
+ bool visit(AST::UiQualifiedPragmaId *ast) override;
+ bool visit(AST::VariableDeclaration *ast) override;
+ bool visit(AST::VariableDeclarationList *ast) override;
// expressions
- virtual bool visit(AST::Expression *ast);
- virtual bool visit(AST::ArrayLiteral *ast);
- virtual bool visit(AST::ArrayMemberExpression *ast);
- virtual bool visit(AST::BinaryExpression *ast);
- virtual bool visit(AST::CallExpression *ast);
- virtual bool visit(AST::ConditionalExpression *ast);
- virtual bool visit(AST::DeleteExpression *ast);
- virtual bool visit(AST::FalseLiteral *ast);
- virtual bool visit(AST::FieldMemberExpression *ast);
- virtual bool visit(AST::FunctionExpression *ast);
- virtual bool visit(AST::IdentifierExpression *ast);
- virtual bool visit(AST::NestedExpression *ast);
- virtual bool visit(AST::NewExpression *ast);
- virtual bool visit(AST::NewMemberExpression *ast);
- virtual bool visit(AST::NotExpression *ast);
- virtual bool visit(AST::NullExpression *ast);
- virtual bool visit(AST::NumericLiteral *ast);
- virtual bool visit(AST::ObjectLiteral *ast);
- virtual bool visit(AST::PostDecrementExpression *ast);
- virtual bool visit(AST::PostIncrementExpression *ast);
- virtual bool visit(AST::PreDecrementExpression *ast);
- virtual bool visit(AST::PreIncrementExpression *ast);
- virtual bool visit(AST::RegExpLiteral *ast);
- virtual bool visit(AST::StringLiteral *ast);
- virtual bool visit(AST::ThisExpression *ast);
- virtual bool visit(AST::TildeExpression *ast);
- virtual bool visit(AST::TrueLiteral *ast);
- virtual bool visit(AST::TypeOfExpression *ast);
- virtual bool visit(AST::UnaryMinusExpression *ast);
- virtual bool visit(AST::UnaryPlusExpression *ast);
- virtual bool visit(AST::VoidExpression *ast);
- virtual bool visit(AST::FunctionDeclaration *ast);
+ bool visit(AST::Expression *ast) override;
+ bool visit(AST::ArrayLiteral *ast) override;
+ bool visit(AST::ArrayMemberExpression *ast) override;
+ bool visit(AST::BinaryExpression *ast) override;
+ bool visit(AST::CallExpression *ast) override;
+ bool visit(AST::ConditionalExpression *ast) override;
+ bool visit(AST::DeleteExpression *ast) override;
+ bool visit(AST::FalseLiteral *ast) override;
+ bool visit(AST::FieldMemberExpression *ast) override;
+ bool visit(AST::FunctionExpression *ast) override;
+ bool visit(AST::IdentifierExpression *ast) override;
+ bool visit(AST::NestedExpression *ast) override;
+ bool visit(AST::NewExpression *ast) override;
+ bool visit(AST::NewMemberExpression *ast) override;
+ bool visit(AST::NotExpression *ast) override;
+ bool visit(AST::NullExpression *ast) override;
+ bool visit(AST::NumericLiteral *ast) override;
+ bool visit(AST::ObjectLiteral *ast) override;
+ bool visit(AST::PostDecrementExpression *ast) override;
+ bool visit(AST::PostIncrementExpression *ast) override;
+ bool visit(AST::PreDecrementExpression *ast) override;
+ bool visit(AST::PreIncrementExpression *ast) override;
+ bool visit(AST::RegExpLiteral *ast) override;
+ bool visit(AST::StringLiteral *ast) override;
+ bool visit(AST::ThisExpression *ast) override;
+ bool visit(AST::TildeExpression *ast) override;
+ bool visit(AST::TrueLiteral *ast) override;
+ bool visit(AST::TypeOfExpression *ast) override;
+ bool visit(AST::UnaryMinusExpression *ast) override;
+ bool visit(AST::UnaryPlusExpression *ast) override;
+ bool visit(AST::VoidExpression *ast) override;
+ bool visit(AST::FunctionDeclaration *ast) override;
// source elements
- virtual bool visit(AST::FunctionSourceElement *ast);
- virtual bool visit(AST::StatementSourceElement *ast);
+ bool visit(AST::FunctionSourceElement *ast) override;
+ bool visit(AST::StatementSourceElement *ast) override;
// statements
- virtual bool visit(AST::Block *ast);
- virtual bool visit(AST::BreakStatement *ast);
- virtual bool visit(AST::ContinueStatement *ast);
- virtual bool visit(AST::DebuggerStatement *ast);
- virtual bool visit(AST::DoWhileStatement *ast);
- virtual bool visit(AST::EmptyStatement *ast);
- virtual bool visit(AST::ExpressionStatement *ast);
- virtual bool visit(AST::ForEachStatement *ast);
- virtual bool visit(AST::ForStatement *ast);
- virtual bool visit(AST::IfStatement *ast);
- virtual bool visit(AST::LabelledStatement *ast);
- virtual bool visit(AST::LocalForEachStatement *ast);
- virtual bool visit(AST::LocalForStatement *ast);
- virtual bool visit(AST::ReturnStatement *ast);
- virtual bool visit(AST::SwitchStatement *ast);
- virtual bool visit(AST::ThrowStatement *ast);
- virtual bool visit(AST::TryStatement *ast);
- virtual bool visit(AST::VariableStatement *ast);
- virtual bool visit(AST::WhileStatement *ast);
- virtual bool visit(AST::WithStatement *ast);
+ bool visit(AST::Block *ast) override;
+ bool visit(AST::BreakStatement *ast) override;
+ bool visit(AST::ContinueStatement *ast) override;
+ bool visit(AST::DebuggerStatement *ast) override;
+ bool visit(AST::DoWhileStatement *ast) override;
+ bool visit(AST::EmptyStatement *ast) override;
+ bool visit(AST::ExpressionStatement *ast) override;
+ bool visit(AST::ForEachStatement *ast) override;
+ bool visit(AST::ForStatement *ast) override;
+ bool visit(AST::IfStatement *ast) override;
+ bool visit(AST::LabelledStatement *ast) override;
+ bool visit(AST::LocalForEachStatement *ast) override;
+ bool visit(AST::LocalForStatement *ast) override;
+ bool visit(AST::ReturnStatement *ast) override;
+ bool visit(AST::SwitchStatement *ast) override;
+ bool visit(AST::ThrowStatement *ast) override;
+ bool visit(AST::TryStatement *ast) override;
+ bool visit(AST::VariableStatement *ast) override;
+ bool visit(AST::WhileStatement *ast) override;
+ bool visit(AST::WithStatement *ast) override;
// ui object members
- virtual bool visit(AST::UiArrayBinding *ast);
- virtual bool visit(AST::UiObjectBinding *ast);
- virtual bool visit(AST::UiObjectDefinition *ast);
- virtual bool visit(AST::UiPublicMember *ast);
- virtual bool visit(AST::UiScriptBinding *ast);
- virtual bool visit(AST::UiSourceElement *ast);
+ bool visit(AST::UiArrayBinding *ast) override;
+ bool visit(AST::UiObjectBinding *ast) override;
+ bool visit(AST::UiObjectDefinition *ast) override;
+ bool visit(AST::UiPublicMember *ast) override;
+ bool visit(AST::UiScriptBinding *ast) override;
+ bool visit(AST::UiSourceElement *ast) override;
bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(QV4::IR::Expr* expr, const AST::SourceLocation &loc);
virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
@@ -486,39 +486,39 @@ protected:
void checkName(const QStringRef &name, const AST::SourceLocation &loc);
void checkForArguments(AST::FormalParameterList *parameters);
- virtual bool visit(AST::Program *ast);
- virtual void endVisit(AST::Program *);
+ bool visit(AST::Program *ast) override;
+ void endVisit(AST::Program *) override;
- virtual bool visit(AST::CallExpression *ast);
- virtual bool visit(AST::NewMemberExpression *ast);
- virtual bool visit(AST::ArrayLiteral *ast);
- virtual bool visit(AST::VariableDeclaration *ast);
- virtual bool visit(AST::IdentifierExpression *ast);
- virtual bool visit(AST::ExpressionStatement *ast);
- virtual bool visit(AST::FunctionExpression *ast);
+ bool visit(AST::CallExpression *ast) override;
+ bool visit(AST::NewMemberExpression *ast) override;
+ bool visit(AST::ArrayLiteral *ast) override;
+ bool visit(AST::VariableDeclaration *ast) override;
+ bool visit(AST::IdentifierExpression *ast) override;
+ bool visit(AST::ExpressionStatement *ast) override;
+ bool visit(AST::FunctionExpression *ast) override;
void enterFunction(AST::FunctionExpression *ast, bool enterName, bool isExpression = true);
- virtual void endVisit(AST::FunctionExpression *);
+ void endVisit(AST::FunctionExpression *) override;
- virtual bool visit(AST::ObjectLiteral *ast);
+ bool visit(AST::ObjectLiteral *ast) override;
- virtual bool visit(AST::PropertyGetterSetter *ast);
- virtual void endVisit(AST::PropertyGetterSetter *);
+ bool visit(AST::PropertyGetterSetter *ast) override;
+ void endVisit(AST::PropertyGetterSetter *) override;
- virtual bool visit(AST::FunctionDeclaration *ast);
- virtual void endVisit(AST::FunctionDeclaration *);
+ bool visit(AST::FunctionDeclaration *ast) override;
+ void endVisit(AST::FunctionDeclaration *) override;
- virtual bool visit(AST::WithStatement *ast);
+ bool visit(AST::WithStatement *ast) override;
- virtual bool visit(AST::DoWhileStatement *ast);
- virtual bool visit(AST::ForStatement *ast);
- virtual bool visit(AST::LocalForStatement *ast);
- virtual bool visit(AST::ForEachStatement *ast);
- virtual bool visit(AST::LocalForEachStatement *ast);
- virtual bool visit(AST::ThisExpression *ast);
+ bool visit(AST::DoWhileStatement *ast) override;
+ bool visit(AST::ForStatement *ast) override;
+ bool visit(AST::LocalForStatement *ast) override;
+ bool visit(AST::ForEachStatement *ast) override;
+ bool visit(AST::LocalForEachStatement *ast) override;
+ bool visit(AST::ThisExpression *ast) override;
- virtual bool visit(AST::Block *ast);
+ bool visit(AST::Block *ast) override;
protected:
void enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::FunctionBody *body, AST::FunctionExpression *expr, bool isExpression);
@@ -544,8 +544,8 @@ public:
, engine(engine)
{}
- virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
- virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
+ void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail) override;
+ void throwReferenceError(const AST::SourceLocation &loc, const QString &detail) override;
private:
QV4::ExecutionEngine *engine;
};
diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp
new file mode 100644
index 0000000000..2e1213464c
--- /dev/null
+++ b/src/qml/compiler/qv4compilationunitmapper.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "qv4compilationunitmapper_p.h"
+
+#include "qv4compileddata_p.h"
+#include <QFileInfo>
+#include <QDateTime>
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+CompilationUnitMapper::CompilationUnitMapper()
+ : dataPtr(nullptr)
+{
+
+}
+
+CompilationUnitMapper::~CompilationUnitMapper()
+{
+ close();
+}
+
+bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const QString &sourcePath, QString *errorString)
+{
+ if (strncmp(header->magic, CompiledData::magic_str, sizeof(header->magic))) {
+ *errorString = QStringLiteral("Magic bytes in the header do not match");
+ return false;
+ }
+
+ if (header->version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
+ *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(header->version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
+ return false;
+ }
+
+ if (header->qtVersion != quint32(QT_VERSION)) {
+ *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(header->qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
+ return false;
+ }
+
+ {
+ QFileInfo sourceCode(sourcePath);
+ QDateTime sourceTimeStamp;
+ if (sourceCode.exists())
+ sourceTimeStamp = sourceCode.lastModified();
+
+ // Files from the resource system do not have any time stamps, so fall back to the application
+ // executable.
+ if (!sourceTimeStamp.isValid())
+ sourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
+
+ if (sourceTimeStamp.isValid() && sourceTimeStamp.toMSecsSinceEpoch() != header->sourceTimeStamp) {
+ *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/compiler/qv4compilationunitmapper_p.h
new file mode 100644
index 0000000000..5b6939f1cf
--- /dev/null
+++ b/src/qml/compiler/qv4compilationunitmapper_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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$
+**
+****************************************************************************/
+
+#ifndef QV4COMPILATIONUNITMAPPER_H
+#define QV4COMPILATIONUNITMAPPER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4global_p.h>
+#include <QFile>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace CompiledData {
+struct Unit;
+}
+
+class CompilationUnitMapper
+{
+public:
+ CompilationUnitMapper();
+ ~CompilationUnitMapper();
+
+ CompiledData::Unit *open(const QString &cacheFilePath, const QString &sourcePath, QString *errorString);
+ void close();
+
+private:
+ static bool verifyHeader(const QV4::CompiledData::Unit *header, const QString &sourcePath, QString *errorString);
+
+#if defined(Q_OS_UNIX)
+ size_t length;
+#endif
+ void *dataPtr;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4COMPILATIONUNITMAPPER_H
diff --git a/src/qml/qml/qqmlaccessors.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
index 7b0fafdc90..1aa3e05f5f 100644
--- a/src/qml/qml/qqmlaccessors.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
@@ -37,69 +37,63 @@
**
****************************************************************************/
-#include "qqmlaccessors_p.h"
+#include "qv4compilationunitmapper_p.h"
-#include "qqmldata_p.h"
-#include "qqmlnotifier_p.h"
+#include <sys/mman.h>
+#include <functional>
+#include <private/qcore_unix_p.h>
+#include <private/qdeferredcleanup_p.h>
+
+#include "qv4compileddata_p.h"
QT_BEGIN_NAMESPACE
-struct AccessorProperties {
- AccessorProperties();
+using namespace QV4;
- QReadWriteLock lock;
- QHash<const QMetaObject *, QQmlAccessorProperties::Properties> properties;
-};
+CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString)
+{
+ close();
-Q_GLOBAL_STATIC(AccessorProperties, accessorProperties)
+ int fd = qt_safe_open(QFile::encodeName(cacheFileName).constData(), O_RDONLY);
+ if (fd == -1) {
+ *errorString = qt_error_string(errno);
+ return nullptr;
+ }
-static void buildNameMask(QQmlAccessorProperties::Properties &properties)
-{
- quint32 mask = 0;
+ QDeferredCleanup cleanup([fd]{
+ qt_safe_close(fd) ;
+ });
- for (int ii = 0; ii < properties.count; ++ii) {
- Q_ASSERT(strlen(properties.properties[ii].name) == properties.properties[ii].nameLength);
- Q_ASSERT(properties.properties[ii].nameLength > 0);
+ CompiledData::Unit header;
+ qint64 bytesRead = qt_safe_read(fd, reinterpret_cast<char *>(&header), sizeof(header));
- mask |= (1 << qMin(31U, properties.properties[ii].nameLength - 1));
+ if (bytesRead != sizeof(header)) {
+ *errorString = QStringLiteral("File too small for the header fields");
+ return nullptr;
}
- properties.nameMask = mask;
-}
+ if (!verifyHeader(&header, sourcePath, errorString))
+ return nullptr;
-AccessorProperties::AccessorProperties()
-{
-}
+ // Data structure and qt version matched, so now we can access the rest of the file safely.
-QQmlAccessorProperties::Properties::Properties(Property *properties, int count)
-: count(count), properties(properties)
-{
- buildNameMask(*this);
-}
+ length = static_cast<size_t>(lseek(fd, 0, SEEK_END));
-QQmlAccessorProperties::Properties
-QQmlAccessorProperties::properties(const QMetaObject *mo)
-{
- AccessorProperties *This = accessorProperties();
+ void *ptr = mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, /*offset*/0);
+ if (ptr == MAP_FAILED) {
+ *errorString = qt_error_string(errno);
+ return nullptr;
+ }
+ dataPtr = ptr;
- QReadLocker lock(&This->lock);
- return This->properties.value(mo);
+ return reinterpret_cast<CompiledData::Unit*>(dataPtr);
}
-void QQmlAccessorProperties::registerProperties(const QMetaObject *mo, int count,
- Property *props)
+void CompilationUnitMapper::close()
{
- Q_ASSERT(count > 0);
-
- Properties properties(props, count);
-
- AccessorProperties *This = accessorProperties();
-
- QWriteLocker lock(&This->lock);
-
- Q_ASSERT(!This->properties.contains(mo) || This->properties.value(mo) == properties);
-
- This->properties.insert(mo, properties);
+ if (dataPtr != nullptr)
+ munmap(dataPtr, length);
+ dataPtr = nullptr;
}
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp
new file mode 100644
index 0000000000..457b702ac3
--- /dev/null
+++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "qv4compilationunitmapper_p.h"
+
+#include "qv4compileddata_p.h"
+#include <private/qdeferredcleanup_p.h>
+#include <QFileInfo>
+#include <QDateTime>
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString)
+{
+ close();
+
+ // ### TODO: fix up file encoding/normalization/unc handling once QFileSystemEntry
+ // is exported from QtCore.
+ HANDLE handle =
+#if defined(Q_OS_WINRT)
+ CreateFile2(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),
+ GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
+ OPEN_EXISTING, nullptr);
+#else
+ CreateFile(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),
+ GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+ nullptr);
+#endif
+ if (handle == INVALID_HANDLE_VALUE) {
+ *errorString = qt_error_string(GetLastError());
+ return nullptr;
+ }
+
+ QDeferredCleanup fileHandleCleanup([handle]{
+ CloseHandle(handle);
+ });
+
+#if !defined(Q_OS_WINRT) || _MSC_VER >= 1900
+ CompiledData::Unit header;
+ DWORD bytesRead;
+ if (!ReadFile(handle, reinterpret_cast<char *>(&header), sizeof(header), &bytesRead, nullptr)) {
+ *errorString = qt_error_string(GetLastError());
+ return nullptr;
+ }
+
+ if (bytesRead != sizeof(header)) {
+ *errorString = QStringLiteral("File too small for the header fields");
+ return nullptr;
+ }
+
+ if (!verifyHeader(&header, sourcePath, errorString))
+ return nullptr;
+
+ const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode
+ ? PAGE_EXECUTE_READ : PAGE_READONLY;
+ const uint viewFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode
+ ? (FILE_MAP_READ | FILE_MAP_EXECUTE) : FILE_MAP_READ;
+
+ // Data structure and qt version matched, so now we can access the rest of the file safely.
+
+ HANDLE fileMappingHandle = CreateFileMapping(handle, 0, mappingFlags, 0, 0, 0);
+ if (!fileMappingHandle) {
+ *errorString = qt_error_string(GetLastError());
+ return nullptr;
+ }
+
+ QDeferredCleanup mappingCleanup([fileMappingHandle]{
+ CloseHandle(fileMappingHandle);
+ });
+
+ dataPtr = MapViewOfFile(fileMappingHandle, viewFlags, 0, 0, 0);
+ if (!dataPtr) {
+ *errorString = qt_error_string(GetLastError());
+ return nullptr;
+ }
+
+ return reinterpret_cast<CompiledData::Unit*>(dataPtr);
+#else
+ Q_UNUSED(sourcePath);
+ *errorString = QStringLiteral("Compilation unit mapping not supported on WinRT 8.1");
+ return nullptr;
+#endif
+}
+
+void CompilationUnitMapper::close()
+{
+#if !defined(Q_OS_WINRT) || _MSC_VER >= 1900
+ if (dataPtr != nullptr)
+ UnmapViewOfFile(dataPtr);
+#endif
+ dataPtr = nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index dc29d1b941..35f61b4f69 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -48,9 +48,20 @@
#include <private/qv4regexpobject_p.h>
#include <private/qqmlpropertycache_p.h>
#include <private/qqmltypeloader_p.h>
+#include <private/qqmlengine_p.h>
+#include "qv4compilationunitmapper_p.h"
+#include <QQmlPropertyMap>
+#include <QDateTime>
+#include <QSaveFile>
+#include <QFile>
+#include <QFileInfo>
+#include <QScopedValueRollback>
+#include <QStandardPaths>
+#include <QDir>
#endif
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
+#include <QCryptographicHash>
#include <algorithm>
@@ -71,13 +82,16 @@ CompilationUnit::CompilationUnit()
, totalBindingsCount(0)
, totalParserStatusCount(0)
, totalObjectCount(0)
+ , metaTypeId(-1)
+ , listMetaTypeId(-1)
+ , isRegisteredWithEngine(false)
{}
CompilationUnit::~CompilationUnit()
{
unlink();
if (data && !(data->flags & QV4::CompiledData::Unit::StaticData))
- free(data);
+ free(const_cast<Unit *>(data));
data = 0;
}
@@ -116,7 +130,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup *l = runtimeLookups + i;
- Lookup::Type type = Lookup::Type(compiledLookups[i].type_and_flags);
+ Lookup::Type type = Lookup::Type(uint(compiledLookups[i].type_and_flags));
if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric;
else if (type == CompiledData::Lookup::Type_Setter)
@@ -151,14 +165,18 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
}
}
- linkBackendToEngine(engine);
-
-#if 0
- runtimeFunctionsSortedByAddress.resize(runtimeFunctions.size());
- memcpy(runtimeFunctionsSortedByAddress.data(), runtimeFunctions.data(), runtimeFunctions.size() * sizeof(QV4::Function*));
- std::sort(runtimeFunctionsSortedByAddress.begin(), runtimeFunctionsSortedByAddress.end(), functionSortHelper);
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ Value *bigEndianConstants = new Value[data->constantTableSize];
+ const LEUInt64 *littleEndianConstants = data->constants();
+ for (uint i = 0; i < data->constantTableSize; ++i)
+ bigEndianConstants[i] = Value::fromReturnedValue(littleEndianConstants[i]);
+ constants = bigEndianConstants;
+#else
+ constants = reinterpret_cast<const Value*>(data->constants());
#endif
+ linkBackendToEngine(engine);
+
if (data->indexOfRootFunction != -1)
return runtimeFunctions[data->indexOfRootFunction];
else
@@ -170,9 +188,13 @@ void CompilationUnit::unlink()
if (engine)
engine->compilationUnits.erase(engine->compilationUnits.find(this));
- for (int ii = 0; ii < propertyCaches.count(); ++ii)
- if (propertyCaches.at(ii).data())
- propertyCaches.at(ii)->release();
+ if (isRegisteredWithEngine) {
+ Q_ASSERT(data && quint32(propertyCaches.count()) > data->indexOfRootObject && propertyCaches.at(data->indexOfRootObject));
+ QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(propertyCaches.at(data->indexOfRootObject)->engine);
+ qmlEngine->unregisterInternalCompositeType(this);
+ isRegisteredWithEngine = false;
+ }
+
propertyCaches.clear();
for (int ii = 0; ii < dependentScripts.count(); ++ii)
@@ -181,6 +203,9 @@ void CompilationUnit::unlink()
importCache = nullptr;
+ qDeleteAll(resolvedTypes);
+ resolvedTypes.clear();
+
engine = 0;
free(runtimeStrings);
runtimeStrings = 0;
@@ -192,6 +217,9 @@ void CompilationUnit::unlink()
runtimeClasses = 0;
qDeleteAll(runtimeFunctions);
runtimeFunctions.clear();
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ delete [] constants;
+#endif
}
void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
@@ -205,13 +233,24 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
}
}
+void CompilationUnit::destroy()
+{
+ QQmlEngine *qmlEngine = 0;
+ if (engine && engine->v8Engine)
+ qmlEngine = engine->v8Engine->engine();
+ if (qmlEngine)
+ QQmlEnginePrivate::deleteInEngineThread(qmlEngine, this);
+ else
+ delete this;
+}
+
IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
{
auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
if (it == namedObjectsPerComponentCache.end()) {
IdentifierHash<int> namedObjectCache(engine);
const CompiledData::Object *component = data->objectAt(componentObjectIndex);
- const quint32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
+ const LEUInt32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr);
namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
@@ -221,6 +260,192 @@ IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjec
return *it;
}
+void CompilationUnit::finalize(QQmlEnginePrivate *engine)
+{
+ // Add to type registry of composites
+ if (propertyCaches.needsVMEMetaObject(data->indexOfRootObject))
+ engine->registerInternalCompositeType(this);
+ else {
+ const QV4::CompiledData::Object *obj = objectAt(data->indexOfRootObject);
+ auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+ if (typeRef->compilationUnit) {
+ metaTypeId = typeRef->compilationUnit->metaTypeId;
+ listMetaTypeId = typeRef->compilationUnit->listMetaTypeId;
+ } else {
+ metaTypeId = typeRef->type->typeId();
+ listMetaTypeId = typeRef->type->qListTypeId();
+ }
+ }
+
+ // Collect some data for instantiation later.
+ int bindingCount = 0;
+ int parserStatusCount = 0;
+ int objectCount = 0;
+ for (quint32 i = 0; i < data->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = data->objectAt(i);
+ bindingCount += obj->nBindings;
+ if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ if (QQmlType *qmlType = typeRef->type) {
+ if (qmlType->parserStatusCast() != -1)
+ ++parserStatusCount;
+ }
+ ++objectCount;
+ if (typeRef->compilationUnit) {
+ bindingCount += typeRef->compilationUnit->totalBindingsCount;
+ parserStatusCount += typeRef->compilationUnit->totalParserStatusCount;
+ objectCount += typeRef->compilationUnit->totalObjectCount;
+ }
+ }
+ }
+
+ totalBindingsCount = bindingCount;
+ totalParserStatusCount = parserStatusCount;
+ totalObjectCount = objectCount;
+}
+
+bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
+ const ResolvedTypeReferenceMap &dependentTypes) const
+{
+ if (dependentTypes.isEmpty()) {
+ for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) {
+ if (data->dependencyMD5Checksum[i] != 0)
+ return false;
+ }
+ return true;
+ }
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ if (!dependentTypes.addToHash(&hash, engine))
+ return false;
+ QByteArray checksum = hash.result();
+ Q_ASSERT(checksum.size() == sizeof(data->dependencyMD5Checksum));
+ return memcmp(data->dependencyMD5Checksum, checksum.constData(),
+ sizeof(data->dependencyMD5Checksum)) == 0;
+}
+
+static QString cacheFilePath(const QUrl &url)
+{
+ const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
+ return localCachePath;
+ QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
+ fileNameHash.addData(localSourcePath.toUtf8());
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
+ QDir::root().mkpath(directory);
+ return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+}
+
+bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
+{
+ errorString->clear();
+
+ if (data->sourceTimeStamp == 0) {
+ *errorString = QStringLiteral("Missing time stamp for source file");
+ return false;
+ }
+
+ if (!QQmlFile::isLocalFile(unitUrl)) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ // Foo.qml -> Foo.qmlc
+ QSaveFile cacheFile(cacheFilePath(unitUrl));
+ if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ QByteArray modifiedUnit;
+ modifiedUnit.resize(data->unitSize);
+ memcpy(modifiedUnit.data(), data, data->unitSize);
+ const char *dataPtr = modifiedUnit.data();
+ Unit *unitPtr;
+ memcpy(&unitPtr, &dataPtr, sizeof(unitPtr));
+ unitPtr->flags |= Unit::StaticData;
+
+ prepareCodeOffsetsForDiskStorage(unitPtr);
+
+ qint64 headerWritten = cacheFile.write(modifiedUnit);
+ if (headerWritten != modifiedUnit.size()) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ if (!saveCodeToDisk(&cacheFile, unitPtr, errorString))
+ return false;
+
+ if (!cacheFile.commit()) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ return true;
+}
+
+bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
+{
+ if (!QQmlFile::isLocalFile(url)) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ const QString sourcePath = url.toLocalFile();
+ QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+
+ CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
+ if (!mappedUnit)
+ return false;
+
+ const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
+ QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+
+ {
+ const QString foundArchitecture = stringAt(data->architectureIndex);
+ const QString expectedArchitecture = QSysInfo::buildAbi();
+ if (foundArchitecture != expectedArchitecture) {
+ *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
+ return false;
+ }
+ }
+
+ {
+ const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
+ const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
+ if (foundCodeGenerator != expectedCodeGenerator) {
+ *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
+ return false;
+ }
+ }
+
+ if (!memoryMapCode(errorString))
+ return false;
+
+ dataPtrChange.commit();
+ free(const_cast<Unit*>(oldDataPtr));
+ backingFile.reset(cacheFile.take());
+ return true;
+}
+
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
+{
+ Q_UNUSED(unit);
+}
+
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
+{
+ Q_UNUSED(device);
+ Q_UNUSED(unit);
+ *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
+ return false;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ *errorString = QStringLiteral("Missing code mapping backend");
+ return false;
+}
#endif // V4_BOOTSTRAP
Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
@@ -237,7 +462,7 @@ QString Binding::valueAsString(const Unit *unit) const
case Type_Boolean:
return value.b ? QStringLiteral("true") : QStringLiteral("false");
case Type_Number:
- return QString::number(value.d);
+ return QString::number(valueAsNumber());
case Type_Invalid:
return QString();
#ifdef QT_NO_TRANSLATION
@@ -319,6 +544,69 @@ QString Binding::valueAsScriptString(const Unit *unit) const
return valueAsString(unit);
}
+#ifndef V4_BOOTSTRAP
+/*!
+Returns the property cache, if one alread exists. The cache is not referenced.
+*/
+QQmlPropertyCache *ResolvedTypeReference::propertyCache() const
+{
+ if (type)
+ return typePropertyCache;
+ else
+ return compilationUnit->rootPropertyCache();
+}
+
+/*!
+Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
+*/
+QQmlPropertyCache *ResolvedTypeReference::createPropertyCache(QQmlEngine *engine)
+{
+ if (typePropertyCache) {
+ return typePropertyCache;
+ } else if (type) {
+ typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type->metaObject());
+ return typePropertyCache;
+ } else {
+ return compilationUnit->rootPropertyCache();
+ }
+}
+
+template <typename T>
+bool qtTypeInherits(const QMetaObject *mo) {
+ while (mo) {
+ if (mo == &T::staticMetaObject)
+ return true;
+ mo = mo->superClass();
+ }
+ return false;
+}
+
+void ResolvedTypeReference::doDynamicTypeCheck()
+{
+ const QMetaObject *mo = 0;
+ if (typePropertyCache)
+ mo = typePropertyCache->firstCppMetaObject();
+ else if (type)
+ mo = type->metaObject();
+ else if (compilationUnit)
+ mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
+ isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
+}
+
+bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const
+{
+ for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
+ QQmlPropertyCache *pc = it.value()->createPropertyCache(engine);
+ bool ok = false;
+ hash->addData(pc->checksum(&ok));
+ if (!ok)
+ return false;
+ }
+ return true;
+}
+
+#endif
+
}
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 8beb932fc8..ae8677138e 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -62,20 +62,24 @@
#include <private/qqmlnullablevalue_p.h>
#include <private/qv4identifier_p.h>
#include <private/qflagpointer_p.h>
+#include <private/qjson_p.h>
#ifndef V4_BOOTSTRAP
#include <private/qqmltypenamecache_p.h>
+#include <private/qqmlpropertycache_p.h>
#endif
QT_BEGIN_NAMESPACE
+// Bump this whenever the compiler data structures change in an incompatible way.
+#define QV4_DATA_STRUCTURE_VERSION 0x04
+
+class QIODevice;
class QQmlPropertyCache;
class QQmlPropertyData;
class QQmlTypeNameCache;
class QQmlScriptData;
-
-// The vector is indexed by QV4::CompiledData::Object index and the flag
-// indicates whether instantiation of the object requires a VME meta-object.
-typedef QVector<QFlagPointer<QQmlPropertyCache>> QQmlPropertyCacheVector;
+class QQmlType;
+class QQmlEngine;
namespace QmlIR {
struct Document;
@@ -87,25 +91,49 @@ struct Function;
}
struct Function;
+class EvalISelFactory;
+class CompilationUnitMapper;
namespace CompiledData {
+typedef QJsonPrivate::q_littleendian<qint16> LEInt16;
+typedef QJsonPrivate::q_littleendian<quint16> LEUInt16;
+typedef QJsonPrivate::q_littleendian<quint32> LEUInt32;
+typedef QJsonPrivate::q_littleendian<qint32> LEInt32;
+typedef QJsonPrivate::q_littleendian<quint64> LEUInt64;
+typedef QJsonPrivate::q_littleendian<qint64> LEInt64;
+
struct String;
struct Function;
struct Lookup;
struct RegExp;
struct Unit;
+template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const>
+struct TableIterator
+{
+ TableIterator(const Container *container, int index) : container(container), index(index) {}
+ const Container *container;
+ int index;
+
+ const ItemType *operator->() { return (container->*IndexedGetter)(index); }
+ void operator++() { ++index; }
+ bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
+ bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
+};
+
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
#pragma pack(push, 1)
#endif
struct Location
{
- qint32 line : 20;
- qint32 column : 12;
+ union {
+ QJsonPrivate::qle_bitfield<0, 20> line;
+ QJsonPrivate::qle_bitfield<20, 12> column;
+ };
- Location(): line(-1), column(-1) {}
+ Location() { line = 0; column = 0; }
inline bool operator<(const Location &other) const {
return line < other.line ||
@@ -115,20 +143,22 @@ struct Location
struct RegExp
{
- enum Flags {
+ enum Flags : unsigned int {
RegExp_Global = 0x01,
RegExp_IgnoreCase = 0x02,
RegExp_Multiline = 0x04
};
- quint32 flags : 4;
- quint32 stringIndex : 28;
+ union {
+ QJsonPrivate::qle_bitfield<0, 4> flags;
+ QJsonPrivate::qle_bitfield<4, 28> stringIndex;
+ };
- static int calculateSize() { return sizeof(RegExp); }
+ RegExp() { flags = 0; stringIndex = 0; }
};
struct Lookup
{
- enum Type {
+ enum Type : unsigned int {
Type_Getter = 0x0,
Type_Setter = 0x1,
Type_GlobalGetter = 2,
@@ -136,21 +166,27 @@ struct Lookup
Type_IndexedSetter = 4
};
- quint32 type_and_flags : 4;
- quint32 nameIndex : 28;
+ union {
+ QJsonPrivate::qle_bitfield<0, 4> type_and_flags;
+ QJsonPrivate::qle_bitfield<4, 28> nameIndex;
+ };
- static int calculateSize() { return sizeof(Lookup); }
+ Lookup() { type_and_flags = 0; nameIndex = 0; }
};
struct JSClassMember
{
- quint32 nameOffset : 31;
- quint32 isAccessor : 1;
+ union {
+ QJsonPrivate::qle_bitfield<0, 31> nameOffset;
+ QJsonPrivate::qle_bitfield<31, 1> isAccessor;
+ };
+
+ JSClassMember() { nameOffset = 0; isAccessor = 0; }
};
struct JSClass
{
- uint nMembers;
+ LEUInt32 nMembers;
// JSClassMember[nMembers]
static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
@@ -158,7 +194,7 @@ struct JSClass
struct String
{
- qint32 size;
+ LEInt32 size;
// uint16 strdata[]
static int calculateSize(const QString &str) {
@@ -168,7 +204,7 @@ struct String
struct Function
{
- enum Flags {
+ enum Flags : unsigned int {
HasDirectEval = 0x1,
UsesArgumentsObject = 0x2,
IsStrict = 0x4,
@@ -176,36 +212,46 @@ struct Function
HasCatchOrWith = 0x10
};
- quint32 index; // in CompilationUnit's function table
- quint32 nameIndex;
- qint64 flags;
- quint32 nFormals;
- quint32 formalsOffset;
- quint32 nLocals;
- quint32 localsOffset;
- quint32 nInnerFunctions;
- quint32 innerFunctionsOffset;
+ LEUInt32 nameIndex;
+ LEUInt32 nFormals;
+ LEUInt32 formalsOffset;
+ LEUInt32 nLocals;
+ LEUInt32 localsOffset;
+ LEUInt32 nInnerFunctions;
Location location;
// Qml Extensions Begin
- quint32 nDependingIdObjects;
- quint32 dependingIdObjectsOffset; // Array of resolved ID objects
- quint32 nDependingContextProperties;
- quint32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
- quint32 nDependingScopeProperties;
- quint32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
+ LEUInt32 nDependingIdObjects;
+ LEUInt32 dependingIdObjectsOffset; // Array of resolved ID objects
+ LEUInt32 nDependingContextProperties;
+ LEUInt32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
+ LEUInt32 nDependingScopeProperties;
+ LEUInt32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
// Qml Extensions End
+ // Absolute offset into file where the code for this function is located. Only used when the function
+ // is serialized.
+ LEUInt64 codeOffset;
+ LEUInt64 codeSize;
+
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
// quint32 offsetForInnerFunctions[nInnerFunctions]
// Function[nInnerFunctions]
- const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
- const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
- const quint32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
- const quint32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
- const quint32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
+ // Keep all unaligned data at the end
+ quint8 flags;
+
+ const LEUInt32 *formalsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
+ const LEUInt32 *localsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
+ const LEUInt32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
+ const LEUInt32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
+ const LEUInt32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
+
+ // --- QQmlPropertyCacheCreator interface
+ const LEUInt32 *formalsBegin() const { return formalsTable(); }
+ const LEUInt32 *formalsEnd() const { return formalsTable() + nFormals; }
+ // ---
inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; }
@@ -217,15 +263,15 @@ struct Function
// Qml data structures
struct Q_QML_EXPORT TranslationData {
- quint32 commentIndex;
- int number;
+ LEUInt32 commentIndex;
+ LEInt32 number;
};
struct Q_QML_PRIVATE_EXPORT Binding
{
- quint32 propertyNameIndex;
+ LEUInt32 propertyNameIndex;
- enum ValueType {
+ enum ValueType : unsigned int {
Type_Invalid,
Type_Boolean,
Type_Number,
@@ -238,7 +284,7 @@ struct Q_QML_PRIVATE_EXPORT Binding
Type_GroupProperty
};
- enum Flags {
+ enum Flags : unsigned int {
IsSignalHandlerExpression = 0x1,
IsSignalHandlerObject = 0x2,
IsOnAssignment = 0x4,
@@ -250,16 +296,18 @@ struct Q_QML_PRIVATE_EXPORT Binding
IsCustomParserBinding = 0x100,
};
- quint32 flags : 16;
- quint32 type : 16;
+ union {
+ QJsonPrivate::qle_bitfield<0, 16> flags;
+ QJsonPrivate::qle_bitfield<16, 16> type;
+ };
union {
bool b;
- double d;
- quint32 compiledScriptIndex; // used when Type_Script
- quint32 objectIndex;
+ quint64 doubleValue; // do not access directly, needs endian protected access
+ LEUInt32 compiledScriptIndex; // used when Type_Script
+ LEUInt32 objectIndex;
TranslationData translationData; // used when Type_Translation
} value;
- quint32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
+ LEUInt32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
Location location;
Location valueLocation;
@@ -319,11 +367,20 @@ struct Q_QML_PRIVATE_EXPORT Binding
QString valueAsScriptString(const Unit *unit) const;
double valueAsNumber() const
{
- if (type == Type_Number)
- return value.d;
- return 0.0;
-
+ if (type != Type_Number)
+ return 0.0;
+ quint64 intval = qFromLittleEndian<quint64>(value.doubleValue);
+ double d;
+ memcpy(&d, &intval, sizeof(double));
+ return d;
+ }
+ void setNumberValueInternal(double d)
+ {
+ quint64 intval;
+ memcpy(&intval, &d, sizeof(double));
+ value.doubleValue = qToLittleEndian<quint64>(intval);
}
+
bool valueAsBoolean() const
{
if (type == Type_Boolean)
@@ -335,16 +392,16 @@ struct Q_QML_PRIVATE_EXPORT Binding
struct Parameter
{
- quint32 nameIndex;
- quint32 type;
- quint32 customTypeNameIndex;
+ LEUInt32 nameIndex;
+ LEUInt32 type;
+ LEUInt32 customTypeNameIndex;
Location location;
};
struct Signal
{
- quint32 nameIndex;
- quint32 nParameters;
+ LEUInt32 nameIndex;
+ LEUInt32 nParameters;
Location location;
// Parameter parameters[1];
@@ -357,41 +414,53 @@ struct Signal
+ nParameters * sizeof(Parameter)
+ 7) & ~0x7;
}
+
+ // --- QQmlPropertyCacheCceatorInterface
+ const Parameter *parametersBegin() const { return parameterAt(0); }
+ const Parameter *parametersEnd() const { return parameterAt(nParameters); }
+ int parameterCount() const { return nParameters; }
+ // ---
};
struct Property
{
- enum Type { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
+ enum Type : unsigned int { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
Font, Time, Date, DateTime, Rect, Point, Size,
Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
Custom, CustomList };
- enum Flags {
+ enum Flags : unsigned int {
IsReadOnly = 0x1
};
- quint32 nameIndex;
- quint32 type : 31;
- quint32 flags : 1; // readonly
- quint32 customTypeNameIndex; // If type >= Custom
+ LEUInt32 nameIndex;
+ union {
+ QJsonPrivate::qle_bitfield<0, 31> type;
+ QJsonPrivate::qle_bitfield<31, 1> flags; // readonly
+ };
+ LEUInt32 customTypeNameIndex; // If type >= Custom
Location location;
};
struct Alias {
- enum Flags {
+ enum Flags : unsigned int {
IsReadOnly = 0x1,
Resolved = 0x2,
AliasPointsToPointerObject = 0x4
};
- quint32 nameIndex : 29;
- quint32 flags : 3;
union {
- quint32 idIndex; // string index
- quint32 targetObjectId; // object id index (in QQmlContextData::idValues)
+ QJsonPrivate::qle_bitfield<0, 29> nameIndex;
+ QJsonPrivate::qle_bitfield<29, 3> flags;
};
union {
- quint32 propertyNameIndex; // string index
- qint32 encodedMetaPropertyIndex;
+ LEUInt32 idIndex; // string index
+ QJsonPrivate::qle_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
+ QJsonPrivate::qle_bitfield<31, 1> aliasToLocalAlias;
+ };
+ union {
+ LEUInt32 propertyNameIndex; // string index
+ LEInt32 encodedMetaPropertyIndex;
+ LEUInt32 localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
};
Location location;
Location referenceLocation;
@@ -404,7 +473,7 @@ struct Alias {
struct Object
{
- enum Flags {
+ enum Flags : 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
@@ -414,24 +483,26 @@ struct Object
// 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 inheritedTypeNameIndex;
- quint32 idNameIndex;
- qint32 id : 16;
- qint32 flags : 15;
- quint32 defaultPropertyIsAlias : 1;
- qint32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
- quint32 nFunctions;
- quint32 offsetToFunctions;
- quint32 nProperties;
- quint32 offsetToProperties;
- quint32 nAliases;
- quint32 offsetToAliases;
- quint32 nSignals;
- quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
- quint32 nBindings;
- quint32 offsetToBindings;
- quint32 nNamedObjectsInComponent;
- quint32 offsetToNamedObjectsInComponent;
+ LEUInt32 inheritedTypeNameIndex;
+ LEUInt32 idNameIndex;
+ union {
+ QJsonPrivate::qle_bitfield<0, 15> flags;
+ QJsonPrivate::qle_bitfield<15, 1> defaultPropertyIsAlias;
+ QJsonPrivate::qle_signedbitfield<16, 16> id;
+ };
+ LEInt32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
+ LEUInt32 nFunctions;
+ LEUInt32 offsetToFunctions;
+ LEUInt32 nProperties;
+ LEUInt32 offsetToProperties;
+ LEUInt32 nAliases;
+ LEUInt32 offsetToAliases;
+ LEUInt32 nSignals;
+ LEUInt32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
+ LEUInt32 nBindings;
+ LEUInt32 offsetToBindings;
+ LEUInt32 nNamedObjectsInComponent;
+ LEUInt32 offsetToNamedObjectsInComponent;
Location location;
Location locationOfIdProperty;
// Function[]
@@ -452,9 +523,9 @@ struct Object
) & ~0x7;
}
- const quint32 *functionOffsetTable() const
+ const LEUInt32 *functionOffsetTable() const
{
- return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
+ return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
}
const Property *propertyTable() const
@@ -474,83 +545,113 @@ struct Object
const Signal *signalAt(int idx) const
{
- const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
+ const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
}
- const quint32 *namedObjectsInComponentTable() const
+ const LEUInt32 *namedObjectsInComponentTable() const
{
- return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
+ return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
}
+
+ // --- QQmlPropertyCacheCreator interface
+ int propertyCount() const { return nProperties; }
+ int aliasCount() const { return nAliases; }
+ int signalCount() const { return nSignals; }
+ int functionCount() const { return nFunctions; }
+
+ const Binding *bindingsBegin() const { return bindingTable(); }
+ const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
+
+ const Property *propertiesBegin() const { return propertyTable(); }
+ const Property *propertiesEnd() const { return propertyTable() + nProperties; }
+
+ const Alias *aliasesBegin() const { return aliasTable(); }
+ const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
+
+ typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
+ SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
+ SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
+
+ int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
+ // ---
};
struct Import
{
- enum ImportType {
+ enum ImportType : unsigned int {
ImportLibrary = 0x1,
ImportFile = 0x2,
ImportScript = 0x3
};
- quint32 type;
+ quint8 type;
- quint32 uriIndex;
- quint32 qualifierIndex;
+ LEUInt32 uriIndex;
+ LEUInt32 qualifierIndex;
- qint32 majorVersion;
- qint32 minorVersion;
+ LEInt32 majorVersion;
+ LEInt32 minorVersion;
Location location;
- Import(): type(0), uriIndex(0), qualifierIndex(0), majorVersion(0), minorVersion(0) {}
+ Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
};
static const char magic_str[] = "qv4cdata";
struct Unit
{
+ // DO NOT CHANGE THESE FIELDS EVER
char magic[8];
- qint16 architecture;
- qint16 version;
- quint32 unitSize; // Size of the Unit and any depending data.
+ LEUInt32 version;
+ LEUInt32 qtVersion;
+ LEInt64 sourceTimeStamp;
+ LEUInt32 unitSize; // Size of the Unit and any depending data.
+ // END DO NOT CHANGE THESE FIELDS EVER
- enum {
+ LEUInt32 architectureIndex; // string index to QSysInfo::buildAbi()
+ LEUInt32 codeGeneratorIndex;
+ char dependencyMD5Checksum[16];
+
+ enum : unsigned int {
IsJavascript = 0x1,
IsQml = 0x2,
StaticData = 0x4, // Unit data persistent in memory?
IsSingleton = 0x8,
- IsSharedLibrary = 0x10 // .pragma shared?
+ IsSharedLibrary = 0x10, // .pragma shared?
+ ContainsMachineCode = 0x20 // used to determine if we need to mmap with execute permissions
};
- quint32 flags;
- uint stringTableSize;
- uint offsetToStringTable;
- uint functionTableSize;
- uint offsetToFunctionTable;
- uint lookupTableSize;
- uint offsetToLookupTable;
- uint regexpTableSize;
- uint offsetToRegexpTable;
- uint constantTableSize;
- uint offsetToConstantTable;
- uint jsClassTableSize;
- uint offsetToJSClassTable;
- qint32 indexOfRootFunction;
- quint32 sourceFileIndex;
+ LEUInt32 flags;
+ LEUInt32 stringTableSize;
+ LEUInt32 offsetToStringTable;
+ LEUInt32 functionTableSize;
+ LEUInt32 offsetToFunctionTable;
+ LEUInt32 lookupTableSize;
+ LEUInt32 offsetToLookupTable;
+ LEUInt32 regexpTableSize;
+ LEUInt32 offsetToRegexpTable;
+ LEUInt32 constantTableSize;
+ LEUInt32 offsetToConstantTable;
+ LEUInt32 jsClassTableSize;
+ LEUInt32 offsetToJSClassTable;
+ LEInt32 indexOfRootFunction;
+ LEUInt32 sourceFileIndex;
/* QML specific fields */
- quint32 nImports;
- quint32 offsetToImports;
- quint32 nObjects;
- quint32 offsetToObjects;
- quint32 indexOfRootObject;
+ LEUInt32 nImports;
+ LEUInt32 offsetToImports;
+ LEUInt32 nObjects;
+ LEUInt32 offsetToObjects;
+ LEUInt32 indexOfRootObject;
const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
}
const Object *objectAt(int idx) const {
- const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
+ const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
}
@@ -560,22 +661,33 @@ struct Unit
/* end QML specific fields*/
QString stringAt(int idx) const {
- const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
+ const LEUInt32 offset = offsetTable[idx];
const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
if (str->size == 0)
return QString();
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
- if (flags & StaticData)
- return QString::fromRawData(characters, str->size);
+ // Too risky to do this while we unmap disk backed compilation but keep pointers to string
+ // data in the identifier tables.
+ // if (flags & StaticData)
+ // return QString::fromRawData(characters, str->size);
return QString(characters, str->size);
+#else
+ const LEUInt16 *characters = reinterpret_cast<const LEUInt16 *>(str + 1);
+ QString qstr(str->size, Qt::Uninitialized);
+ QChar *ch = qstr.data();
+ for (int i = 0; i < str->size; ++i)
+ ch[i] = QChar(characters[i]);
+ return qstr;
+#endif
}
- const uint *functionOffsetTable() const { return reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
+ const LEUInt32 *functionOffsetTable() const { return reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
const Function *functionAt(int idx) const {
- const uint *offsetTable = functionOffsetTable();
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = functionOffsetTable();
+ const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
}
@@ -583,27 +695,18 @@ struct Unit
const RegExp *regexpAt(int index) const {
return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
}
- const QV4::Value *constants() const {
- return reinterpret_cast<const QV4::Value*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
+ const LEUInt64 *constants() const {
+ return reinterpret_cast<const LEUInt64*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
}
const JSClassMember *jsClassAt(int idx, int *nMembers) const {
- const uint *offsetTable = reinterpret_cast<const uint *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
- const uint offset = offsetTable[idx];
+ const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
+ const LEUInt32 offset = offsetTable[idx];
const char *ptr = reinterpret_cast<const char *>(this) + offset;
const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
*nMembers = klass->nMembers;
return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
}
-
- static int calculateSize(uint nFunctions, uint nRegExps, uint nConstants,
- uint nLookups, uint nClasses) {
- return (sizeof(Unit)
- + (nFunctions + nClasses) * sizeof(uint)
- + nRegExps * RegExp::calculateSize()
- + nConstants * sizeof(QV4::ReturnedValue)
- + nLookups * Lookup::calculateSize()
- + 7) & ~7; }
};
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
@@ -631,8 +734,75 @@ struct TypeReferenceMap : QHash<int, TypeReference>
return *it;
return *insert(nameIndex, loc);
}
+
+ template <typename CompiledObject>
+ void collectFromObject(const CompiledObject *obj)
+ {
+ if (obj->inheritedTypeNameIndex != 0) {
+ TypeReference &r = this->add(obj->inheritedTypeNameIndex, obj->location);
+ r.needsCreation = true;
+ r.errorWhenNotFound = true;
+ }
+
+ for (auto prop = obj->propertiesBegin(), propEnd = obj->propertiesEnd(); prop != propEnd; ++prop) {
+ if (prop->type >= QV4::CompiledData::Property::Custom) {
+ // ### FIXME: We could report the more accurate location here by using prop->location, but the old
+ // compiler can't and the tests expect it to be the object location right now.
+ TypeReference &r = this->add(prop->customTypeNameIndex, obj->location);
+ r.errorWhenNotFound = true;
+ }
+ }
+
+ for (auto binding = obj->bindingsBegin(), bindingEnd = obj->bindingsEnd(); binding != bindingEnd; ++binding) {
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
+ this->add(binding->propertyNameIndex, binding->location);
+ }
+ }
+
+ template <typename Iterator>
+ void collectFromObjects(Iterator it, Iterator end)
+ {
+ for (; it != end; ++it)
+ collectFromObject(*it);
+ }
};
+#ifndef V4_BOOTSTRAP
+struct ResolvedTypeReference
+{
+ ResolvedTypeReference()
+ : type(0)
+ , majorVersion(0)
+ , minorVersion(0)
+ , isFullyDynamicType(false)
+ {}
+
+ QQmlType *type;
+ QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+
+ int majorVersion;
+ int minorVersion;
+ // Types such as QQmlPropertyMap can add properties dynamically at run-time and
+ // therefore cannot have a property cache installed when instantiated.
+ bool isFullyDynamicType;
+
+ QQmlPropertyCache *propertyCache() const;
+ QQmlPropertyCache *createPropertyCache(QQmlEngine *);
+
+ void doDynamicTypeCheck();
+};
+// map from name index
+// While this could be a hash, a map is chosen here to provide a stable
+// order, which is used to calculating a check-sum on dependent meta-objects.
+struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
+{
+ bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
+};
+#else
+struct ResolvedTypeReferenceMap {};
+#endif
+
// index is per-object binding index
typedef QVector<QQmlPropertyData*> BindingPropertyData;
@@ -654,7 +824,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
virtual ~CompilationUnit();
#endif
- Unit *data;
+ const Unit *data;
// Called only when building QML, when we build the header for JS first and append QML data
virtual QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument);
@@ -673,8 +843,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
// QML specific fields
QQmlPropertyCacheVector propertyCaches;
- QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject).data(); }
- bool isCompositeType() const { return propertyCaches.at(data->indexOfRootObject).flag(); }
+ QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject); }
QQmlRefPointer<QQmlTypeNameCache> importCache;
@@ -688,19 +857,65 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QHash<int, IdentifierHash<int>> namedObjectsPerComponentCache;
IdentifierHash<int> namedObjectsPerComponent(int componentObjectIndex);
+ // pointers either to data->constants() or little-endian memory copy.
+ const Value* constants;
+
+ void finalize(QQmlEnginePrivate *engine);
+
int totalBindingsCount; // Number of bindings used in this type
int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
int totalObjectCount; // Number of objects explicitly instantiated
QVector<QQmlScriptData *> dependentScripts;
+ ResolvedTypeReferenceMap resolvedTypes;
+
+ bool verifyChecksum(QQmlEngine *engine,
+ const ResolvedTypeReferenceMap &dependentTypes) const;
+
+ int metaTypeId;
+ int listMetaTypeId;
+ bool isRegisteredWithEngine;
+
+ QScopedPointer<CompilationUnitMapper> backingFile;
+
+ // --- interface for QQmlPropertyCacheCreator
+ typedef Object CompiledObject;
+ int objectCount() const { return data->nObjects; }
+ int rootObjectIndex() const { return data->indexOfRootObject; }
+ const Object *objectAt(int index) const { return data->objectAt(index); }
+ QString stringAt(int index) const { return data->stringAt(index); }
+
+ struct FunctionIterator
+ {
+ FunctionIterator(const Unit *unit, const Object *object, int index) : unit(unit), object(object), index(index) {}
+ const Unit *unit;
+ const Object *object;
+ int index;
+
+ const Function *operator->() const { return unit->functionAt(object->functionOffsetTable()[index]); }
+ void operator++() { ++index; }
+ bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
+ bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
+ };
+ FunctionIterator objectFunctionsBegin(const Object *object) const { return FunctionIterator(data, object, 0); }
+ FunctionIterator objectFunctionsEnd(const Object *object) const { return FunctionIterator(data, object, object->nFunctions); }
+ // ---
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
void unlink();
void markObjects(QV4::ExecutionEngine *e);
+ void destroy() Q_DECL_OVERRIDE;
+
+ bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+ bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString);
+
protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
+ virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit);
+ virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString);
+ virtual bool memoryMapCode(QString *errorString);
#endif // V4_BOOTSTRAP
};
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index aacf0e9928..729c56540d 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -42,6 +42,8 @@
#include <qv4isel_p.h>
#include <private/qv4string_p.h>
#include <private/qv4value_p.h>
+#include <private/qv4alloca_p.h>
+#include <wtf/MathExtras.h>
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
@@ -75,15 +77,21 @@ void QV4::Compiler::StringTableGenerator::clear()
void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
- uint *stringTable = reinterpret_cast<uint *>(dataStart + unit->offsetToStringTable);
+ CompiledData::LEUInt32 *stringTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataStart + unit->offsetToStringTable);
char *stringData = dataStart + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
for (int i = 0; i < strings.size(); ++i) {
stringTable[i] = stringData - dataStart;
const QString &qstr = strings.at(i);
- QV4::CompiledData::String *s = (QV4::CompiledData::String*)(stringData);
+ QV4::CompiledData::String *s = reinterpret_cast<QV4::CompiledData::String *>(stringData);
s->size = qstr.length();
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
memcpy(s + 1, qstr.constData(), qstr.length()*sizeof(ushort));
+#else
+ ushort *uc = reinterpret_cast<ushort *>(s + 1);
+ for (int i = 0; i < qstr.length(); ++i)
+ uc[i] = qToLittleEndian<ushort>(qstr.at(i).unicode());
+#endif
stringData += QV4::CompiledData::String::calculateSize(qstr);
}
@@ -91,7 +99,6 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module)
: irModule(module)
- , jsClassDataSize(0)
{
// Make sure the empty string always gets index 0
registerString(QString());
@@ -173,36 +180,38 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg
{
// ### re-use existing class definitions.
- QList<CompiledData::JSClassMember> members;
- members.reserve(count);
+ const int size = CompiledData::JSClass::calculateSize(count);
+ jsClassOffsets.append(jsClassData.size());
+ const int oldSize = jsClassData.size();
+ jsClassData.resize(jsClassData.size() + size);
+ memset(jsClassData.data() + oldSize, 0, size);
- IR::ExprList *it = args;
- for (int i = 0; i < count; ++i, it = it->next) {
- CompiledData::JSClassMember member;
+ CompiledData::JSClass *jsClass = reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
+ jsClass->nMembers = count;
+ CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
+ IR::ExprList *it = args;
+ for (int i = 0; i < count; ++i, it = it->next, ++member) {
QV4::IR::Name *name = it->expr->asName();
it = it->next;
const bool isData = it->expr->asConst()->value;
it = it->next;
- member.nameOffset = registerString(*name->id);
- member.isAccessor = !isData;
- members << member;
+ member->nameOffset = registerString(*name->id);
+ member->isAccessor = !isData;
if (!isData)
it = it->next;
}
- jsClasses << members;
- jsClassDataSize += CompiledData::JSClass::calculateSize(members.count());
- return jsClasses.size() - 1;
+ return jsClassOffsets.size() - 1;
}
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
{
registerString(irModule->fileName);
- foreach (QV4::IR::Function *f, irModule->functions) {
+ for (QV4::IR::Function *f : qAsConst(irModule->functions)) {
registerString(*f->name);
for (int i = 0; i < f->formals.size(); ++i)
registerString(*f->formals.at(i));
@@ -210,94 +219,51 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(*f->locals.at(i));
}
- int unitSize = QV4::CompiledData::Unit::calculateSize(irModule->functions.size(), regexps.size(),
- constants.size(), lookups.size(), jsClasses.count());
-
- uint functionDataSize = 0;
- for (int i = 0; i < irModule->functions.size(); ++i) {
- QV4::IR::Function *f = irModule->functions.at(i);
- functionOffsets.insert(f, functionDataSize + unitSize);
+ CompiledData::LEUInt32 *functionOffsets = reinterpret_cast<CompiledData::LEUInt32*>(alloca(irModule->functions.size() * sizeof(CompiledData::LEUInt32)));
+ uint jsClassDataOffset = 0;
- const int qmlIdDepsCount = f->idObjectDependencies.count();
- const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
- functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
+ char *dataPtr;
+ CompiledData::Unit *unit;
+ {
+ QV4::CompiledData::Unit tempHeader = generateHeader(option, functionOffsets, &jsClassDataOffset);
+ dataPtr = reinterpret_cast<char *>(malloc(tempHeader.unitSize));
+ memcpy(&unit, &dataPtr, sizeof(CompiledData::Unit*));
+ memcpy(unit, &tempHeader, sizeof(tempHeader));
}
- const int totalSize = unitSize + functionDataSize + jsClassDataSize + (option == GenerateWithStringTable ? stringTable.sizeOfTableAndData() : 0);
- char *data = (char *)malloc(totalSize);
- memset(data, 0, totalSize);
- QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
-
- memcpy(unit->magic, QV4::CompiledData::magic_str, sizeof(unit->magic));
- unit->architecture = 0; // ###
- unit->flags = QV4::CompiledData::Unit::IsJavascript;
- unit->version = 1;
- unit->unitSize = totalSize;
- unit->functionTableSize = irModule->functions.size();
- unit->offsetToFunctionTable = sizeof(*unit);
- unit->lookupTableSize = lookups.count();
- unit->offsetToLookupTable = unit->offsetToFunctionTable + unit->functionTableSize * sizeof(uint);
- unit->regexpTableSize = regexps.size();
- unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize();
- unit->constantTableSize = constants.size();
- unit->offsetToConstantTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
- unit->jsClassTableSize = jsClasses.count();
- unit->offsetToJSClassTable = unit->offsetToConstantTable + unit->constantTableSize * sizeof(ReturnedValue);
- if (option == GenerateWithStringTable) {
- unit->stringTableSize = stringTable.stringCount();
- unit->offsetToStringTable = unitSize + functionDataSize + jsClassDataSize;
- } else {
- unit->stringTableSize = 0;
- unit->offsetToStringTable = 0;
- }
- unit->indexOfRootFunction = -1;
- unit->sourceFileIndex = getStringId(irModule->fileName);
- unit->nImports = 0;
- unit->offsetToImports = 0;
- unit->nObjects = 0;
- unit->offsetToObjects = 0;
- unit->indexOfRootObject = 0;
-
- uint *functionTable = (uint *)(data + unit->offsetToFunctionTable);
- for (int i = 0; i < irModule->functions.size(); ++i)
- functionTable[i] = functionOffsets.value(irModule->functions.at(i));
-
- char *f = data + unitSize;
+ memcpy(dataPtr + unit->offsetToFunctionTable, functionOffsets, unit->functionTableSize * sizeof(CompiledData::LEUInt32));
+
for (int i = 0; i < irModule->functions.size(); ++i) {
QV4::IR::Function *function = irModule->functions.at(i);
if (function == irModule->rootFunction)
unit->indexOfRootFunction = i;
- const int bytes = writeFunction(f, i, function);
- f += bytes;
+ writeFunction(dataPtr + functionOffsets[i], function);
}
- CompiledData::Lookup *lookupsToWrite = (CompiledData::Lookup*)(data + unit->offsetToLookupTable);
- foreach (const CompiledData::Lookup &l, lookups)
+ CompiledData::Lookup *lookupsToWrite = reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
+ for (const CompiledData::Lookup &l : qAsConst(lookups))
*lookupsToWrite++ = l;
- CompiledData::RegExp *regexpTable = (CompiledData::RegExp *)(data + unit->offsetToRegexpTable);
+ CompiledData::RegExp *regexpTable = reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
- ReturnedValue *constantTable = (ReturnedValue *)(data + unit->offsetToConstantTable);
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ ReturnedValue *constantTable = reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
-
- // write js classes and js class lookup table
- uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable);
- char *jsClass = data + unitSize + functionDataSize;
- for (int i = 0; i < jsClasses.count(); ++i) {
- jsClassTable[i] = jsClass - data;
-
- const QList<CompiledData::JSClassMember> members = jsClasses.at(i);
-
- CompiledData::JSClass *c = reinterpret_cast<CompiledData::JSClass*>(jsClass);
- c->nMembers = members.count();
-
- CompiledData::JSClassMember *memberToWrite = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + sizeof(CompiledData::JSClass));
- foreach (const CompiledData::JSClassMember &member, members)
- *memberToWrite++ = member;
-
- jsClass += CompiledData::JSClass::calculateSize(members.count());
+#else
+ CompiledData::LEUInt64 *constantTable = reinterpret_cast<CompiledData::LEUInt64 *>(dataPtr + unit->offsetToConstantTable);
+ for (int i = 0; i < constants.count(); ++i)
+ constantTable[i] = constants.at(i);
+#endif
+
+ {
+ memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
+
+ // write js classes and js class lookup table
+ CompiledData::LEUInt32 *jsClassOffsetTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataPtr + unit->offsetToJSClassTable);
+ for (int i = 0; i < jsClassOffsets.count(); ++i)
+ jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
}
// write strings and string table
@@ -307,13 +273,13 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
return unit;
}
-int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::Function *irFunction)
+void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *irFunction) const
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
quint32 currentOffset = sizeof(QV4::CompiledData::Function);
+ currentOffset = (currentOffset + 7) & ~quint32(0x7);
- function->index = index;
function->nameIndex = getStringId(*irFunction->name);
function->flags = 0;
if (irFunction->hasDirectEval)
@@ -335,8 +301,6 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
currentOffset += function->nLocals * sizeof(quint32);
function->nInnerFunctions = irFunction->nestedFunctions.size();
- function->innerFunctionsOffset = currentOffset;
- currentOffset += function->nInnerFunctions * sizeof(quint32);
function->nDependingIdObjects = 0;
function->nDependingContextProperties = 0;
@@ -363,6 +327,9 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
function->location.line = irFunction->line;
function->location.column = irFunction->column;
+ function->codeOffset = 0;
+ function->codeSize = 0;
+
// write formals
quint32 *formals = (quint32 *)(f + function->formalsOffset);
for (int i = 0; i < irFunction->formals.size(); ++i)
@@ -373,15 +340,12 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
for (int i = 0; i < irFunction->locals.size(); ++i)
locals[i] = getStringId(*irFunction->locals.at(i));
- // write inner functions
- quint32 *innerFunctions = (quint32 *)(f + function->innerFunctionsOffset);
- for (int i = 0; i < irFunction->nestedFunctions.size(); ++i)
- innerFunctions[i] = functionOffsets.value(irFunction->nestedFunctions.at(i));
-
// write QML dependencies
quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
- foreach (int id, irFunction->idObjectDependencies)
- *writtenDeps++ = id;
+ for (int id : irFunction->idObjectDependencies) {
+ Q_ASSERT(id >= 0);
+ *writtenDeps++ = static_cast<quint32>(id);
+ }
writtenDeps = (quint32 *)(f + function->dependingContextPropertiesOffset);
for (auto property : irFunction->contextObjectPropertyDependencies) {
@@ -394,7 +358,75 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
*writtenDeps++ = property.key(); // property index
*writtenDeps++ = property.value(); // notify index
}
+}
+
+QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset)
+{
+ CompiledData::Unit unit;
+ memcpy(unit.magic, CompiledData::magic_str, sizeof(unit.magic));
+ unit.flags = QV4::CompiledData::Unit::IsJavascript;
+ unit.flags |= irModule->unitFlags;
+ unit.version = QV4_DATA_STRUCTURE_VERSION;
+ unit.qtVersion = QT_VERSION;
+ unit.architectureIndex = registerString(QSysInfo::buildAbi());
+ unit.codeGeneratorIndex = registerString(codeGeneratorName);
+ memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
- return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions,
- function->nDependingIdObjects, function->nDependingContextProperties + function->nDependingScopeProperties);
+ quint32 nextOffset = sizeof(CompiledData::Unit);
+
+ unit.functionTableSize = irModule->functions.size();
+ unit.offsetToFunctionTable = nextOffset;
+ nextOffset += unit.functionTableSize * sizeof(uint);
+
+ unit.lookupTableSize = lookups.count();
+ unit.offsetToLookupTable = nextOffset;
+ nextOffset += unit.lookupTableSize * sizeof(CompiledData::Lookup);
+
+ unit.regexpTableSize = regexps.size();
+ unit.offsetToRegexpTable = nextOffset;
+ nextOffset += unit.regexpTableSize * sizeof(CompiledData::RegExp);
+
+ unit.constantTableSize = constants.size();
+
+ // Ensure we load constants from well-aligned addresses into for example SSE registers.
+ nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(16, nextOffset));
+ unit.offsetToConstantTable = nextOffset;
+ nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
+
+ unit.jsClassTableSize = jsClassOffsets.count();
+ unit.offsetToJSClassTable = nextOffset;
+ nextOffset += unit.jsClassTableSize * sizeof(uint);
+
+ *jsClassDataOffset = nextOffset;
+ nextOffset += jsClassData.size();
+
+ for (int i = 0; i < irModule->functions.size(); ++i) {
+ QV4::IR::Function *f = irModule->functions.at(i);
+ functionOffsets[i] = nextOffset;
+
+ const int qmlIdDepsCount = f->idObjectDependencies.count();
+ const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
+ nextOffset += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
+ }
+
+ if (option == GenerateWithStringTable) {
+ unit.stringTableSize = stringTable.stringCount();
+ unit.offsetToStringTable = nextOffset;
+ nextOffset += stringTable.sizeOfTableAndData();
+ } else {
+ unit.stringTableSize = 0;
+ unit.offsetToStringTable = 0;
+ }
+ unit.indexOfRootFunction = -1;
+ unit.sourceFileIndex = getStringId(irModule->fileName);
+ unit.sourceTimeStamp = irModule->sourceTimeStamp;
+ unit.nImports = 0;
+ unit.offsetToImports = 0;
+ unit.nObjects = 0;
+ unit.offsetToObjects = 0;
+ unit.indexOfRootObject = 0;
+
+ unit.unitSize = nextOffset;
+
+ return unit;
}
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 0321a83b4f..49b8664513 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -52,6 +52,7 @@
#include <QtCore/qstring.h>
#include "qv4jsir_p.h"
+#include <private/qjson_p.h>
QT_BEGIN_NAMESPACE
@@ -114,18 +115,20 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
QV4::CompiledData::Unit *generateUnit(GeneratorOption option = GenerateWithStringTable);
// Returns bytes written
- int writeFunction(char *f, int index, IR::Function *irFunction);
+ void writeFunction(char *f, IR::Function *irFunction) const;
StringTableGenerator stringTable;
+ QString codeGeneratorName;
private:
+ CompiledData::Unit generateHeader(GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset);
+
IR::Module *irModule;
- QHash<IR::Function *, uint> functionOffsets;
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
QVector<ReturnedValue> constants;
- QList<QList<CompiledData::JSClassMember> > jsClasses;
- uint jsClassDataSize;
+ QByteArray jsClassData;
+ QVector<int> jsClassOffsets;
};
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 93043135a4..beb43376ee 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -58,10 +58,17 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+#define MOTH_DEBUG_INSTR(F)
+#else
+#define MOTH_DEBUG_INSTR(F) \
+ F(Line, line) \
+ F(Debug, debug)
+#endif
+
#define FOR_EACH_MOTH_INSTR(F) \
F(Ret, ret) \
- F(Line, line) \
- F(Debug, debug) \
+ MOTH_DEBUG_INSTR(F) \
F(LoadRuntimeString, loadRuntimeString) \
F(LoadRegExp, loadRegExp) \
F(LoadClosure, loadClosure) \
@@ -81,19 +88,9 @@ QT_BEGIN_NAMESPACE
F(SetLookup, setLookup) \
F(StoreQObjectProperty, storeQObjectProperty) \
F(LoadQObjectProperty, loadQObjectProperty) \
- F(LoadQRealQObjectPropertyDirectly, loadQRealQObjectPropertyDirectly) \
- F(LoadQObjectQObjectPropertyDirectly, loadQObjectQObjectPropertyDirectly) \
- F(LoadIntQObjectPropertyDirectly, loadIntQObjectPropertyDirectly) \
- F(LoadBoolQObjectPropertyDirectly, loadBoolQObjectPropertyDirectly) \
- F(LoadQStringQObjectPropertyDirectly, loadQStringQObjectPropertyDirectly) \
F(StoreScopeObjectProperty, storeScopeObjectProperty) \
F(StoreContextObjectProperty, storeContextObjectProperty) \
F(LoadScopeObjectProperty, loadScopeObjectProperty) \
- F(LoadScopeObjectQRealPropertyDirectly, loadScopeObjectQRealPropertyDirectly) \
- F(LoadScopeObjectQObjectPropertyDirectly, loadScopeObjectQObjectPropertyDirectly) \
- F(LoadScopeObjectIntPropertyDirectly, loadScopeObjectIntPropertyDirectly) \
- F(LoadScopeObjectBoolPropertyDirectly, loadScopeObjectBoolPropertyDirectly) \
- F(LoadScopeObjectQStringPropertyDirectly, loadScopeObjectQStringPropertyDirectly) \
F(LoadContextObjectProperty, loadContextObjectProperty) \
F(LoadIdObject, loadIdObject) \
F(LoadAttachedQObjectProperty, loadAttachedQObjectProperty) \
@@ -172,7 +169,7 @@ QT_BEGIN_NAMESPACE
#define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QV4::Moth::Instr) - 1)
#ifdef MOTH_THREADED_INTERPRETER
-# define MOTH_INSTR_HEADER void *code;
+# define MOTH_INSTR_HEADER union { quint32 instructionType; void *code; };
#else
# define MOTH_INSTR_HEADER quint32 instructionType;
#endif
@@ -184,6 +181,8 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Moth {
+ // When making changes to the instructions, make sure to bump QV4_DATA_STRUCTURE_VERSION in qv4compileddata_p.h
+
struct Param {
// Params are looked up as follows:
// Constant: 0
@@ -262,6 +261,8 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+
+#ifndef QT_NO_QML_DEBUGGING
struct instr_line {
MOTH_INSTR_HEADER
qint32 lineNumber;
@@ -270,6 +271,8 @@ union Instr
MOTH_INSTR_HEADER
qint32 lineNumber;
};
+#endif // QT_NO_QML_DEBUGGING
+
struct instr_loadRuntimeString {
MOTH_INSTR_HEADER
int stringId;
@@ -332,42 +335,14 @@ union Instr
int propertyIndex;
Param base;
Param result;
- };
- struct instr_loadScopeObjectQRealPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- };
- struct instr_loadScopeObjectQObjectPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- };
- struct instr_loadScopeObjectIntPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- };
- struct instr_loadScopeObjectBoolPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- };
- struct instr_loadScopeObjectQStringPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
+ bool captureRequired;
};
struct instr_loadContextObjectProperty {
MOTH_INSTR_HEADER
int propertyIndex;
Param base;
Param result;
+ bool captureRequired;
};
struct instr_loadIdObject {
MOTH_INSTR_HEADER
@@ -382,46 +357,6 @@ union Instr
Param result;
bool captureRequired;
};
- struct instr_loadQRealQObjectPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- int coreIndex;
- int notifyIndex;
- };
- struct instr_loadQObjectQObjectPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- int coreIndex;
- int notifyIndex;
- };
- struct instr_loadIntQObjectPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- int coreIndex;
- int notifyIndex;
- };
- struct instr_loadBoolQObjectPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- int coreIndex;
- int notifyIndex;
- };
- struct instr_loadQStringQObjectPropertyDirectly {
- MOTH_INSTR_HEADER
- Param base;
- Param result;
- QQmlAccessors *accessors;
- int coreIndex;
- int notifyIndex;
- };
struct instr_loadAttachedQObjectProperty {
MOTH_INSTR_HEADER
int propertyIndex;
@@ -880,19 +815,9 @@ union Instr
instr_loadProperty loadProperty;
instr_getLookup getLookup;
instr_loadScopeObjectProperty loadScopeObjectProperty;
- instr_loadScopeObjectQRealPropertyDirectly loadScopeObjectQRealPropertyDirectly;
- instr_loadScopeObjectQObjectPropertyDirectly loadScopeObjectQObjectPropertyDirectly;
- instr_loadScopeObjectIntPropertyDirectly loadScopeObjectIntPropertyDirectly;
- instr_loadScopeObjectBoolPropertyDirectly loadScopeObjectBoolPropertyDirectly;
- instr_loadScopeObjectQStringPropertyDirectly loadScopeObjectQStringPropertyDirectly;
instr_loadContextObjectProperty loadContextObjectProperty;
instr_loadIdObject loadIdObject;
instr_loadQObjectProperty loadQObjectProperty;
- instr_loadQRealQObjectPropertyDirectly loadQRealQObjectPropertyDirectly;
- instr_loadQObjectQObjectPropertyDirectly loadQObjectQObjectPropertyDirectly;
- instr_loadIntQObjectPropertyDirectly loadIntQObjectPropertyDirectly;
- instr_loadBoolQObjectPropertyDirectly loadBoolQObjectPropertyDirectly;
- instr_loadQStringQObjectPropertyDirectly loadQStringQObjectPropertyDirectly;
instr_loadAttachedQObjectProperty loadAttachedQObjectProperty;
instr_storeProperty storeProperty;
instr_setLookup setLookup;
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index b452c4b3d9..5dd722bfc2 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -46,8 +46,7 @@
#include <private/qv4regexpobject_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmlengine_p.h>
-#include "qml/qqmlaccessors_p.h"
-#include "qml/qqmlpropertycache_p.h"
+#include <wtf/MathExtras.h>
#undef USE_TYPE_INFO
@@ -151,171 +150,10 @@ inline bool isBoolType(IR::Expr *e)
return (e->type == IR::BoolType);
}
-/*
- * stack slot allocation:
- *
- * foreach bb do
- * foreach stmt do
- * if the current statement is not a phi-node:
- * purge ranges that end before the current statement
- * check for life ranges to activate, and if they don't have a stackslot associated then allocate one
- * renumber temps to stack
- * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated
- * if it's a jump:
- * foreach phi node in the successor:
- * allocate slots for each temp (both sources and targets) if they don't have one allocated already
- * insert moves before the jump
- */
-class AllocateStackSlots: protected ConvertTemps
-{
- IR::LifeTimeIntervals::Ptr _intervals;
- QVector<IR::LifeTimeInterval *> _unhandled;
- QVector<IR::LifeTimeInterval *> _live;
- QBitArray _slotIsInUse;
- IR::Function *_function;
-
- int defPosition(IR::Stmt *s) const
- {
- return usePosition(s) + 1;
- }
-
- int usePosition(IR::Stmt *s) const
- {
- return _intervals->positionForStatement(s);
- }
-
-public:
- AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals)
- : _intervals(intervals)
- , _slotIsInUse(intervals->size(), false)
- , _function(0)
- {
- _live.reserve(8);
- _unhandled = _intervals->intervals();
- }
-
- void forFunction(IR::Function *function)
- {
- IR::Optimizer::showMeTheCode(function, "Before stack slot allocation");
- _function = function;
- toStackSlots(function);
- }
-
-protected:
- virtual int allocateFreeSlot()
- {
- for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) {
- if (!_slotIsInUse[i]) {
- if (_nextUnusedStackSlot <= i) {
- Q_ASSERT(_nextUnusedStackSlot == i);
- _nextUnusedStackSlot = i + 1;
- }
- _slotIsInUse[i] = true;
- return i;
- }
- }
-
- Q_UNREACHABLE();
- return -1;
- }
-
- virtual void process(IR::Stmt *s)
- {
-// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id);
-
- if (IR::Phi *phi = s->asPhi()) {
- visitPhi(phi);
- } else {
- // purge ranges no longer alive:
- for (int i = 0; i < _live.size(); ) {
- const IR::LifeTimeInterval *lti = _live.at(i);
- if (lti->end() < usePosition(s)) {
-// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index];
- _live.remove(i);
- Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]);
- _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false;
- continue;
- } else {
- ++i;
- }
- }
-
- // active new ranges:
- while (!_unhandled.isEmpty()) {
- IR::LifeTimeInterval *lti = _unhandled.last();
- if (lti->start() > defPosition(s))
- break; // we're done
- Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index));
- _stackSlotForTemp[lti->temp().index] = allocateFreeSlot();
-// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index];
- _live.append(lti);
- _unhandled.removeLast();
- }
-
- s->accept(this);
- }
-
- if (IR::Jump *jump = s->asJump()) {
- IR::MoveMapping moves;
- for (IR::Stmt *succStmt : jump->target->statements()) {
- if (IR::Phi *phi = succStmt->asPhi()) {
- forceActivation(*phi->targetTemp);
- for (int i = 0, ei = phi->incoming.size(); i != ei; ++i) {
- IR::Expr *e = phi->incoming[i];
- if (IR::Temp *t = e->asTemp()) {
- forceActivation(*t);
- }
- if (jump->target->in[i] == _currentBasicBlock)
- moves.add(phi->incoming[i], phi->targetTemp);
- }
- } else {
- break;
- }
- }
- moves.order();
- QList<IR::Move *> newMoves = moves.insertMoves(_currentBasicBlock, _function, true);
- foreach (IR::Move *move, newMoves)
- move->accept(this);
- }
- }
-
- void forceActivation(const IR::Temp &t)
- {
- if (_stackSlotForTemp.contains(t.index))
- return;
-
- int i = _unhandled.size() - 1;
- for (; i >= 0; --i) {
- IR::LifeTimeInterval *lti = _unhandled[i];
- if (lti->temp() == t) {
- _live.append(lti);
- _unhandled.remove(i);
- break;
- }
- }
- Q_ASSERT(i >= 0); // check that we always found the entry
-
- _stackSlotForTemp[t.index] = allocateFreeSlot();
-// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index];
- }
-
- virtual void visitPhi(IR::Phi *phi)
- {
- Q_UNUSED(phi);
-#if !defined(QT_NO_DEBUG)
- Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index));
- Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]);
- foreach (IR::Expr *e, phi->incoming) {
- if (IR::Temp *t = e->asTemp())
- Q_ASSERT(_stackSlotForTemp.contains(t->index));
- }
-#endif // defined(QT_NO_DEBUG)
- }
-};
} // anonymous namespace
-InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- : EvalInstructionSelection(execAllocator, module, jsGenerator)
+InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
+ : EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
, qmlEngine(qmlEngine)
, _block(0)
, _codeStart(0)
@@ -361,7 +199,7 @@ void InstructionSelection::run(int functionIndex)
qEnvironmentVariableIsEmpty("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION");
if (doStackSlotAllocation) {
- AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function);
+ IR::AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function);
} else {
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
@@ -371,7 +209,7 @@ void InstructionSelection::run(int functionIndex)
ConvertTemps().toStackSlots(_function);
}
- QSet<IR::Jump *> removableJumps = opt.calculateOptionalJumps();
+ BitVector removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
IR::Stmt *cs = 0;
@@ -413,6 +251,7 @@ void InstructionSelection::run(int functionIndex)
if (s->location.startLine != currentLine) {
blockNeedsDebugInstruction = false;
currentLine = s->location.startLine;
+#ifndef QT_NO_QML_DEBUGGER
if (irModule->debugMode) {
Instruction::Debug debug;
debug.lineNumber = currentLine;
@@ -422,10 +261,11 @@ void InstructionSelection::run(int functionIndex)
line.lineNumber = currentLine;
addInstruction(line);
}
+#endif
}
}
- s->accept(this);
+ visit(s);
}
}
@@ -452,7 +292,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backend
{
compilationUnit->codeRefs.resize(irModule->functions.size());
int i = 0;
- foreach (IR::Function *irFunction, irModule->functions)
+ for (IR::Function *irFunction : qAsConst(irModule->functions))
compilationUnit->codeRefs[i++] = codeRefs[irFunction];
QQmlRefPointer<QV4::CompiledData::CompilationUnit> result;
result.adopt(compilationUnit.take());
@@ -739,61 +579,20 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target
addInstruction(store);
}
-void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind,
- QQmlPropertyData *property, int index,
- IR::Expr *target)
-{
- if (property && property->hasAccessors() && property->isFullyResolved()) {
- if (kind == IR::Member::MemberOfQmlScopeObject) {
- if (property->propType == QMetaType::QReal) {
- Instruction::LoadScopeObjectQRealPropertyDirectly load;
- load.base = getParam(source);
- load.accessors = property->accessors;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- } else if (property->isQObject()) {
- Instruction::LoadScopeObjectQObjectPropertyDirectly load;
- load.base = getParam(source);
- load.accessors = property->accessors;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- } else if (property->propType == QMetaType::Int) {
- Instruction::LoadScopeObjectIntPropertyDirectly load;
- load.base = getParam(source);
- load.accessors = property->accessors;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- } else if (property->propType == QMetaType::Bool) {
- Instruction::LoadScopeObjectBoolPropertyDirectly load;
- load.base = getParam(source);
- load.accessors = property->accessors;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- } else if (property->propType == QMetaType::QString) {
- Instruction::LoadScopeObjectQStringPropertyDirectly load;
- load.base = getParam(source);
- load.accessors = property->accessors;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- }
- }
- }
-
+void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
+{
if (kind == IR::Member::MemberOfQmlScopeObject) {
Instruction::LoadScopeObjectProperty load;
load.base = getParam(source);
load.propertyIndex = index;
+ load.captureRequired = captureRequired;
load.result = getResultParam(target);
addInstruction(load);
} else if (kind == IR::Member::MemberOfQmlContextObject) {
Instruction::LoadContextObjectProperty load;
load.base = getParam(source);
load.propertyIndex = index;
+ load.captureRequired = captureRequired;
load.result = getResultParam(target);
addInstruction(load);
} else if (kind == IR::Member::MemberOfIdObjectsArray) {
@@ -807,59 +606,8 @@ void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::M
}
}
-void InstructionSelection::getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target)
-{
- if (property && property->hasAccessors() && property->isFullyResolved()) {
- if (!attachedPropertiesId && !isSingletonProperty) {
- if (property->propType == QMetaType::QReal) {
- Instruction::LoadQRealQObjectPropertyDirectly load;
- load.base = getParam(base);
- load.accessors = property->accessors;
- load.coreIndex = property->coreIndex;
- load.notifyIndex = captureRequired ? property->notifyIndex : -1;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- } else if (property->isQObject()) {
- Instruction::LoadQObjectQObjectPropertyDirectly load;
- load.base = getParam(base);
- load.accessors = property->accessors;
- load.coreIndex = property->coreIndex;
- load.notifyIndex = captureRequired ? property->notifyIndex : -1;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- } else if (property->propType == QMetaType::Int) {
- Instruction::LoadIntQObjectPropertyDirectly load;
- load.base = getParam(base);
- load.accessors = property->accessors;
- load.coreIndex = property->coreIndex;
- load.notifyIndex = captureRequired ? property->notifyIndex : -1;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- } else if (property->propType == QMetaType::Bool) {
- Instruction::LoadBoolQObjectPropertyDirectly load;
- load.base = getParam(base);
- load.accessors = property->accessors;
- load.coreIndex = property->coreIndex;
- load.notifyIndex = captureRequired ? property->notifyIndex : -1;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- } else if (property->propType == QMetaType::QString) {
- Instruction::LoadQStringQObjectPropertyDirectly load;
- load.base = getParam(base);
- load.accessors = property->accessors;
- load.coreIndex = property->coreIndex;
- load.notifyIndex = captureRequired ? property->notifyIndex : -1;
- load.result = getResultParam(target);
- addInstruction(load);
- return;
- }
- }
- }
- const int propertyIndex = property->coreIndex;
+void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target)
+{
if (attachedPropertiesId != 0) {
Instruction::LoadAttachedQObjectProperty load;
load.propertyIndex = propertyIndex;
@@ -1187,18 +935,25 @@ void InstructionSelection::prepareCallArgs(IR::ExprList *e, quint32 &argc, quint
}
}
-void InstructionSelection::visitJump(IR::Jump *s)
+void InstructionSelection::addDebugInstruction()
{
- if (s->target == _nextBlock)
- return;
- if (_removableJumps.contains(s))
- return;
-
+#ifndef QT_NO_QML_DEBUGGER
if (blockNeedsDebugInstruction) {
Instruction::Debug debug;
debug.lineNumber = -int(currentLine);
addInstruction(debug);
}
+#endif
+}
+
+void InstructionSelection::visitJump(IR::Jump *s)
+{
+ if (s->target == _nextBlock)
+ return;
+ if (_removableJumps.at(_block->index()))
+ return;
+
+ addDebugInstruction();
Instruction::Jump jump;
jump.offset = 0;
@@ -1209,11 +964,7 @@ void InstructionSelection::visitJump(IR::Jump *s)
void InstructionSelection::visitCJump(IR::CJump *s)
{
- if (blockNeedsDebugInstruction) {
- Instruction::Debug debug;
- debug.lineNumber = -int(currentLine);
- addInstruction(debug);
- }
+ addDebugInstruction();
Param condition;
if (IR::Temp *t = s->cond->asTemp()) {
@@ -1248,12 +999,8 @@ void InstructionSelection::visitCJump(IR::CJump *s)
void InstructionSelection::visitRet(IR::Ret *s)
{
- if (blockNeedsDebugInstruction) {
- // this is required so stepOut will always be guaranteed to stop in every stack frame
- Instruction::Debug debug;
- debug.lineNumber = -int(currentLine);
- addInstruction(debug);
- }
+ // this is required so stepOut will always be guaranteed to stop in every stack frame
+ addDebugInstruction();
Instruction::Ret ret;
ret.result = getParam(s->expr);
@@ -1589,12 +1336,7 @@ void QV4::Moth::InstructionSelection::callBuiltinConvertThisToObject()
ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
{
-
-#ifdef MOTH_THREADED_INTERPRETER
- instr.common.code = VME::instructionJumpTable()[static_cast<int>(type)];
-#else
instr.common.instructionType = type;
-#endif
int instructionSize = Instr::size(type);
if (_codeEnd - _codeNext < instructionSize) {
@@ -1680,6 +1422,29 @@ CompilationUnit::~CompilationUnit()
void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
{
+#ifdef MOTH_THREADED_INTERPRETER
+ // link byte code against addresses of instructions
+ for (int i = 0; i < codeRefs.count(); ++i) {
+ QByteArray &codeRef = codeRefs[i];
+ char *code = codeRef.data();
+ int index = 0;
+ while (index < codeRef.size()) {
+ Instr *genericInstr = reinterpret_cast<Instr *>(code + index);
+
+ switch (genericInstr->common.instructionType) {
+#define LINK_INSTRUCTION(InstructionType, Member) \
+ case Instr::InstructionType: \
+ genericInstr->common.code = VME::instructionJumpTable()[static_cast<int>(genericInstr->common.instructionType)]; \
+ index += InstrMeta<(int)Instr::InstructionType>::Size; \
+ break;
+
+ FOR_EACH_MOTH_INSTR(LINK_INSTRUCTION)
+
+ }
+ }
+ }
+#endif
+
runtimeFunctions.resize(data->functionTableSize);
runtimeFunctions.fill(0);
for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
@@ -1690,3 +1455,80 @@ void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
runtimeFunctions[i] = runtimeFunction;
}
}
+
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
+{
+ const int codeAlignment = 16;
+ quint64 offset = WTF::roundUpToMultipleOf(codeAlignment, unit->unitSize);
+ Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
+ for (int i = 0; i < codeRefs.size(); ++i) {
+ CompiledData::Function *compiledFunction = const_cast<CompiledData::Function *>(unit->functionAt(i));
+ compiledFunction->codeOffset = offset;
+ compiledFunction->codeSize = codeRefs.at(i).size();
+ offset = WTF::roundUpToMultipleOf(codeAlignment, offset + compiledFunction->codeSize);
+ }
+}
+
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString)
+{
+ Q_ASSERT(device->pos() == unit->unitSize);
+ Q_ASSERT(device->atEnd());
+ Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
+
+ QByteArray padding;
+
+ for (int i = 0; i < codeRefs.size(); ++i) {
+ const CompiledData::Function *compiledFunction = unit->functionAt(i);
+
+ if (device->pos() > qint64(compiledFunction->codeOffset)) {
+ *errorString = QStringLiteral("Invalid state of cache file to write.");
+ return false;
+ }
+
+ const quint64 paddingSize = compiledFunction->codeOffset - device->pos();
+ padding.fill(0, paddingSize);
+ qint64 written = device->write(padding);
+ if (written != padding.size()) {
+ *errorString = device->errorString();
+ return false;
+ }
+
+ const void *codePtr = codeRefs.at(i).constData();
+ written = device->write(reinterpret_cast<const char *>(codePtr), compiledFunction->codeSize);
+ if (written != qint64(compiledFunction->codeSize)) {
+ *errorString = device->errorString();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ codeRefs.resize(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset));
+#ifdef MOTH_THREADED_INTERPRETER
+ // for the threaded interpreter we need to make a copy of the data because it needs to be
+ // modified for the instruction handler addresses.
+ QByteArray code(codePtr, compiledFunction->codeSize);
+#else
+ QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
+#endif
+ codeRefs[i] = code;
+ }
+
+ return true;
+}
+
+QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
+{
+ QQmlRefPointer<CompiledData::CompilationUnit> result;
+ result.adopt(new Moth::CompilationUnit);
+ return result;
+}
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index bf3909682d..9699555670 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -54,6 +54,7 @@
#include <private/qv4global_p.h>
#include <private/qv4isel_p.h>
#include <private/qv4isel_util_p.h>
+#include <private/qv4util_p.h>
#include <private/qv4jsir_p.h>
#include <private/qv4value_p.h>
#include "qv4instr_moth_p.h"
@@ -66,7 +67,10 @@ namespace Moth {
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
- virtual void linkBackendToEngine(QV4::ExecutionEngine *engine);
+ void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
+ bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
QVector<QByteArray> codeRefs;
@@ -77,71 +81,71 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory);
~InstructionSelection();
- virtual void run(int functionIndex);
+ void run(int functionIndex) override;
protected:
- virtual QQmlRefPointer<CompiledData::CompilationUnit> backendCompileStep();
-
- virtual void visitJump(IR::Jump *);
- virtual void visitCJump(IR::CJump *);
- virtual void visitRet(IR::Ret *);
-
- virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result);
- virtual void callBuiltinTypeofQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::Expr *result);
- virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result);
- virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result);
- virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result);
- virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result);
- virtual void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result);
- virtual void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result);
- virtual void callBuiltinDeleteName(const QString &name, IR::Expr *result);
- virtual void callBuiltinDeleteValue(IR::Expr *result);
- virtual void callBuiltinThrow(IR::Expr *arg);
- virtual void callBuiltinReThrow();
- virtual void callBuiltinUnwindException(IR::Expr *);
- virtual void callBuiltinPushCatchScope(const QString &exceptionName);
- virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result);
- virtual void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result);
- virtual void callBuiltinPushWithScope(IR::Expr *arg);
- virtual void callBuiltinPopScope();
- virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
- virtual void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args);
- virtual void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray);
- virtual void callBuiltinSetupArgumentObject(IR::Expr *result);
- virtual void callBuiltinConvertThisToObject();
- virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result);
- virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result);
- virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result);
- virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result);
- virtual void convertType(IR::Expr *source, IR::Expr *target);
- virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result);
- virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result);
- virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result);
- virtual void loadThisObject(IR::Expr *e);
- virtual void loadQmlContext(IR::Expr *e);
- virtual void loadQmlImportedScripts(IR::Expr *e);
- virtual void loadQmlSingleton(const QString &name, IR::Expr *e);
- virtual void loadConst(IR::Const *sourceConst, IR::Expr *e);
- virtual void loadString(const QString &str, IR::Expr *target);
- virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target);
- virtual void getActivationProperty(const IR::Name *name, IR::Expr *target);
- virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
- virtual void initClosure(IR::Closure *closure, IR::Expr *target);
- virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target);
- virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName);
- virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex);
- virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex);
- virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target);
- virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
- virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target);
- virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex);
- virtual void copyValue(IR::Expr *source, IR::Expr *target);
- virtual void swapValues(IR::Expr *source, IR::Expr *target);
- virtual void unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target);
- virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
+ QQmlRefPointer<CompiledData::CompilationUnit> backendCompileStep() override;
+
+ void visitJump(IR::Jump *) override;
+ void visitCJump(IR::CJump *) override;
+ void visitRet(IR::Ret *) override;
+
+ void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) override;
+ void callBuiltinTypeofQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::Expr *result) override;
+ void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result) override;
+ void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) override;
+ void callBuiltinTypeofName(const QString &name, IR::Expr *result) override;
+ void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result) override;
+ void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result) override;
+ void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) override;
+ void callBuiltinDeleteName(const QString &name, IR::Expr *result) override;
+ void callBuiltinDeleteValue(IR::Expr *result) override;
+ void callBuiltinThrow(IR::Expr *arg) override;
+ void callBuiltinReThrow() override;
+ void callBuiltinUnwindException(IR::Expr *) override;
+ void callBuiltinPushCatchScope(const QString &exceptionName) override;
+ void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result) override;
+ void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result) override;
+ void callBuiltinPushWithScope(IR::Expr *arg) override;
+ void callBuiltinPopScope() override;
+ void callBuiltinDeclareVar(bool deletable, const QString &name) override;
+ void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args) override;
+ void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) override;
+ void callBuiltinSetupArgumentObject(IR::Expr *result) override;
+ void callBuiltinConvertThisToObject() override;
+ void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) override;
+ void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) override;
+ void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) override;
+ void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result) override;
+ void convertType(IR::Expr *source, IR::Expr *target) override;
+ void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result) override;
+ void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) override;
+ void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) override;
+ void loadThisObject(IR::Expr *e) override;
+ void loadQmlContext(IR::Expr *e) override;
+ void loadQmlImportedScripts(IR::Expr *e) override;
+ void loadQmlSingleton(const QString &name, IR::Expr *e) override;
+ void loadConst(IR::Const *sourceConst, IR::Expr *e) override;
+ void loadString(const QString &str, IR::Expr *target) override;
+ void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target) override;
+ void getActivationProperty(const IR::Name *name, IR::Expr *target) override;
+ void setActivationProperty(IR::Expr *source, const QString &targetName) override;
+ void initClosure(IR::Closure *closure, IR::Expr *target) override;
+ void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) override;
+ void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) override;
+ void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) override;
+ void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) override;
+ void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target) override;
+ void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target) override;
+ void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) override;
+ void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) override;
+ void copyValue(IR::Expr *source, IR::Expr *target) override;
+ void swapValues(IR::Expr *source, IR::Expr *target) override;
+ void unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target) override;
+ void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) override;
private:
Param binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
@@ -174,6 +178,8 @@ private:
template <int Instr>
inline ptrdiff_t addInstruction(const InstrData<Instr> &data);
+ inline void addDebugInstruction();
+
ptrdiff_t addInstructionHelper(Instr::Type type, Instr &instr);
void patchJumpAddresses();
QByteArray squeezeCode() const;
@@ -192,7 +198,7 @@ private:
uchar *_codeNext;
uchar *_codeEnd;
- QSet<IR::Jump *> _removableJumps;
+ BitVector _removableJumps;
IR::Stmt *_currentStatement;
QScopedPointer<CompilationUnit> compilationUnit;
@@ -202,11 +208,14 @@ private:
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
+ ISelFactory() : EvalISelFactory(QStringLiteral("moth")) {}
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
- virtual bool jitCompileRegexps() const
+ EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) Q_DECL_OVERRIDE Q_DECL_FINAL
+ { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator, this); }
+ bool jitCompileRegexps() const Q_DECL_OVERRIDE Q_DECL_FINAL
{ return false; }
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> createUnitForLoading() Q_DECL_OVERRIDE;
+
};
template<int InstrT>
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 6ba23a0951..efcfb9bd77 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -52,7 +52,7 @@
using namespace QV4;
using namespace QV4::IR;
-EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
: useFastLookups(true)
, useTypeInference(true)
, executableAllocator(execAllocator)
@@ -67,6 +67,7 @@ EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *exe
Q_ASSERT(execAllocator);
#endif
Q_ASSERT(module);
+ jsGenerator->codeGeneratorName = iselFactory->codeGeneratorName;
}
EvalInstructionSelection::~EvalInstructionSelection()
@@ -146,25 +147,24 @@ void IRDecoder::visitMove(IR::Move *s)
const int attachedPropertiesId = m->attachedPropertiesId;
const bool isSingletonProperty = m->kind == IR::Member::MemberOfSingletonObject;
- if (_function && attachedPropertiesId == 0 && !m->property->isConstant()) {
+ if (_function && attachedPropertiesId == 0 && !m->property->isConstant() && _function->isQmlBinding) {
if (m->kind == IR::Member::MemberOfQmlContextObject) {
- _function->contextObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
+ _function->contextObjectPropertyDependencies.insert(m->property->coreIndex(), m->property->notifyIndex());
captureRequired = false;
} else if (m->kind == IR::Member::MemberOfQmlScopeObject) {
- _function->scopeObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
+ _function->scopeObjectPropertyDependencies.insert(m->property->coreIndex(), m->property->notifyIndex());
captureRequired = false;
}
}
if (m->kind == IR::Member::MemberOfQmlScopeObject || m->kind == IR::Member::MemberOfQmlContextObject) {
- getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->property,
- m->property->coreIndex, s->target);
+ getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex(), captureRequired, s->target);
return;
}
- getQObjectProperty(m->base, m->property, captureRequired, isSingletonProperty, attachedPropertiesId, s->target);
+ getQObjectProperty(m->base, m->property->coreIndex(), captureRequired, isSingletonProperty, attachedPropertiesId, s->target);
#endif // V4_BOOTSTRAP
return;
} else if (m->kind == IR::Member::MemberOfIdObjectsArray) {
- getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, nullptr, m->idIndex, s->target);
+ getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->idIndex, /*captureRequired*/false, s->target);
return;
} else if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) {
getProperty(m->base, *m->name, s->target);
@@ -187,7 +187,7 @@ void IRDecoder::visitMove(IR::Move *s)
#ifndef V4_BOOTSTRAP
Q_ASSERT(member->kind != IR::Member::MemberOfIdObjectsArray);
if (member->kind == IR::Member::MemberOfQmlScopeObject || member->kind == IR::Member::MemberOfQmlContextObject) {
- callQmlContextProperty(member->base, (IR::Member::MemberKind)member->kind, member->property->coreIndex, c->args, s->target);
+ callQmlContextProperty(member->base, (IR::Member::MemberKind)member->kind, member->property->coreIndex(), c->args, s->target);
return;
}
#endif
@@ -216,10 +216,10 @@ void IRDecoder::visitMove(IR::Move *s)
Q_UNIMPLEMENTED();
#else
if (m->kind == IR::Member::MemberOfQmlScopeObject || m->kind == IR::Member::MemberOfQmlContextObject) {
- setQmlContextProperty(s->source, m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex);
+ setQmlContextProperty(s->source, m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex());
return;
}
- setQObjectProperty(s->source, m->base, m->property->coreIndex);
+ setQObjectProperty(s->source, m->base, m->property->coreIndex());
#endif
return;
} else {
@@ -263,7 +263,7 @@ void IRDecoder::visitExp(IR::Exp *s)
#ifndef V4_BOOTSTRAP
Q_ASSERT(member->kind != IR::Member::MemberOfIdObjectsArray);
if (member->kind == IR::Member::MemberOfQmlScopeObject || member->kind == IR::Member::MemberOfQmlContextObject) {
- callQmlContextProperty(member->base, (IR::Member::MemberKind)member->kind, member->property->coreIndex, c->args, 0);
+ callQmlContextProperty(member->base, (IR::Member::MemberKind)member->kind, member->property->coreIndex(), c->args, 0);
return;
}
#endif
@@ -295,7 +295,7 @@ void IRDecoder::callBuiltin(IR::Call *call, Expr *result)
if (member->kind == IR::Member::MemberOfQmlScopeObject || member->kind == IR::Member::MemberOfQmlContextObject) {
callBuiltinTypeofQmlContextProperty(member->base,
IR::Member::MemberKind(member->kind),
- member->property->coreIndex, result);
+ member->property->coreIndex(), result);
return;
}
#endif
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 2ee776adf4..037c02e5ea 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -61,18 +61,18 @@
QT_BEGIN_NAMESPACE
-class QQmlAccessors;
class QQmlEnginePrivate;
namespace QV4 {
+class EvalISelFactory;
class ExecutableAllocator;
struct Function;
class Q_QML_PRIVATE_EXPORT EvalInstructionSelection
{
public:
- EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory);
virtual ~EvalInstructionSelection() = 0;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compile(bool generateUnitData = true);
@@ -105,23 +105,44 @@ protected:
class Q_QML_PRIVATE_EXPORT EvalISelFactory
{
public:
+ EvalISelFactory(const QString &codeGeneratorName) : codeGeneratorName(codeGeneratorName) {}
virtual ~EvalISelFactory() = 0;
virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0;
virtual bool jitCompileRegexps() const = 0;
+ virtual QQmlRefPointer<QV4::CompiledData::CompilationUnit> createUnitForLoading() = 0;
+
+ const QString codeGeneratorName;
};
namespace IR {
-class Q_QML_PRIVATE_EXPORT IRDecoder: protected IR::StmtVisitor
+class Q_QML_PRIVATE_EXPORT IRDecoder
{
public:
IRDecoder() : _function(0) {}
virtual ~IRDecoder() = 0;
- virtual void visitPhi(IR::Phi *) {}
-
-public: // visitor methods for StmtVisitor:
- virtual void visitMove(IR::Move *s);
- virtual void visitExp(IR::Exp *s);
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto j = s->asJump()) {
+ visitJump(j);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+private: // visitor methods for StmtVisitor:
+ void visitMove(IR::Move *s);
+ void visitExp(IR::Exp *s);
public: // to implement by subclasses:
virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) = 0;
@@ -166,8 +187,8 @@ public: // to implement by subclasses:
virtual void setActivationProperty(IR::Expr *source, const QString &targetName) = 0;
virtual void initClosure(IR::Closure *closure, IR::Expr *target) = 0;
virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) = 0;
- virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0;
- virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target) = 0;
+ virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0;
+ virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target) = 0;
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) = 0;
virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) = 0;
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) = 0;
@@ -179,6 +200,11 @@ public: // to implement by subclasses:
virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) = 0;
protected:
+ virtual void visitJump(IR::Jump *) = 0;
+ virtual void visitCJump(IR::CJump *) = 0;
+ virtual void visitRet(IR::Ret *) = 0;
+ virtual void visitPhi(IR::Phi *) {}
+
virtual void callBuiltin(IR::Call *c, IR::Expr *result);
IR::Function *_function; // subclass needs to set
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index 674fc01623..1755193d32 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -104,7 +104,7 @@ inline Primitive convertToValue(IR::Const *c)
return Primitive::undefinedValue();
}
-class ConvertTemps: protected IR::StmtVisitor, protected IR::ExprVisitor
+class ConvertTemps
{
void renumber(IR::Temp *t)
{
@@ -132,7 +132,7 @@ protected:
virtual void process(IR::Stmt *s)
{
- s->accept(this);
+ visit(s);
}
public:
@@ -157,34 +157,28 @@ public:
}
protected:
- virtual void visitConst(IR::Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(IR::Name *) {}
- virtual void visitTemp(IR::Temp *e) { renumber(e); }
- virtual void visitArgLocal(IR::ArgLocal *) {}
- virtual void visitClosure(IR::Closure *) {}
- virtual void visitConvert(IR::Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(IR::Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(IR::Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(IR::Call *e) {
- e->base->accept(this);
- for (IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
+ void visit(IR::Stmt *s) {
+ switch (s->stmtKind) {
+ case IR::Stmt::PhiStmt:
+ visitPhi(s->asPhi());
+ break;
+ default:
+ STMT_VISIT_ALL_KINDS(s);
+ break;
+ }
}
- virtual void visitNew(IR::New *e) {
- e->base->accept(this);
- for (IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
+
+ virtual void visitPhi(IR::Phi *)
+ { Q_UNREACHABLE(); }
+
+private:
+ void visit(IR::Expr *e) {
+ if (auto temp = e->asTemp()) {
+ renumber(temp);
+ } else {
+ EXPR_VISIT_ALL_KINDS(e);
+ }
}
- virtual void visitSubscript(IR::Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(IR::Member *e) { e->base->accept(this); }
- virtual void visitExp(IR::Exp *s) { s->expr->accept(this); }
- virtual void visitMove(IR::Move *s) { s->target->accept(this); s->source->accept(this); }
- virtual void visitJump(IR::Jump *) {}
- virtual void visitCJump(IR::CJump *s) { s->cond->accept(this); }
- virtual void visitRet(IR::Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(IR::Phi *) { Q_UNREACHABLE(); }
};
} // namespace QV4
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 370dfd0fae..5687834b00 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -157,12 +157,13 @@ AluOp binaryOperator(int op)
}
}
-struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
+class RemoveSharedExpressions
{
CloneExpr clone;
std::vector<Expr *> subexpressions; // contains all the non-cloned subexpressions in the given function. sorted using std::lower_bound.
Expr *uniqueExpr;
+public:
RemoveSharedExpressions(): uniqueExpr(0) {}
void operator()(IR::Function *function)
@@ -176,11 +177,12 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
clone.setBasicBlock(block);
for (Stmt *s : block->statements()) {
- s->accept(this);
+ visit(s);
}
}
}
+private:
template <typename Expr_>
Expr_ *cleanup(Expr_ *expr)
{
@@ -189,7 +191,7 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
subexpressions.insert(it, expr);
IR::Expr *e = expr;
qSwap(uniqueExpr, e);
- expr->accept(this);
+ visit(expr);
qSwap(uniqueExpr, e);
return static_cast<Expr_ *>(e);
}
@@ -199,83 +201,45 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
return clone(expr);
}
- // statements
- virtual void visitExp(Exp *s)
+ void visit(Stmt *s)
{
- s->expr = cleanup(s->expr);
- }
-
- virtual void visitMove(Move *s)
- {
- s->target = cleanup(s->target);
- s->source = cleanup(s->source);
- }
-
- virtual void visitJump(Jump *)
- {
- // nothing to do for Jump statements
- }
-
- virtual void visitCJump(CJump *s)
- {
- s->cond = cleanup(s->cond);
- }
-
- virtual void visitRet(Ret *s)
- {
- s->expr = cleanup(s->expr);
- }
-
- virtual void visitPhi(IR::Phi *) { Q_UNIMPLEMENTED(); }
-
- // expressions
- virtual void visitConst(Const *) {}
- virtual void visitString(String *) {}
- virtual void visitRegExp(RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
-
- virtual void visitConvert(Convert *e)
- {
- e->expr = cleanup(e->expr);
- }
-
- virtual void visitUnop(Unop *e)
- {
- e->expr = cleanup(e->expr);
- }
-
- virtual void visitBinop(Binop *e)
- {
- e->left = cleanup(e->left);
- e->right = cleanup(e->right);
- }
-
- virtual void visitCall(Call *e)
- {
- e->base = cleanup(e->base);
- for (IR::ExprList *it = e->args; it; it = it->next)
- it->expr = cleanup(it->expr);
- }
-
- virtual void visitNew(New *e)
- {
- e->base = cleanup(e->base);
- for (IR::ExprList *it = e->args; it; it = it->next)
- it->expr = cleanup(it->expr);
- }
-
- virtual void visitSubscript(Subscript *e)
- {
- e->base = cleanup(e->base);
- e->index = cleanup(e->index);
+ if (auto e = s->asExp()) {
+ e->expr = cleanup(e->expr);
+ } else if (auto m = s->asMove()) {
+ m->target = cleanup(m->target);
+ m->source = cleanup(m->source);
+ } else if (auto c = s->asCJump()) {
+ c->cond = cleanup(c->cond);
+ } else if (auto r = s->asRet()) {
+ r->expr = cleanup(r->expr);
+ }
}
- virtual void visitMember(Member *e)
+ void visit(Expr *e)
{
- e->base = cleanup(e->base);
+ if (auto c = e->asConvert()) {
+ c->expr = cleanup(c->expr);
+ } else if (auto u = e->asUnop()) {
+ u->expr = cleanup(u->expr);
+ } else if (auto b = e->asBinop()) {
+ b->left = cleanup(b->left);
+ b->right = cleanup(b->right);
+ } else if (auto c = e->asCall()) {
+ c->base = cleanup(c->base);
+ for (IR::ExprList *it = c->args; it; it = it->next) {
+ it->expr = cleanup(it->expr);
+ }
+ } else if (auto n = e->asNew()) {
+ n->base = cleanup(n->base);
+ for (IR::ExprList *it = n->args; it; it = it->next) {
+ it->expr = cleanup(it->expr);
+ }
+ } else if (auto s = e->asSubscript()) {
+ s->base = cleanup(s->base);
+ s->index = cleanup(s->index);
+ } else if (auto m = e->asMember()) {
+ m->base = cleanup(m->base);
+ }
}
};
@@ -404,9 +368,10 @@ Function::Function(Module *module, Function *outer, const QString &name)
, isNamedExpression(false)
, hasTry(false)
, hasWith(false)
+ , isQmlBinding(false)
, unused(0)
- , line(-1)
- , column(-1)
+ , line(0)
+ , column(0)
, _allBasicBlocks(0)
, _statementCount(0)
{
@@ -548,75 +513,39 @@ ExprList *CloneExpr::clone(ExprList *list)
return clonedList;
}
-void CloneExpr::visitConst(Const *e)
-{
- cloned = cloneConst(e, block->function);
-}
-
-void CloneExpr::visitString(String *e)
-{
- cloned = block->STRING(e->value);
-}
-
-void CloneExpr::visitRegExp(RegExp *e)
-{
- cloned = block->REGEXP(e->value, e->flags);
-}
-
-void CloneExpr::visitName(Name *e)
-{
- cloned = cloneName(e, block->function);
-}
-
-void CloneExpr::visitTemp(Temp *e)
-{
- cloned = cloneTemp(e, block->function);
-}
-
-void CloneExpr::visitArgLocal(ArgLocal *e)
-{
- cloned = cloneArgLocal(e, block->function);
-}
-
-void CloneExpr::visitClosure(Closure *e)
-{
- cloned = block->CLOSURE(e->value);
-}
-
-void CloneExpr::visitConvert(Convert *e)
-{
- cloned = block->CONVERT(clone(e->expr), e->type);
-}
-
-void CloneExpr::visitUnop(Unop *e)
-{
- cloned = block->UNOP(e->op, clone(e->expr));
-}
-
-void CloneExpr::visitBinop(Binop *e)
-{
- cloned = block->BINOP(e->op, clone(e->left), clone(e->right));
-}
-
-void CloneExpr::visitCall(Call *e)
-{
- cloned = block->CALL(clone(e->base), clone(e->args));
-}
-
-void CloneExpr::visitNew(New *e)
-{
- cloned = block->NEW(clone(e->base), clone(e->args));
-}
-
-void CloneExpr::visitSubscript(Subscript *e)
-{
- cloned = block->SUBSCRIPT(clone(e->base), clone(e->index));
-}
-
-void CloneExpr::visitMember(Member *e)
-{
- Expr *clonedBase = clone(e->base);
- cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->idIndex);
+void CloneExpr::visit(Expr *e)
+{
+ if (auto c = e->asConst()) {
+ cloned = cloneConst(c, block->function);
+ } else if (auto s = e->asString()) {
+ cloned = block->STRING(s->value);
+ } else if (auto r = e->asRegExp()) {
+ cloned = block->REGEXP(r->value, r->flags);
+ } else if (auto n = e->asName()) {
+ cloned = cloneName(n, block->function);
+ } else if (auto t = e->asTemp()) {
+ cloned = cloneTemp(t, block->function);
+ } else if (auto a = e->asArgLocal()) {
+ cloned = cloneArgLocal(a, block->function);
+ } else if (auto c = e->asClosure()) {
+ cloned = block->CLOSURE(c->value);
+ } else if (auto c = e->asConvert()) {
+ cloned = block->CONVERT(clone(c->expr), c->type);
+ } else if (auto u = e->asUnop()) {
+ cloned = block->UNOP(u->op, clone(u->expr));
+ } else if (auto b = e->asBinop()) {
+ cloned = block->BINOP(b->op, clone(b->left), clone(b->right));
+ } else if (auto c = e->asCall()) {
+ cloned = block->CALL(clone(c->base), clone(c->args));
+ } else if (auto n = e->asNew()) {
+ cloned = block->NEW(clone(n->base), clone(n->args));
+ } else if (auto s = e->asSubscript()) {
+ cloned = block->SUBSCRIPT(clone(s->base), clone(s->index));
+ } else if (auto m = e->asMember()) {
+ cloned = block->MEMBER(clone(m->base), m->name, m->property, m->kind, m->idIndex);
+ } else {
+ Q_UNREACHABLE();
+ }
}
IRPrinter::IRPrinter(QTextStream *out)
@@ -632,17 +561,17 @@ IRPrinter::~IRPrinter()
void IRPrinter::print(Stmt *s)
{
- s->accept(this);
+ visit(s);
}
void IRPrinter::print(const Expr &e)
{
- const_cast<Expr *>(&e)->accept(this);
+ visit(const_cast<Expr *>(&e));
}
void IRPrinter::print(Expr *e)
{
- e->accept(this);
+ visit(e);
}
void IRPrinter::print(Function *f)
@@ -696,7 +625,7 @@ void IRPrinter::print(BasicBlock *bb)
QTextStream *prevOut = &os;
std::swap(out, prevOut);
addStmtNr(s);
- s->accept(this);
+ visit(s);
if (s->location.startLine) {
out->flush();
for (int i = 58 - str.length(); i > 0; --i)
@@ -713,10 +642,29 @@ void IRPrinter::print(BasicBlock *bb)
std::swap(currentBB, bb);
}
+void IRPrinter::visit(Stmt *s)
+{
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto j = s->asJump()) {
+ visitJump(j);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ } else {
+ Q_UNREACHABLE();
+ }
+}
+
void IRPrinter::visitExp(Exp *s)
{
*out << "void ";
- s->expr->accept(this);
+ visit(s->expr);
}
void IRPrinter::visitMove(Move *s)
@@ -725,13 +673,13 @@ void IRPrinter::visitMove(Move *s)
if (!s->swap && targetTemp->type != UnknownType)
*out << typeName(targetTemp->type) << ' ';
- s->target->accept(this);
+ visit(s->target);
*out << ' ';
if (s->swap)
*out << "<=> ";
else
*out << "= ";
- s->source->accept(this);
+ visit(s->source);
}
void IRPrinter::visitJump(Jump *s)
@@ -742,7 +690,7 @@ void IRPrinter::visitJump(Jump *s)
void IRPrinter::visitCJump(CJump *s)
{
*out << "if ";
- s->cond->accept(this);
+ visit(s->cond);
*out << " goto L" << s->iftrue->index()
<< " else goto L" << s->iffalse->index();
}
@@ -752,7 +700,7 @@ void IRPrinter::visitRet(Ret *s)
*out << "return";
if (s->expr) {
*out << ' ';
- s->expr->accept(this);
+ visit(s->expr);
}
}
@@ -761,7 +709,7 @@ void IRPrinter::visitPhi(Phi *s)
if (s->targetTemp->type != UnknownType)
*out << typeName(s->targetTemp->type) << ' ';
- s->targetTemp->accept(this);
+ visit(s->targetTemp);
*out << " = phi ";
for (int i = 0, ei = s->incoming.size(); i < ei; ++i) {
if (i > 0)
@@ -769,7 +717,42 @@ void IRPrinter::visitPhi(Phi *s)
if (currentBB)
*out << 'L' << currentBB->in.at(i)->index() << ": ";
if (s->incoming[i])
- s->incoming[i]->accept(this);
+ visit(s->incoming[i]);
+ }
+}
+
+void IRPrinter::visit(Expr *e)
+{
+ if (auto c = e->asConst()) {
+ visitConst(c);
+ } else if (auto s = e->asString()) {
+ visitString(s);
+ } else if (auto r = e->asRegExp()) {
+ visitRegExp(r);
+ } else if (auto n = e->asName()) {
+ visitName(n);
+ } else if (auto t = e->asTemp()) {
+ visitTemp(t);
+ } else if (auto a = e->asArgLocal()) {
+ visitArgLocal(a);
+ } else if (auto c = e->asClosure()) {
+ visitClosure(c);
+ } else if (auto c = e->asConvert()) {
+ visitConvert(c);
+ } else if (auto u = e->asUnop()) {
+ visitUnop(u);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ } else {
+ Q_UNREACHABLE();
}
}
@@ -867,32 +850,32 @@ void IRPrinter::visitClosure(Closure *e)
void IRPrinter::visitConvert(Convert *e)
{
*out << "convert " << typeName(e->expr->type) << " to " << typeName(e->type) << ' ';
- e->expr->accept(this);
+ visit(e->expr);
}
void IRPrinter::visitUnop(Unop *e)
{
*out << opname(e->op) << ' ';
- e->expr->accept(this);
+ visit(e->expr);
}
void IRPrinter::visitBinop(Binop *e)
{
*out << opname(e->op) << ' ';
- e->left->accept(this);
+ visit(e->left);
*out << ", ";
- e->right->accept(this);
+ visit(e->right);
}
void IRPrinter::visitCall(Call *e)
{
*out << "call ";
- e->base->accept(this);
+ visit(e->base);
*out << '(';
for (ExprList *it = e->args; it; it = it->next) {
if (it != e->args)
*out << ", ";
- it->expr->accept(this);
+ visit(it->expr);
}
*out << ')';
}
@@ -900,21 +883,21 @@ void IRPrinter::visitCall(Call *e)
void IRPrinter::visitNew(New *e)
{
*out << "new ";
- e->base->accept(this);
+ visit(e->base);
*out << '(';
for (ExprList *it = e->args; it; it = it->next) {
if (it != e->args)
*out << ", ";
- it->expr->accept(this);
+ visit(it->expr);
}
*out << ')';
}
void IRPrinter::visitSubscript(Subscript *e)
{
- e->base->accept(this);
+ visit(e->base);
*out << '[';
- e->index->accept(this);
+ visit(e->index);
*out << ']';
}
@@ -924,19 +907,15 @@ void IRPrinter::visitMember(Member *e)
&& e->attachedPropertiesId != 0 && !e->base->asTemp())
*out << "[[attached property from " << e->attachedPropertiesId << "]]";
else
- e->base->accept(this);
+ visit(e->base);
*out << '.' << *e->name;
#ifndef V4_BOOTSTRAP
- if (e->property) {
- *out << " (meta-property " << e->property->coreIndex
- << " <" << QMetaType::typeName(e->property->propType) << ">";
- if (e->property->hasAccessors() && e->property->isFullyResolved()) {
- *out << ", accessible";
- }
- *out << ")";
- } else if (e->kind == Member::MemberOfIdObjectsArray) {
+ if (e->property)
+ *out << " (meta-property " << e->property->coreIndex()
+ << " <" << QMetaType::typeName(e->property->propType())
+ << ">)";
+ else if (e->kind == Member::MemberOfIdObjectsArray)
*out << "(id object " << e->idIndex << ")";
- }
#endif
}
@@ -946,15 +925,15 @@ QString IRPrinter::escape(const QString &s)
for (int i = 0; i < s.length(); ++i) {
const QChar ch = s.at(i);
if (ch == QLatin1Char('\n'))
- r += QStringLiteral("\\n");
+ r += QLatin1String("\\n");
else if (ch == QLatin1Char('\r'))
- r += QStringLiteral("\\r");
+ r += QLatin1String("\\r");
else if (ch == QLatin1Char('\\'))
- r += QStringLiteral("\\\\");
+ r += QLatin1String("\\\\");
else if (ch == QLatin1Char('"'))
- r += QStringLiteral("\\\"");
+ r += QLatin1String("\\\"");
else if (ch == QLatin1Char('\''))
- r += QStringLiteral("\\'");
+ r += QLatin1String("\\'");
else
r += ch;
}
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 94fa65cf71..73aa6c4975 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -192,7 +192,7 @@ enum AluOp {
AluOp binaryOperator(int op);
const char *opname(IR::AluOp op);
-enum Type {
+enum Type : quint16 {
UnknownType = 0,
MissingType = 1 << 0,
@@ -217,34 +217,6 @@ inline bool strictlyEqualTypes(Type t1, Type t2)
QString typeName(Type t);
-struct ExprVisitor {
- virtual ~ExprVisitor() {}
- virtual void visitConst(Const *) = 0;
- virtual void visitString(String *) = 0;
- virtual void visitRegExp(RegExp *) = 0;
- virtual void visitName(Name *) = 0;
- virtual void visitTemp(Temp *) = 0;
- virtual void visitArgLocal(ArgLocal *) = 0;
- virtual void visitClosure(Closure *) = 0;
- virtual void visitConvert(Convert *) = 0;
- virtual void visitUnop(Unop *) = 0;
- virtual void visitBinop(Binop *) = 0;
- virtual void visitCall(Call *) = 0;
- virtual void visitNew(New *) = 0;
- virtual void visitSubscript(Subscript *) = 0;
- virtual void visitMember(Member *) = 0;
-};
-
-struct StmtVisitor {
- virtual ~StmtVisitor() {}
- virtual void visitExp(Exp *) = 0;
- virtual void visitMove(Move *) = 0;
- virtual void visitJump(Jump *) = 0;
- virtual void visitCJump(CJump *) = 0;
- virtual void visitRet(Ret *) = 0;
- virtual void visitPhi(Phi *) = 0;
-};
-
struct MemberExpressionResolver;
struct DiscoveredType {
@@ -288,28 +260,129 @@ struct MemberExpressionResolver
};
struct Q_AUTOTEST_EXPORT Expr {
+ enum ExprKind : quint8 {
+ NameExpr,
+ TempExpr,
+ ArgLocalExpr,
+ SubscriptExpr,
+ MemberExpr,
+
+ LastLValue = MemberExpr,
+
+ ConstExpr,
+ StringExpr,
+ RegExpExpr,
+ ClosureExpr,
+ ConvertExpr,
+ UnopExpr,
+ BinopExpr,
+ CallExpr,
+ NewExpr
+ };
+
Type type;
+ const ExprKind exprKind;
+
+ Expr &operator=(const Expr &other) {
+ Q_ASSERT(exprKind == other.exprKind);
+ type = other.type;
+ return *this;
+ }
+
+ template <typename To>
+ inline bool isa() const {
+ return To::classof(this);
+ }
- Expr(): type(UnknownType) {}
- virtual ~Expr() {}
- virtual void accept(ExprVisitor *) = 0;
- virtual bool isLValue() { return false; }
- virtual Const *asConst() { return 0; }
- virtual String *asString() { return 0; }
- virtual RegExp *asRegExp() { return 0; }
- virtual Name *asName() { return 0; }
- virtual Temp *asTemp() { return 0; }
- virtual ArgLocal *asArgLocal() { return 0; }
- virtual Closure *asClosure() { return 0; }
- virtual Convert *asConvert() { return 0; }
- virtual Unop *asUnop() { return 0; }
- virtual Binop *asBinop() { return 0; }
- virtual Call *asCall() { return 0; }
- virtual New *asNew() { return 0; }
- virtual Subscript *asSubscript() { return 0; }
- virtual Member *asMember() { return 0; }
+ template <typename To>
+ inline To *as() {
+ if (isa<To>()) {
+ return static_cast<To *>(this);
+ } else {
+ return nullptr;
+ }
+ }
+
+ template <typename To>
+ inline const To *as() const {
+ if (isa<To>()) {
+ return static_cast<const To *>(this);
+ } else {
+ return nullptr;
+ }
+ }
+
+ Expr(ExprKind exprKind): type(UnknownType), exprKind(exprKind) {}
+ bool isLValue() const;
+
+ Const *asConst() { return as<Const>(); }
+ String *asString() { return as<String>(); }
+ RegExp *asRegExp() { return as<RegExp>(); }
+ Name *asName() { return as<Name>(); }
+ Temp *asTemp() { return as<Temp>(); }
+ ArgLocal *asArgLocal() { return as<ArgLocal>(); }
+ Closure *asClosure() { return as<Closure>(); }
+ Convert *asConvert() { return as<Convert>(); }
+ Unop *asUnop() { return as<Unop>(); }
+ Binop *asBinop() { return as<Binop>(); }
+ Call *asCall() { return as<Call>(); }
+ New *asNew() { return as<New>(); }
+ Subscript *asSubscript() { return as<Subscript>(); }
+ Member *asMember() { return as<Member>(); }
};
+#define EXPR_VISIT_ALL_KINDS(e) \
+ switch (e->exprKind) { \
+ case QV4::IR::Expr::ConstExpr: \
+ break; \
+ case QV4::IR::Expr::StringExpr: \
+ break; \
+ case QV4::IR::Expr::RegExpExpr: \
+ break; \
+ case QV4::IR::Expr::NameExpr: \
+ break; \
+ case QV4::IR::Expr::TempExpr: \
+ break; \
+ case QV4::IR::Expr::ArgLocalExpr: \
+ break; \
+ case QV4::IR::Expr::ClosureExpr: \
+ break; \
+ case QV4::IR::Expr::ConvertExpr: { \
+ auto casted = e->asConvert(); \
+ visit(casted->expr); \
+ } break; \
+ case QV4::IR::Expr::UnopExpr: { \
+ auto casted = e->asUnop(); \
+ visit(casted->expr); \
+ } break; \
+ case QV4::IR::Expr::BinopExpr: { \
+ auto casted = e->asBinop(); \
+ visit(casted->left); \
+ visit(casted->right); \
+ } break; \
+ case QV4::IR::Expr::CallExpr: { \
+ auto casted = e->asCall(); \
+ visit(casted->base); \
+ for (QV4::IR::ExprList *it = casted->args; it; it = it->next) \
+ visit(it->expr); \
+ } break; \
+ case QV4::IR::Expr::NewExpr: { \
+ auto casted = e->asNew(); \
+ visit(casted->base); \
+ for (QV4::IR::ExprList *it = casted->args; it; it = it->next) \
+ visit(it->expr); \
+ } break; \
+ case QV4::IR::Expr::SubscriptExpr: { \
+ auto casted = e->asSubscript(); \
+ visit(casted->base); \
+ visit(casted->index); \
+ } break; \
+ case QV4::IR::Expr::MemberExpr: { \
+ auto casted = e->asMember(); \
+ visit(casted->base); \
+ } break; \
+ }
+
struct ExprList {
Expr *expr;
ExprList *next;
@@ -326,26 +399,28 @@ struct ExprList {
struct Const: Expr {
double value;
+ Const(): Expr(ConstExpr) {}
+
void init(Type type, double value)
{
this->type = type;
this->value = value;
}
- virtual void accept(ExprVisitor *v) { v->visitConst(this); }
- virtual Const *asConst() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == ConstExpr; }
};
struct String: Expr {
const QString *value;
+ String(): Expr(StringExpr) {}
+
void init(const QString *value)
{
this->value = value;
}
- virtual void accept(ExprVisitor *v) { v->visitString(this); }
- virtual String *asString() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == StringExpr; }
};
struct RegExp: Expr {
@@ -359,14 +434,15 @@ struct RegExp: Expr {
const QString *value;
int flags;
+ RegExp(): Expr(RegExpExpr) {}
+
void init(const QString *value, int flags)
{
this->value = value;
this->flags = flags;
}
- virtual void accept(ExprVisitor *v) { v->visitRegExp(this); }
- virtual RegExp *asRegExp() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == RegExpExpr; }
};
struct Name: Expr {
@@ -399,13 +475,13 @@ struct Name: Expr {
quint32 line;
quint32 column;
+ Name(): Expr(NameExpr) {}
+
void initGlobal(const QString *id, quint32 line, quint32 column);
void init(const QString *id, quint32 line, quint32 column);
void init(Builtin builtin, quint32 line, quint32 column);
- virtual void accept(ExprVisitor *v) { v->visitName(this); }
- virtual bool isLValue() { return true; }
- virtual Name *asName() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == NameExpr; }
};
struct Q_AUTOTEST_EXPORT Temp: Expr {
@@ -424,7 +500,8 @@ struct Q_AUTOTEST_EXPORT Temp: Expr {
MemberExpressionResolver *memberResolver;
Temp()
- : index((1 << 28) - 1)
+ : Expr(TempExpr)
+ , index((1 << 28) - 1)
, isReadOnly(0)
, kind(Invalid)
, memberResolver(0)
@@ -438,9 +515,8 @@ struct Q_AUTOTEST_EXPORT Temp: Expr {
}
bool isInvalid() const { return kind == Invalid; }
- virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
- virtual bool isLValue() { return !isReadOnly; }
- virtual Temp *asTemp() { return this; }
+
+ static bool classof(const Expr *c) { return c->exprKind == TempExpr; }
};
inline bool operator==(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
@@ -479,44 +555,48 @@ struct Q_AUTOTEST_EXPORT ArgLocal: Expr {
this->isArgumentsOrEval = false;
}
- virtual void accept(ExprVisitor *v) { v->visitArgLocal(this); }
- virtual bool isLValue() { return true; }
- virtual ArgLocal *asArgLocal() { return this; }
+ ArgLocal(): Expr(ArgLocalExpr) {}
bool operator==(const ArgLocal &other) const
{ return index == other.index && scope == other.scope && kind == other.kind; }
+
+ static bool classof(const Expr *c) { return c->exprKind == ArgLocalExpr; }
};
struct Closure: Expr {
int value; // index in _module->functions
const QString *functionName;
+ Closure(): Expr(ClosureExpr) {}
+
void init(int functionInModule, const QString *functionName)
{
this->value = functionInModule;
this->functionName = functionName;
}
- virtual void accept(ExprVisitor *v) { v->visitClosure(this); }
- virtual Closure *asClosure() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == ClosureExpr; }
};
struct Convert: Expr {
Expr *expr;
+ Convert(): Expr(ConvertExpr) {}
+
void init(Expr *expr, Type type)
{
this->expr = expr;
this->type = type;
}
- virtual void accept(ExprVisitor *v) { v->visitConvert(this); }
- virtual Convert *asConvert() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == ConvertExpr; }
};
struct Unop: Expr {
- AluOp op;
Expr *expr;
+ AluOp op;
+
+ Unop(): Expr(UnopExpr) {}
void init(AluOp op, Expr *expr)
{
@@ -524,14 +604,15 @@ struct Unop: Expr {
this->expr = expr;
}
- virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
- virtual Unop *asUnop() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == UnopExpr; }
};
struct Binop: Expr {
- AluOp op;
Expr *left; // Temp or Const
Expr *right; // Temp or Const
+ AluOp op;
+
+ Binop(): Expr(BinopExpr) {}
void init(AluOp op, Expr *left, Expr *right)
{
@@ -540,14 +621,15 @@ struct Binop: Expr {
this->right = right;
}
- virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
- virtual Binop *asBinop() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == BinopExpr; }
};
struct Call: Expr {
Expr *base; // Name, Member, Temp
ExprList *args; // List of Temps
+ Call(): Expr(CallExpr) {}
+
void init(Expr *base, ExprList *args)
{
this->base = base;
@@ -560,14 +642,15 @@ struct Call: Expr {
return 0;
}
- virtual void accept(ExprVisitor *v) { v->visitCall(this); }
- virtual Call *asCall() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == CallExpr; }
};
struct New: Expr {
Expr *base; // Name, Member, Temp
ExprList *args; // List of Temps
+ New(): Expr(NewExpr) {}
+
void init(Expr *base, ExprList *args)
{
this->base = base;
@@ -580,23 +663,22 @@ struct New: Expr {
return 0;
}
- virtual void accept(ExprVisitor *v) { v->visitNew(this); }
- virtual New *asNew() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == NewExpr; }
};
struct Subscript: Expr {
Expr *base;
Expr *index;
+ Subscript(): Expr(SubscriptExpr) {}
+
void init(Expr *base, Expr *index)
{
this->base = base;
this->index = index;
}
- virtual void accept(ExprVisitor *v) { v->visitSubscript(this); }
- virtual bool isLValue() { return true; }
- virtual Subscript *asSubscript() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == SubscriptExpr; }
};
struct Member: Expr {
@@ -628,6 +710,8 @@ struct Member: Expr {
uchar kind: 3; // MemberKind
+ Member(): Expr(MemberExpr) {}
+
void setEnumValue(int value) {
kind = MemberOfEnum;
enumValue = value;
@@ -649,35 +733,52 @@ struct Member: Expr {
this->kind = kind;
}
- virtual void accept(ExprVisitor *v) { v->visitMember(this); }
- virtual bool isLValue() { return true; }
- virtual Member *asMember() { return this; }
+ static bool classof(const Expr *c) { return c->exprKind == MemberExpr; }
};
+inline bool Expr::isLValue() const {
+ if (auto t = as<Temp>())
+ return !t->isReadOnly;
+ return exprKind <= LastLValue;
+}
+
struct Stmt {
+ enum StmtKind: quint8 {
+ MoveStmt,
+ ExpStmt,
+ JumpStmt,
+ CJumpStmt,
+ RetStmt,
+ PhiStmt
+ };
+
+ template <typename To>
+ inline bool isa() const {
+ return To::classof(this);
+ }
+
+ template <typename To>
+ inline To *as() {
+ if (isa<To>())
+ return static_cast<To *>(this);
+ else
+ return nullptr;
+ }
+
enum { InvalidId = -1 };
QQmlJS::AST::SourceLocation location;
- explicit Stmt(int id): _id(id) {}
+ explicit Stmt(int id, StmtKind stmtKind): _id(id), stmtKind(stmtKind) {}
- virtual ~Stmt()
- {
-#ifdef Q_CC_MSVC
- // MSVC complains about potential memory leaks if a destructor never returns.
-#else
- Q_UNREACHABLE();
-#endif
- }
- virtual Stmt *asTerminator() { return 0; }
+ Stmt *asTerminator();
- virtual void accept(StmtVisitor *) = 0;
- virtual Exp *asExp() { return 0; }
- virtual Move *asMove() { return 0; }
- virtual Jump *asJump() { return 0; }
- virtual CJump *asCJump() { return 0; }
- virtual Ret *asRet() { return 0; }
- virtual Phi *asPhi() { return 0; }
+ Exp *asExp() { return as<Exp>(); }
+ Move *asMove() { return as<Move>(); }
+ Jump *asJump() { return as<Jump>(); }
+ CJump *asCJump() { return as<CJump>(); }
+ Ret *asRet() { return as<Ret>(); }
+ Phi *asPhi() { return as<Phi>(); }
int id() const { return _id; }
@@ -687,21 +788,52 @@ private: // For memory management in BasicBlock
private:
friend struct Function;
int _id;
+
+public:
+ const StmtKind stmtKind;
};
+#define STMT_VISIT_ALL_KINDS(s) \
+ switch (s->stmtKind) { \
+ case QV4::IR::Stmt::MoveStmt: { \
+ auto casted = s->asMove(); \
+ visit(casted->target); \
+ visit(casted->source); \
+ } break; \
+ case QV4::IR::Stmt::ExpStmt: { \
+ auto casted = s->asExp(); \
+ visit(casted->expr); \
+ } break; \
+ case QV4::IR::Stmt::JumpStmt: \
+ break; \
+ case QV4::IR::Stmt::CJumpStmt: { \
+ auto casted = s->asCJump(); \
+ visit(casted->cond); \
+ } break; \
+ case QV4::IR::Stmt::RetStmt: { \
+ auto casted = s->asRet(); \
+ visit(casted->expr); \
+ } break; \
+ case QV4::IR::Stmt::PhiStmt: { \
+ auto casted = s->asPhi(); \
+ visit(casted->targetTemp); \
+ for (auto *e : casted->incoming) { \
+ visit(e); \
+ } \
+ } break; \
+ }
+
struct Exp: Stmt {
Expr *expr;
- Exp(int id): Stmt(id) {}
+ Exp(int id): Stmt(id, ExpStmt) {}
void init(Expr *expr)
{
this->expr = expr;
}
- virtual void accept(StmtVisitor *v) { v->visitExp(this); }
- virtual Exp *asExp() { return this; }
-
+ static bool classof(const Stmt *c) { return c->stmtKind == ExpStmt; }
};
struct Move: Stmt {
@@ -709,7 +841,7 @@ struct Move: Stmt {
Expr *source;
bool swap;
- Move(int id): Stmt(id) {}
+ Move(int id): Stmt(id, MoveStmt) {}
void init(Expr *target, Expr *source)
{
@@ -718,25 +850,20 @@ struct Move: Stmt {
this->swap = false;
}
- virtual void accept(StmtVisitor *v) { v->visitMove(this); }
- virtual Move *asMove() { return this; }
-
+ static bool classof(const Stmt *c) { return c->stmtKind == MoveStmt; }
};
struct Jump: Stmt {
BasicBlock *target;
- Jump(int id): Stmt(id) {}
+ Jump(int id): Stmt(id, JumpStmt) {}
void init(BasicBlock *target)
{
this->target = target;
}
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitJump(this); }
- virtual Jump *asJump() { return this; }
+ static bool classof(const Stmt *c) { return c->stmtKind == JumpStmt; }
};
struct CJump: Stmt {
@@ -745,7 +872,7 @@ struct CJump: Stmt {
BasicBlock *iffalse;
BasicBlock *parent;
- CJump(int id): Stmt(id) {}
+ CJump(int id): Stmt(id, CJumpStmt) {}
void init(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse, BasicBlock *parent)
{
@@ -755,26 +882,20 @@ struct CJump: Stmt {
this->parent = parent;
}
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitCJump(this); }
- virtual CJump *asCJump() { return this; }
+ static bool classof(const Stmt *c) { return c->stmtKind == CJumpStmt; }
};
struct Ret: Stmt {
Expr *expr;
- Ret(int id): Stmt(id) {}
+ Ret(int id): Stmt(id, RetStmt) {}
void init(Expr *expr)
{
this->expr = expr;
}
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitRet(this); }
- virtual Ret *asRet() { return this; }
+ static bool classof(const Stmt *c) { return c->stmtKind == RetStmt; }
};
// Phi nodes can only occur at the start of a basic block. If there are any, they need to be
@@ -785,30 +906,54 @@ struct Phi: Stmt {
Temp *targetTemp;
VarLengthArray<Expr *, 4> incoming;
- Phi(int id): Stmt(id) {}
+ Phi(int id): Stmt(id, PhiStmt) {}
- virtual void accept(StmtVisitor *v) { v->visitPhi(this); }
- virtual Phi *asPhi() { return this; }
+ static bool classof(const Stmt *c) { return c->stmtKind == PhiStmt; }
void destroyData()
{ incoming.~VarLengthArray(); }
};
+inline Stmt *Stmt::asTerminator()
+{
+ if (auto s = asJump()) {
+ return s;
+ } else if (auto s = asCJump()) {
+ return s;
+ } else if (auto s = asRet()) {
+ return s;
+ } else {
+ return nullptr;
+ }
+}
+
struct Q_QML_PRIVATE_EXPORT Module {
QQmlJS::MemoryPool pool;
QVector<Function *> functions;
Function *rootFunction;
QString fileName;
+ qint64 sourceTimeStamp;
bool isQmlModule; // implies rootFunction is always 0
+ uint unitFlags; // flags merged into CompiledData::Unit::flags
+#ifdef QT_NO_QML_DEBUGGER
+ static const bool debugMode = false;
+#else
bool debugMode;
+#endif
Function *newFunction(const QString &name, Function *outer);
Module(bool debugMode)
: rootFunction(0)
+ , sourceTimeStamp(0)
, isQmlModule(false)
+ , unitFlags(0)
+#ifndef QT_NO_QML_DEBUGGER
, debugMode(debugMode)
{}
+#else
+ { Q_UNUSED(debugMode); }
+#endif
~Module();
void setFileName(const QString &name);
@@ -1060,6 +1205,20 @@ private:
unsigned _isRemoved : 1;
};
+template <typename T>
+class SmallSet: public QVarLengthArray<T, 8>
+{
+public:
+ void insert(int value)
+ {
+ for (auto it : *this) {
+ if (it == value)
+ return;
+ }
+ this->append(value);
+ }
+};
+
// Map from meta property index (existence implies dependency) to notify signal index
struct KeyValuePair
{
@@ -1125,14 +1284,15 @@ struct Function {
uint isNamedExpression : 1;
uint hasTry: 1;
uint hasWith: 1;
- uint unused : 25;
+ uint isQmlBinding: 1;
+ uint unused : 24;
- // Location of declaration in source code (-1 if not specified)
- int line;
- int column;
+ // Location of declaration in source code (0 if not specified)
+ uint line;
+ uint column;
// Qml extension:
- QSet<int> idObjectDependencies;
+ SmallSet<int> idObjectDependencies;
PropertyDependencyMap contextObjectPropertyDependencies;
PropertyDependencyMap scopeObjectPropertyDependencies;
@@ -1192,7 +1352,7 @@ private:
int _statementCount;
};
-class CloneExpr: protected IR::ExprVisitor
+class CloneExpr
{
public:
explicit CloneExpr(IR::BasicBlock *block = 0);
@@ -1210,7 +1370,7 @@ public:
{
Expr *c = expr;
qSwap(cloned, c);
- expr->accept(this);
+ visit(expr);
qSwap(cloned, c);
return static_cast<ExprSubclass *>(c);
}
@@ -1253,23 +1413,10 @@ public:
return newArgLocal;
}
-protected:
+private:
IR::ExprList *clone(IR::ExprList *list);
- virtual void visitConst(Const *);
- virtual void visitString(String *);
- virtual void visitRegExp(RegExp *);
- virtual void visitName(Name *);
- virtual void visitTemp(Temp *);
- virtual void visitArgLocal(ArgLocal *);
- virtual void visitClosure(Closure *);
- virtual void visitConvert(Convert *);
- virtual void visitUnop(Unop *);
- virtual void visitBinop(Binop *);
- virtual void visitCall(Call *);
- virtual void visitNew(New *);
- virtual void visitSubscript(Subscript *);
- virtual void visitMember(Member *);
+ void visit(Expr *e);
protected:
IR::BasicBlock *block;
@@ -1278,7 +1425,7 @@ private:
IR::Expr *cloned;
};
-class Q_AUTOTEST_EXPORT IRPrinter: public StmtVisitor, public ExprVisitor
+class Q_AUTOTEST_EXPORT IRPrinter
{
public:
IRPrinter(QTextStream *out);
@@ -1291,6 +1438,7 @@ public:
virtual void print(Function *f);
virtual void print(BasicBlock *bb);
+ void visit(Stmt *s);
virtual void visitExp(Exp *s);
virtual void visitMove(Move *s);
virtual void visitJump(Jump *s);
@@ -1298,6 +1446,7 @@ public:
virtual void visitRet(Ret *s);
virtual void visitPhi(Phi *s);
+ void visit(Expr *e);
virtual void visitConst(Const *e);
virtual void visitString(String *e);
virtual void visitRegExp(RegExp *e);
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 6965d839ab..a98cf6d338 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -642,7 +642,7 @@ public:
qout << from;
else
qout << "(none)";
- qout << " -> " << to->index() << endl;
+ qout << " dominates " << to->index() << endl;
}
qDebug("%s", buf.data().constData());
}
@@ -740,6 +740,21 @@ public:
return order;
}
+ void mergeIntoPredecessor(BasicBlock *successor)
+ {
+ int succIdx = successor->index();
+ if (succIdx == InvalidBasicBlockIndex) {
+ return;
+ }
+
+ int succDom = idom[unsigned(succIdx)];
+ for (BasicBlockIndex &idx : idom) {
+ if (idx == succIdx) {
+ idx = succDom;
+ }
+ }
+ }
+
private:
bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const {
// dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
@@ -898,7 +913,7 @@ private:
}
};
-class VariableCollector: public StmtVisitor, ExprVisitor {
+class VariableCollector {
std::vector<Temp> _allTemps;
std::vector<BasicBlockSet> _defsites;
std::vector<std::vector<int> > A_orig;
@@ -946,7 +961,7 @@ public:
currentBB = bb;
killed.assign(function->tempCount, false);
for (Stmt *s : bb->statements())
- s->accept(this);
+ visit(s);
}
}
@@ -971,62 +986,45 @@ public:
return nonLocals.at(var.index);
}
-protected:
- virtual void visitPhi(Phi *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
-
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { e->base->accept(this); }
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
-
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitMove(Move *s) {
- s->source->accept(this);
+private:
+ void visit(Stmt *s)
+ {
+ if (s->asPhi()) {
+ // nothing to do
+ } else if (auto move = s->asMove()) {
+ visit(move->source);
- if (Temp *t = s->target->asTemp()) {
- addTemp(t);
+ if (Temp *t = move->target->asTemp()) {
+ addTemp(t);
- if (isCollectable(t)) {
- _defsites[t->index].insert(currentBB);
- addDefInCurrentBlock(t);
+ if (isCollectable(t)) {
+ _defsites[t->index].insert(currentBB);
+ addDefInCurrentBlock(t);
- // For semi-pruned SSA:
- killed.setBit(t->index);
+ // For semi-pruned SSA:
+ killed.setBit(t->index);
+ }
+ } else {
+ visit(move->target);
}
} else {
- s->target->accept(this);
+ STMT_VISIT_ALL_KINDS(s)
}
}
- virtual void visitTemp(Temp *t)
+ void visit(Expr *e)
{
- addTemp(t);
+ if (auto t = e->asTemp()) {
+ addTemp(t);
- if (isCollectable(t))
- if (!killed.at(t->index))
- nonLocals.setBit(t->index);
+ if (isCollectable(t)) {
+ if (!killed.at(t->index)) {
+ nonLocals.setBit(t->index);
+ }
+ }
+ } else {
+ EXPR_VISIT_ALL_KINDS(e);
+ }
}
};
@@ -1125,7 +1123,7 @@ public:
{
QVector<UntypedTemp> res;
res.reserve(tempCount());
- foreach (const DefUse &du, _defUses)
+ for (const DefUse &du : _defUses)
if (du.isValid())
res.append(UntypedTemp(du.temp));
return res;
@@ -1152,7 +1150,7 @@ public:
{
Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size());
QVector<Stmt *> &uses = _defUses[variable.index].uses;
- foreach (Stmt *stmt, newUses)
+ for (Stmt *stmt : newUses)
if (std::find(uses.begin(), uses.end(), stmt) == uses.end())
uses.push_back(stmt);
}
@@ -1192,6 +1190,15 @@ public:
return _defUses[variable.index].blockOfStatement;
}
+ void replaceBasicBlock(BasicBlock *from, BasicBlock *to)
+ {
+ for (auto &du : _defUses) {
+ if (du.blockOfStatement == from) {
+ du.blockOfStatement = to;
+ }
+ }
+ }
+
void removeUse(Stmt *usingStmt, const Temp &var)
{
Q_ASSERT(static_cast<unsigned>(var.index) < _defUses.size());
@@ -1219,7 +1226,7 @@ public:
QVector<Stmt*> removeDefUses(Stmt *s)
{
QVector<Stmt*> defStmts;
- foreach (const Temp &usedVar, usedVars(s)) {
+ for (const Temp &usedVar : usedVars(s)) {
if (Stmt *ds = defStmt(usedVar))
defStmts += ds;
removeUse(s, usedVar);
@@ -1240,7 +1247,7 @@ public:
buf.open(QIODevice::WriteOnly);
QTextStream qout(&buf);
qout << "Defines and uses:" << endl;
- foreach (const DefUse &du, _defUses) {
+ for (const DefUse &du : _defUses) {
if (!du.isValid())
continue;
qout << '%' << du.temp.index;
@@ -1248,14 +1255,14 @@ public:
<< ", statement: " << du.defStmt->id()
<< endl;
qout << " uses:";
- foreach (Stmt *s, du.uses)
+ for (Stmt *s : du.uses)
qout << ' ' << s->id();
qout << endl;
}
qout << "Uses per statement:" << endl;
for (size_t i = 0, ei = _usesPerStatement.size(); i != ei; ++i) {
qout << " " << i << ":";
- foreach (const Temp &t, _usesPerStatement[i])
+ for (const Temp &t : _usesPerStatement[i])
qout << ' ' << t.index;
qout << endl;
}
@@ -1345,7 +1352,7 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) {
//
// Undo(t, c) =
// mapping[t] = c
-class VariableRenamer: public StmtVisitor, public ExprVisitor
+class VariableRenamer
{
Q_DISABLE_COPY(VariableRenamer)
@@ -1466,7 +1473,7 @@ private:
for (Stmt *s : bb->statements()) {
currentStmt = s;
- s->accept(this);
+ visit(s);
}
for (BasicBlock *Y : bb->out) {
@@ -1532,23 +1539,35 @@ private:
return newIndex;
}
-protected:
- virtual void visitTemp(Temp *e) { // only called for uses, not defs
-// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top();
- e->index = currentNumber(*e);
- e->kind = Temp::VirtualRegister;
- defUses.addUse(*e, currentStmt);
- }
+private:
+ void visit(Stmt *s)
+ {
+ if (auto move = s->asMove()) {
+ // uses:
+ visit(move->source);
- virtual void visitMove(Move *s) {
- // uses:
- s->source->accept(this);
+ // defs:
+ if (Temp *t = move->target->asTemp()) {
+ renameTemp(t);
+ } else {
+ visit(move->target);
+ }
+ } else if (auto phi = s->asPhi()) {
+ renameTemp(phi->targetTemp);
+ } else {
+ STMT_VISIT_ALL_KINDS(s);
+ }
+ }
- // defs:
- if (Temp *t = s->target->asTemp())
- renameTemp(t);
- else
- s->target->accept(this);
+ void visit(Expr *e)
+ {
+ if (auto temp = e->asTemp()) {
+ temp->index = currentNumber(*temp);
+ temp->kind = Temp::VirtualRegister;
+ defUses.addUse(*temp, currentStmt);
+ } else {
+ EXPR_VISIT_ALL_KINDS(e);
+ }
}
void renameTemp(Temp *t) { // only called for defs, not uses
@@ -1558,44 +1577,6 @@ protected:
t->index = newIdx;
defUses.addDef(t, currentStmt, currentBB);
}
-
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitPhi(Phi *s) { renameTemp(s->targetTemp); }
-
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
-
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
-
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitSubscript(Subscript *e) {
- e->base->accept(this);
- e->index->accept(this);
- }
-
- virtual void visitMember(Member *e) {
- e->base->accept(this);
- }
};
// This function converts the IR to semi-pruned SSA form. For details about SSA and the algorightm,
@@ -1652,7 +1633,7 @@ bool hasPhiOnlyUses(Phi *phi, const DefUses &defUses, QBitArray &collectedPhis)
{
collectedPhis.setBit(phi->id());
- foreach (Stmt *use, defUses.uses(*phi->targetTemp)) {
+ for (Stmt *use : defUses.uses(*phi->targetTemp)) {
Phi *dependentPhi = use->asPhi();
if (!dependentPhi)
return false; // there is a use by a non-phi node
@@ -1698,7 +1679,7 @@ void cleanupPhis(DefUses &defUses)
const Temp &targetVar = *phi->targetTemp;
defUses.defStmtBlock(targetVar)->removeStatement(phi);
- foreach (const Temp &usedVar, defUses.usedVars(phi))
+ for (const Temp &usedVar : defUses.usedVars(phi))
defUses.removeUse(phi, usedVar);
defUses.removeDef(targetVar);
}
@@ -1748,7 +1729,7 @@ public:
worklist.assign(worklist.size(), false);
worklistSize = 0;
- foreach (Stmt *s, stmts) {
+ for (Stmt *s : stmts) {
if (!s)
continue;
@@ -1821,7 +1802,7 @@ public:
StatementWorklist &operator+=(const QVector<Stmt *> &stmts)
{
- foreach (Stmt *s, stmts)
+ for (Stmt *s : stmts)
this->operator+=(s);
return *this;
@@ -1922,7 +1903,7 @@ private:
}
};
-class SideEffectsChecker: public ExprVisitor
+class SideEffectsChecker
{
bool _sideEffect;
@@ -1931,11 +1912,14 @@ public:
: _sideEffect(false)
{}
+ ~SideEffectsChecker()
+ {}
+
bool hasSideEffects(Expr *expr)
{
bool sideEffect = false;
qSwap(_sideEffect, sideEffect);
- expr->accept(this);
+ visit(expr);
qSwap(_sideEffect, sideEffect);
return sideEffect;
}
@@ -1948,12 +1932,35 @@ protected:
bool seenSideEffects() const { return _sideEffect; }
-protected:
- void visitConst(Const *) Q_DECL_OVERRIDE {}
- void visitString(IR::String *) Q_DECL_OVERRIDE {}
- void visitRegExp(IR::RegExp *) Q_DECL_OVERRIDE {}
+ void visit(Expr *e)
+ {
+ if (auto n = e->asName()) {
+ visitName(n);
+ } else if (auto t = e->asTemp()) {
+ visitTemp(t);
+ } else if (auto c = e->asClosure()) {
+ visitClosure(c);
+ } else if (auto c = e->asConvert()) {
+ visitConvert(c);
+ } else if (auto u = e->asUnop()) {
+ visitUnop(u);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ }
+ }
+
+ virtual void visitTemp(Temp *) {}
- void visitName(Name *e) Q_DECL_OVERRIDE {
+private:
+ void visitName(Name *e) {
if (e->freeOfSideEffects)
return;
// TODO: maybe we can distinguish between built-ins of which we know that they do not have
@@ -1962,15 +1969,12 @@ protected:
markAsSideEffect();
}
- void visitTemp(Temp *) Q_DECL_OVERRIDE {}
- void visitArgLocal(ArgLocal *) Q_DECL_OVERRIDE {}
-
- void visitClosure(Closure *) Q_DECL_OVERRIDE {
+ void visitClosure(Closure *) {
markAsSideEffect();
}
- void visitConvert(Convert *e) Q_DECL_OVERRIDE {
- e->expr->accept(this);
+ void visitConvert(Convert *e) {
+ visit(e->expr);
switch (e->expr->type) {
case QObjectType:
@@ -1983,8 +1987,8 @@ protected:
}
}
- void visitUnop(Unop *e) Q_DECL_OVERRIDE {
- e->expr->accept(this);
+ void visitUnop(Unop *e) {
+ visit(e->expr);
switch (e->op) {
case OpUPlus:
@@ -2001,7 +2005,7 @@ protected:
}
}
- void visitBinop(Binop *e) Q_DECL_OVERRIDE {
+ void visitBinop(Binop *e) {
// TODO: prune parts that don't have a side-effect. For example, in:
// function f(x) { +x+1; return 0; }
// we can prune the binop and leave the unop/conversion.
@@ -2013,30 +2017,30 @@ protected:
markAsSideEffect();
}
- void visitSubscript(Subscript *e) Q_DECL_OVERRIDE {
- e->base->accept(this);
- e->index->accept(this);
+ void visitSubscript(Subscript *e) {
+ visit(e->base);
+ visit(e->index);
markAsSideEffect();
}
- void visitMember(Member *e) Q_DECL_OVERRIDE {
- e->base->accept(this);
+ void visitMember(Member *e) {
+ visit(e->base);
if (e->freeOfSideEffects)
return;
markAsSideEffect();
}
- void visitCall(Call *e) Q_DECL_OVERRIDE {
- e->base->accept(this);
+ void visitCall(Call *e) {
+ visit(e->base);
for (ExprList *args = e->args; args; args = args->next)
- args->expr->accept(this);
+ visit(args->expr);
markAsSideEffect(); // TODO: there are built-in functions that have no side effect.
}
- void visitNew(New *e) Q_DECL_OVERRIDE {
- e->base->accept(this);
+ void visitNew(New *e) {
+ visit(e->base);
for (ExprList *args = e->args; args; args = args->next)
- args->expr->accept(this);
+ visit(args->expr);
markAsSideEffect(); // TODO: there are built-in types that have no side effect.
}
};
@@ -2045,21 +2049,19 @@ class EliminateDeadCode: public SideEffectsChecker
{
DefUses &_defUses;
StatementWorklist &_worklist;
- QVector<Temp *> _collectedTemps;
+ QVarLengthArray<Temp *, 8> _collectedTemps;
public:
EliminateDeadCode(DefUses &defUses, StatementWorklist &worklist)
: _defUses(defUses)
, _worklist(worklist)
- {
- _collectedTemps.reserve(8);
- }
+ {}
void run(Expr *&expr, Stmt *stmt) {
_collectedTemps.clear();
if (!hasSideEffects(expr)) {
expr = 0;
- foreach (Temp *t, _collectedTemps) {
+ for (Temp *t : _collectedTemps) {
_defUses.removeUse(stmt, *t);
_worklist += _defUses.defStmt(*t);
}
@@ -2067,13 +2069,13 @@ public:
}
protected:
- void visitTemp(Temp *e) Q_DECL_OVERRIDE
+ void visitTemp(Temp *e) Q_DECL_OVERRIDE Q_DECL_FINAL
{
_collectedTemps.append(e);
}
};
-class PropagateTempTypes: public StmtVisitor, ExprVisitor
+class PropagateTempTypes
{
const DefUses &defUses;
UntypedTemp theTemp;
@@ -2089,64 +2091,31 @@ public:
newType = type;
theTemp = temp;
if (Stmt *defStmt = defUses.defStmt(temp.temp))
- defStmt->accept(this);
- foreach (Stmt *use, defUses.uses(temp.temp))
- use->accept(this);
- }
-
-protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *e) {
- if (theTemp == UntypedTemp(*e)) {
- e->type = static_cast<Type>(newType.type);
- e->memberResolver = newType.memberResolver;
- }
- }
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
-
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitSubscript(Subscript *e) {
- e->base->accept(this);
- e->index->accept(this);
+ visit(defStmt);
+ for (Stmt *use : defUses.uses(temp.temp))
+ visit(use);
}
- virtual void visitMember(Member *e) {
- e->base->accept(this);
- }
-
- virtual void visitExp(Exp *s) {s->expr->accept(this);}
- virtual void visitMove(Move *s) {
- s->source->accept(this);
- s->target->accept(this);
+private:
+ void visit(Stmt *s)
+ {
+ STMT_VISIT_ALL_KINDS(s);
}
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(Phi *s) {
- s->targetTemp->accept(this);
- foreach (Expr *e, s->incoming)
- e->accept(this);
+ void visit(Expr *e)
+ {
+ if (auto temp = e->asTemp()) {
+ if (theTemp == UntypedTemp(*temp)) {
+ temp->type = static_cast<Type>(newType.type);
+ temp->memberResolver = newType.memberResolver;
+ }
+ } else {
+ EXPR_VISIT_ALL_KINDS(e);
+ }
}
};
-class TypeInference: public StmtVisitor, public ExprVisitor
+class TypeInference
{
enum { DebugTypeInference = 0 };
@@ -2248,7 +2217,7 @@ private:
TypingResult ty;
std::swap(_ty, ty);
std::swap(_currentStmt, s);
- _currentStmt->accept(this);
+ visit(_currentStmt);
std::swap(_currentStmt, s);
std::swap(_ty, ty);
return ty.fullyTyped;
@@ -2257,7 +2226,7 @@ private:
TypingResult run(Expr *e) {
TypingResult ty;
std::swap(_ty, ty);
- e->accept(this);
+ visit(e);
std::swap(_ty, ty);
if (ty.type != UnknownType)
@@ -2277,7 +2246,7 @@ private:
it = ty;
if (DebugTypeInference) {
- foreach (Stmt *s, _defUses.uses(*t)) {
+ for (Stmt *s : _defUses.uses(*t)) {
QBuffer buf;
buf.open(QIODevice::WriteOnly);
QTextStream qout(&buf);
@@ -2299,39 +2268,74 @@ private:
}
}
-protected:
- virtual void visitConst(Const *e) {
- if (e->type & NumberType) {
- if (canConvertToSignedInteger(e->value))
+private:
+ void visit(Expr *e)
+ {
+ if (auto c = e->asConst()) {
+ visitConst(c);
+ } else if (auto s = e->asString()) {
+ visitString(s);
+ } else if (auto r = e->asRegExp()) {
+ visitRegExp(r);
+ } else if (auto n = e->asName()) {
+ visitName(n);
+ } else if (auto t = e->asTemp()) {
+ visitTemp(t);
+ } else if (auto a = e->asArgLocal()) {
+ visitArgLocal(a);
+ } else if (auto c = e->asClosure()) {
+ visitClosure(c);
+ } else if (auto c = e->asConvert()) {
+ visitConvert(c);
+ } else if (auto u = e->asUnop()) {
+ visitUnop(u);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ void visitConst(Const *c) {
+ if (c->type & NumberType) {
+ if (canConvertToSignedInteger(c->value))
_ty = TypingResult(SInt32Type);
- else if (canConvertToUnsignedInteger(e->value))
+ else if (canConvertToUnsignedInteger(c->value))
_ty = TypingResult(UInt32Type);
else
- _ty = TypingResult(e->type);
+ _ty = TypingResult(c->type);
} else
- _ty = TypingResult(e->type);
+ _ty = TypingResult(c->type);
}
- virtual void visitString(IR::String *) { _ty = TypingResult(StringType); }
- virtual void visitRegExp(IR::RegExp *) { _ty = TypingResult(VarType); }
- virtual void visitName(Name *) { _ty = TypingResult(VarType); }
- virtual void visitTemp(Temp *e) {
+ void visitString(IR::String *) { _ty = TypingResult(StringType); }
+ void visitRegExp(IR::RegExp *) { _ty = TypingResult(VarType); }
+ void visitName(Name *) { _ty = TypingResult(VarType); }
+ void visitTemp(Temp *e) {
if (e->memberResolver && e->memberResolver->isValid())
_ty = TypingResult(e->memberResolver);
else
_ty = TypingResult(_tempTypes[e->index]);
setType(e, _ty.type);
}
- virtual void visitArgLocal(ArgLocal *e) {
+ void visitArgLocal(ArgLocal *e) {
_ty = TypingResult(VarType);
setType(e, _ty.type);
}
- virtual void visitClosure(Closure *) { _ty = TypingResult(VarType); }
- virtual void visitConvert(Convert *e) {
+ void visitClosure(Closure *) { _ty = TypingResult(VarType); }
+ void visitConvert(Convert *e) {
_ty = TypingResult(e->type);
}
- virtual void visitUnop(Unop *e) {
+ void visitUnop(Unop *e) {
_ty = run(e->expr);
switch (e->op) {
case OpUPlus: _ty.type = DoubleType; return;
@@ -2348,7 +2352,7 @@ protected:
}
}
- virtual void visitBinop(Binop *e) {
+ void visitBinop(Binop *e) {
TypingResult leftTy = run(e->left);
TypingResult rightTy = run(e->right);
_ty.fullyTyped = leftTy.fullyTyped && rightTy.fullyTyped;
@@ -2406,24 +2410,24 @@ protected:
}
}
- virtual void visitCall(Call *e) {
+ void visitCall(Call *e) {
_ty = run(e->base);
for (ExprList *it = e->args; it; it = it->next)
_ty.fullyTyped &= run(it->expr).fullyTyped;
_ty.type = VarType;
}
- virtual void visitNew(New *e) {
+ void visitNew(New *e) {
_ty = run(e->base);
for (ExprList *it = e->args; it; it = it->next)
_ty.fullyTyped &= run(it->expr).fullyTyped;
_ty.type = VarType;
}
- virtual void visitSubscript(Subscript *e) {
+ void visitSubscript(Subscript *e) {
_ty.fullyTyped = run(e->base).fullyTyped && run(e->index).fullyTyped;
_ty.type = VarType;
}
- virtual void visitMember(Member *e) {
+ void visitMember(Member *e) {
_ty = run(e->base);
if (_ty.fullyTyped && _ty.type.memberResolver && _ty.type.memberResolver->isValid()) {
@@ -2433,8 +2437,27 @@ protected:
_ty.type = VarType;
}
- virtual void visitExp(Exp *s) { _ty = run(s->expr); }
- virtual void visitMove(Move *s) {
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto j = s->asJump()) {
+ visitJump(j);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ void visitExp(Exp *s) { _ty = run(s->expr); }
+ void visitMove(Move *s) {
if (Temp *t = s->target->asTemp()) {
if (Name *n = s->source->asName()) {
if (n->builtin == Name::builtin_qml_context) {
@@ -2455,10 +2478,10 @@ protected:
_ty.fullyTyped &= sourceTy.fullyTyped;
}
- virtual void visitJump(Jump *) { _ty = TypingResult(MissingType); }
- virtual void visitCJump(CJump *s) { _ty = run(s->cond); }
- virtual void visitRet(Ret *s) { _ty = run(s->expr); }
- virtual void visitPhi(Phi *s) {
+ void visitJump(Jump *) { _ty = TypingResult(MissingType); }
+ void visitCJump(CJump *s) { _ty = run(s->cond); }
+ void visitRet(Ret *s) { _ty = run(s->expr); }
+ void visitPhi(Phi *s) {
_ty = run(s->incoming[0]);
for (int i = 1, ei = s->incoming.size(); i != ei; ++i) {
TypingResult ty = run(s->incoming[i]);
@@ -2583,7 +2606,7 @@ public:
}
PropagateTempTypes propagator(_defUses);
- foreach (const UntypedTemp &t, knownOk) {
+ for (const UntypedTemp &t : qAsConst(knownOk)) {
propagator.run(t, SInt32Type);
if (Stmt *defStmt = _defUses.defStmt(t.temp)) {
if (Move *m = defStmt->asMove()) {
@@ -2607,7 +2630,7 @@ private:
if (uses.isEmpty())
return false;
- foreach (Stmt *use, uses) {
+ for (Stmt *use : uses) {
if (Move *m = use->asMove()) {
Temp *targetTemp = m->target->asTemp();
@@ -2677,14 +2700,15 @@ void convertConst(Const *c, Type targetType)
c->type = targetType;
}
-class TypePropagation: public StmtVisitor, public ExprVisitor {
+class TypePropagation
+{
DefUses &_defUses;
Type _ty;
IR::Function *_f;
bool run(Expr *&e, Type requestedType = UnknownType, bool insertConversion = true) {
qSwap(_ty, requestedType);
- e->accept(this);
+ visit(e);
qSwap(_ty, requestedType);
if (requestedType != UnknownType) {
@@ -2731,7 +2755,7 @@ public:
for (Stmt *s : bb->statements()) {
_currStmt = s;
- s->accept(this);
+ visit(s);
}
foreach (const Conversion &conversion, _conversions) {
@@ -2817,8 +2841,29 @@ public:
}
}
-protected:
- virtual void visitConst(Const *c) {
+private:
+ void visit(Expr *e)
+ {
+ if (auto c = e->asConst()) {
+ visitConst(c);
+ } else if (auto c = e->asConvert()) {
+ run(c->expr, c->type);
+ } else if (auto u = e->asUnop()) {
+ run(u->expr, u->type);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ }
+ }
+
+ void visitConst(Const *c) {
if (_ty & NumberType && c->type & NumberType) {
if (_ty == SInt32Type)
c->value = QV4::Primitive::toInt32(c->value);
@@ -2828,15 +2873,7 @@ protected:
}
}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { run(e->expr, e->type); }
- virtual void visitUnop(Unop *e) { run(e->expr, e->type); }
- virtual void visitBinop(Binop *e) {
+ void visitBinop(Binop *e) {
// FIXME: This routine needs more tuning!
switch (e->op) {
case OpAdd:
@@ -2887,20 +2924,36 @@ protected:
Q_UNREACHABLE();
}
}
- virtual void visitCall(Call *e) {
+ void visitCall(Call *e) {
run(e->base);
for (ExprList *it = e->args; it; it = it->next)
run(it->expr);
}
- virtual void visitNew(New *e) {
+ void visitNew(New *e) {
run(e->base);
for (ExprList *it = e->args; it; it = it->next)
run(it->expr);
}
- virtual void visitSubscript(Subscript *e) { run(e->base); run(e->index); }
- virtual void visitMember(Member *e) { run(e->base); }
- virtual void visitExp(Exp *s) { run(s->expr); }
- virtual void visitMove(Move *s) {
+ void visitSubscript(Subscript *e) { run(e->base); run(e->index); }
+ void visitMember(Member *e) { run(e->base); }
+
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ }
+ }
+
+ void visitExp(Exp *s) { run(s->expr); }
+ void visitMove(Move *s) {
if (s->source->asConvert())
return; // this statement got inserted for a phi-node type conversion
@@ -2925,12 +2978,11 @@ protected:
run(s->source, s->target->type, !inhibitConversion);
}
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) {
+ void visitCJump(CJump *s) {
run(s->cond, BoolType);
}
- virtual void visitRet(Ret *s) { run(s->expr); }
- virtual void visitPhi(Phi *s) {
+ void visitRet(Ret *s) { run(s->expr); }
+ void visitPhi(Phi *s) {
Type ty = s->targetTemp->type;
for (int i = 0, ei = s->incoming.size(); i != ei; ++i)
run(s->incoming[i], ty);
@@ -3113,7 +3165,8 @@ public:
std::vector<BasicBlock *> backedges;
backedges.reserve(4);
- foreach (BasicBlock *bb, dt.calculateDFNodeIterOrder()) {
+ const auto order = dt.calculateDFNodeIterOrder();
+ for (BasicBlock *bb : order) {
Q_ASSERT(!bb->isRemoved());
backedges.clear();
@@ -3136,12 +3189,12 @@ public:
if (!DebugLoopDetection)
return;
- foreach (LoopInfo *info, loopInfos) {
+ for (const LoopInfo *info : loopInfos) {
qDebug() << "Loop header:" << info->loopHeader->index()
<< "for loop" << quint64(info);
- foreach (BasicBlock *bb, info->loopBody)
+ for (BasicBlock *bb : info->loopBody)
qDebug() << " " << bb->index();
- foreach (LoopInfo *nested, info->nestedLoops)
+ for (LoopInfo *nested : info->nestedLoops)
qDebug() << " sub loop:" << quint64(nested);
qDebug() << " parent loop:" << quint64(info->parentLoop);
}
@@ -3225,15 +3278,15 @@ private:
findLoop(loopHeader)->loopBody.append(bb);
}
- foreach (LoopInfo *info, loopInfos) {
- if (BasicBlock *containingLoopHeader = info->loopHeader->containingGroup())
- findLoop(containingLoopHeader)->addNestedLoop(info);
+ for (int i = 0, size = loopInfos.size(); i < size; ++i) {
+ if (BasicBlock *containingLoopHeader = loopInfos.at(i)->loopHeader->containingGroup())
+ findLoop(containingLoopHeader)->addNestedLoop(loopInfos.at(i));
}
}
LoopInfo *findLoop(BasicBlock *loopHeader)
{
- foreach (LoopInfo *info, loopInfos) {
+ for (LoopInfo *info : qAsConst(loopInfos)) {
if (info->loopHeader == loopHeader)
return info;
}
@@ -3299,6 +3352,15 @@ class BlockScheduler
// this is a loop, where there in -> candidate edge is the jump back to the top of the loop.
continue;
+ if (in == candidate)
+ // this is a very tight loop, e.g.:
+ // L1: ...
+ // goto L1
+ // This can happen when, for example, the basic-block merging gets rid of the empty
+ // body block. In this case, we can safely schedule this block (if all other
+ // incoming edges are either loop-back edges, or have been scheduled already).
+ continue;
+
return false; // an incoming edge that is not yet emitted, and is not a back-edge
}
@@ -3398,8 +3460,8 @@ public:
};
#ifndef QT_NO_DEBUG
-void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
- foreach (BasicBlock *bb, basicBlocks) {
+void checkCriticalEdges(const QVector<BasicBlock *> &basicBlocks) {
+ for (BasicBlock *bb : basicBlocks) {
if (bb && bb->out.size() > 1) {
for (BasicBlock *bb2 : bb->out) {
if (bb2 && bb2->in.size() > 1) {
@@ -3504,7 +3566,7 @@ static Expr *clone(Expr *e, IR::Function *function) {
}
}
-class ExprReplacer: public StmtVisitor, public ExprVisitor
+class ExprReplacer
{
DefUses &_defUses;
IR::Function* _function;
@@ -3533,9 +3595,9 @@ public:
newUses->reserve(uses.size());
// qout << " " << uses.size() << " uses:"<<endl;
- foreach (Stmt *use, uses) {
+ for (Stmt *use : uses) {
// qout<<" ";use->dump(qout);qout<<"\n";
- use->accept(this);
+ visit(use);
// qout<<" -> ";use->dump(qout);qout<<"\n";
W += use;
if (newUses)
@@ -3546,45 +3608,101 @@ public:
qSwap(_toReplace, toReplace);
}
-protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { check(e->expr); }
- virtual void visitUnop(Unop *e) { check(e->expr); }
- virtual void visitBinop(Binop *e) { check(e->left); check(e->right); }
- virtual void visitCall(Call *e) {
+private:
+ void visit(Expr *e)
+ {
+ if (auto c = e->asConst()) {
+ visitConst(c);
+ } else if (auto s = e->asString()) {
+ visitString(s);
+ } else if (auto r = e->asRegExp()) {
+ visitRegExp(r);
+ } else if (auto n = e->asName()) {
+ visitName(n);
+ } else if (auto t = e->asTemp()) {
+ visitTemp(t);
+ } else if (auto a = e->asArgLocal()) {
+ visitArgLocal(a);
+ } else if (auto c = e->asClosure()) {
+ visitClosure(c);
+ } else if (auto c = e->asConvert()) {
+ visitConvert(c);
+ } else if (auto u = e->asUnop()) {
+ visitUnop(u);
+ } else if (auto b = e->asBinop()) {
+ visitBinop(b);
+ } else if (auto c = e->asCall()) {
+ visitCall(c);
+ } else if (auto n = e->asNew()) {
+ visitNew(n);
+ } else if (auto s = e->asSubscript()) {
+ visitSubscript(s);
+ } else if (auto m = e->asMember()) {
+ visitMember(m);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ void visitConst(Const *) {}
+ void visitString(IR::String *) {}
+ void visitRegExp(IR::RegExp *) {}
+ void visitName(Name *) {}
+ void visitTemp(Temp *) {}
+ void visitArgLocal(ArgLocal *) {}
+ void visitClosure(Closure *) {}
+ void visitConvert(Convert *e) { check(e->expr); }
+ void visitUnop(Unop *e) { check(e->expr); }
+ void visitBinop(Binop *e) { check(e->left); check(e->right); }
+ void visitCall(Call *e) {
check(e->base);
for (ExprList *it = e->args; it; it = it->next)
check(it->expr);
}
- virtual void visitNew(New *e) {
+ void visitNew(New *e) {
check(e->base);
for (ExprList *it = e->args; it; it = it->next)
check(it->expr);
}
- virtual void visitSubscript(Subscript *e) { check(e->base); check(e->index); }
- virtual void visitMember(Member *e) { check(e->base); }
- virtual void visitExp(Exp *s) { check(s->expr); }
- virtual void visitMove(Move *s) { check(s->target); check(s->source); }
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { check(s->cond); }
- virtual void visitRet(Ret *s) { check(s->expr); }
- virtual void visitPhi(Phi *s) {
+ void visitSubscript(Subscript *e) { check(e->base); check(e->index); }
+ void visitMember(Member *e) { check(e->base); }
+
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ visitExp(e);
+ } else if (auto m = s->asMove()) {
+ visitMove(m);
+ } else if (auto j = s->asJump()) {
+ visitJump(j);
+ } else if (auto c = s->asCJump()) {
+ visitCJump(c);
+ } else if (auto r = s->asRet()) {
+ visitRet(r);
+ } else if (auto p = s->asPhi()) {
+ visitPhi(p);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ void visitExp(Exp *s) { check(s->expr); }
+ void visitMove(Move *s) { check(s->target); check(s->source); }
+ void visitJump(Jump *) {}
+ void visitCJump(CJump *s) { check(s->cond); }
+ void visitRet(Ret *s) { check(s->expr); }
+ void visitPhi(Phi *s) {
for (int i = 0, ei = s->incoming.size(); i != ei; ++i)
check(s->incoming[i]);
}
private:
void check(Expr *&e) {
- if (equals(e, _toReplace))
+ if (equals(e, _toReplace)) {
e = clone(_replacement, _function);
- else
- e->accept(this);
+ } else {
+ visit(e);
+ }
}
// This only calculates equality for everything needed by constant propagation
@@ -3625,6 +3743,8 @@ namespace {
void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUses,
StatementWorklist &W, DominatorTree &dt)
{
+ enum { DebugUnlinking = 0 };
+
struct Util {
static void removeIncomingEdge(BasicBlock *from, BasicBlock *to, DefUses &defUses, StatementWorklist &W)
{
@@ -3633,7 +3753,7 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
return;
to->in.remove(idx);
- foreach (Stmt *outStmt, to->statements()) {
+ for (Stmt *outStmt : to->statements()) {
if (!outStmt)
continue;
if (Phi *phi = outStmt->asPhi()) {
@@ -3651,7 +3771,7 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
static bool isReachable(BasicBlock *bb, const DominatorTree &dt)
{
- foreach (BasicBlock *in, bb->in) {
+ for (BasicBlock *in : bb->in) {
if (in->isRemoved())
continue;
if (dt.dominates(bb, in)) // a back-edge, not interesting
@@ -3663,11 +3783,17 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
}
};
+ Q_ASSERT(!from->isRemoved());
+ Q_ASSERT(!to->isRemoved());
+
// don't purge blocks that are entry points for catch statements. They might not be directly
// connected, but are required anyway
if (to->isExceptionHandler())
return;
+ if (DebugUnlinking)
+ qDebug("Unlinking L%d -> L%d...", from->index(), to->index());
+
// First, unlink the edge
from->out.removeOne(to);
Util::removeIncomingEdge(from, to, defUses, W);
@@ -3677,8 +3803,12 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
// Check if the target is still reachable...
if (Util::isReachable(to, dt)) { // yes, recalculate the immediate dominator, and we're done.
+ if (DebugUnlinking)
+ qDebug(".. L%d is still reachable, recalulate idom.", to->index());
dt.collectSiblings(to, siblings);
} else {
+ if (DebugUnlinking)
+ qDebug(".. L%d is unreachable, purging it:", to->index());
// The target is unreachable, so purge it:
QVector<BasicBlock *> toPurge;
toPurge.reserve(8);
@@ -3686,6 +3816,8 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
while (!toPurge.isEmpty()) {
BasicBlock *bb = toPurge.first();
toPurge.removeFirst();
+ if (DebugUnlinking)
+ qDebug("... purging L%d", bb->index());
if (bb->isRemoved())
continue;
@@ -3729,6 +3861,8 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
}
dt.recalculateIDoms(siblings);
+ if (DebugUnlinking)
+ qDebug("Unlinking done.");
}
bool tryOptimizingComparison(Expr *&expr)
@@ -3807,13 +3941,13 @@ void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops =
struct Util {
QTextStream &qout;
Util(QTextStream &qout): qout(qout) {}
- void genLoop(LoopDetection::LoopInfo *loop)
+ void genLoop(const LoopDetection::LoopInfo *loop)
{
qout << " subgraph \"cluster" << quint64(loop) << "\" {\n";
qout << " L" << loop->loopHeader->index() << ";\n";
- foreach (BasicBlock *bb, loop->loopBody)
+ for (BasicBlock *bb : loop->loopBody)
qout << " L" << bb->index() << ";\n";
- foreach (LoopDetection::LoopInfo *nested, loop->nestedLoops)
+ for (LoopDetection::LoopInfo *nested : loop->nestedLoops)
genLoop(nested);
qout << " }\n";
}
@@ -3824,7 +3958,7 @@ void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops =
else name = QStringLiteral("%1").arg((unsigned long long)f);
qout << "digraph \"" << name << "\" { ordering=out;\n";
- foreach (LoopDetection::LoopInfo *l, loops) {
+ for (LoopDetection::LoopInfo *l : loops) {
if (l->parentLoop == 0)
Util(qout).genLoop(l);
}
@@ -4153,7 +4287,8 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df)
}
//### TODO: use DefUses from the optimizer, because it already has all this information
-class InputOutputCollector: protected StmtVisitor, protected ExprVisitor {
+class InputOutputCollector
+{
void setOutput(Temp *out)
{
Q_ASSERT(!output);
@@ -4170,48 +4305,33 @@ public:
void collect(Stmt *s) {
inputs.resize(0);
output = 0;
- s->accept(this);
+ visit(s);
}
-protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *e) {
- inputs.push_back(e);
- }
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { e->base->accept(this); }
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
- virtual void visitMove(Move *s) {
- s->source->accept(this);
- if (Temp *t = s->target->asTemp()) {
- setOutput(t);
+private:
+ void visit(Expr *e)
+ {
+ if (auto t = e->asTemp()) {
+ inputs.push_back(t);
} else {
- s->target->accept(this);
+ EXPR_VISIT_ALL_KINDS(e);
}
}
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(Phi *) {
- // Handled separately
+
+ void visit(Stmt *s)
+ {
+ if (auto m = s->asMove()) {
+ visit(m->source);
+ if (Temp *t = m->target->asTemp()) {
+ setOutput(t);
+ } else {
+ visit(m->target);
+ }
+ } else if (s->asPhi()) {
+ // Handled separately
+ } else {
+ STMT_VISIT_ALL_KINDS(s);
+ }
}
};
@@ -4224,7 +4344,59 @@ protected:
* See LifeTimeIntervals::renumber for details on the numbering.
*/
class LifeRanges {
- typedef QSet<Temp> LiveRegs;
+ class LiveRegs
+ {
+ typedef std::vector<int> Storage;
+ Storage regs;
+
+ public:
+ void insert(int r)
+ {
+ if (find(r) == end())
+ regs.push_back(r);
+ }
+
+ void unite(const LiveRegs &other)
+ {
+ if (other.empty())
+ return;
+ if (empty()) {
+ regs = other.regs;
+ return;
+ }
+ for (int r : other.regs)
+ insert(r);
+ }
+
+ typedef Storage::iterator iterator;
+ iterator find(int r)
+ { return std::find(regs.begin(), regs.end(), r); }
+
+ iterator begin()
+ { return regs.begin(); }
+
+ iterator end()
+ { return regs.end(); }
+
+ void erase(iterator it)
+ { regs.erase(it); }
+
+ void remove(int r)
+ {
+ iterator it = find(r);
+ if (it != end())
+ erase(it);
+ }
+
+ bool empty() const
+ { return regs.empty(); }
+
+ int size() const
+ { return int(regs.size()); }
+
+ int at(int idx) const
+ { return regs.at(idx); }
+ };
std::vector<LiveRegs> _liveIn;
std::vector<LifeTimeInterval *> _intervals;
@@ -4232,14 +4404,21 @@ class LifeRanges {
LifeTimeInterval &interval(const Temp *temp)
{
- LifeTimeInterval *&lti = _intervals[temp->index];
- if (Q_UNLIKELY(!lti)) {
- lti = new LifeTimeInterval;
- lti->setTemp(*temp);
- }
+ LifeTimeInterval *lti = _intervals[temp->index];
+ Q_ASSERT(lti);
return *lti;
}
+ void ensureInterval(const IR::Temp &temp)
+ {
+ Q_ASSERT(!temp.isInvalid());
+ LifeTimeInterval *&lti = _intervals[temp.index];
+ if (lti)
+ return;
+ lti = new LifeTimeInterval;
+ lti->setTemp(temp);
+ }
+
int defPosition(IR::Stmt *s) const
{
return usePosition(s) + 1;
@@ -4285,7 +4464,8 @@ public:
qout << "Life ranges:" << endl;
qout << "Intervals:" << endl;
- foreach (const LifeTimeInterval *range, _sortedIntervals->intervals()) {
+ const auto intervals = _sortedIntervals->intervals();
+ for (const LifeTimeInterval *range : intervals) {
range->dump(qout);
qout << endl;
}
@@ -4293,13 +4473,13 @@ public:
IRPrinter printer(&qout);
for (size_t i = 0, ei = _liveIn.size(); i != ei; ++i) {
qout << "L" << i <<" live-in: ";
- QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i));
- if (live.isEmpty())
+ auto live = _liveIn.at(i);
+ if (live.empty())
qout << "(none)";
std::sort(live.begin(), live.end());
for (int i = 0; i < live.size(); ++i) {
if (i > 0) qout << ", ";
- printer.print(&live[i]);
+ qout << '%' << live.at(i);
}
qout << endl;
}
@@ -4318,8 +4498,10 @@ private:
for (Stmt *s : successor->statements()) {
if (Phi *phi = s->asPhi()) {
- if (Temp *t = phi->incoming.at(bbIndex)->asTemp())
- live.insert(*t);
+ if (Temp *t = phi->incoming.at(bbIndex)->asTemp()) {
+ ensureInterval(*t);
+ live.insert(t->index);
+ }
} else {
break;
}
@@ -4328,14 +4510,15 @@ private:
const QVector<Stmt *> &statements = bb->statements();
- foreach (const Temp &opd, live)
- interval(&opd).addRange(start(bb), end(bb));
+ for (int reg : live)
+ _intervals[reg]->addRange(start(bb), end(bb));
InputOutputCollector collector;
for (int i = statements.size() - 1; i >= 0; --i) {
Stmt *s = statements.at(i);
if (Phi *phi = s->asPhi()) {
- LiveRegs::iterator it = live.find(*phi->targetTemp);
+ ensureInterval(*phi->targetTemp);
+ LiveRegs::iterator it = live.find(phi->targetTemp->index);
if (it == live.end()) {
// a phi node target that is only defined, but never used
interval(phi->targetTemp).setFrom(start(bb));
@@ -4348,25 +4531,27 @@ private:
collector.collect(s);
//### TODO: use DefUses from the optimizer, because it already has all this information
if (Temp *opd = collector.output) {
+ ensureInterval(*opd);
LifeTimeInterval &lti = interval(opd);
lti.setFrom(defPosition(s));
- live.remove(lti.temp());
+ live.remove(lti.temp().index);
_sortedIntervals->add(&lti);
}
//### TODO: use DefUses from the optimizer, because it already has all this information
for (size_t i = 0, ei = collector.inputs.size(); i != ei; ++i) {
Temp *opd = collector.inputs[i];
+ ensureInterval(*opd);
interval(opd).addRange(start(bb), usePosition(s));
- live.insert(*opd);
+ live.insert(opd->index);
}
}
if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null.
- foreach (const Temp &opd, live)
- interval(&opd).addRange(start(bb), usePosition(loopEnd->terminator()));
+ for (int reg : live)
+ _intervals[reg]->addRange(start(bb), usePosition(loopEnd->terminator()));
}
- _liveIn[bb->index()] = live;
+ _liveIn[bb->index()] = std::move(live);
}
};
@@ -4381,7 +4566,7 @@ void removeUnreachleBlocks(IR::Function *function)
function->renumberBasicBlocks();
}
-class ConvertArgLocals: protected StmtVisitor, protected ExprVisitor
+class ConvertArgLocals
{
public:
ConvertArgLocals(IR::Function *function)
@@ -4419,10 +4604,13 @@ public:
}
}
- for (BasicBlock *bb : function->basicBlocks())
- if (!bb->isRemoved())
- for (Stmt *s : bb->statements())
- s->accept(this);
+ for (BasicBlock *bb : function->basicBlocks()) {
+ if (!bb->isRemoved()) {
+ for (Stmt *s : bb->statements()) {
+ visit(s);
+ }
+ }
+ }
if (convertArgs && function->formals.size() > 0)
function->basicBlock(0)->prependStatements(extraMoves);
@@ -4430,39 +4618,45 @@ public:
function->locals.clear();
}
-protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { check(e->expr); }
- virtual void visitUnop(Unop *e) { check(e->expr); }
- virtual void visitBinop(Binop *e) { check(e->left); check(e->right); }
- virtual void visitCall(Call *e) {
- check(e->base);
- for (ExprList *it = e->args; it; it = it->next)
- check(it->expr);
- }
- virtual void visitNew(New *e) {
- check(e->base);
- for (ExprList *it = e->args; it; it = it->next)
- check(it->expr);
+private:
+ void visit(Stmt *s)
+ {
+ if (auto e = s->asExp()) {
+ check(e->expr);
+ } else if (auto m = s->asMove()) {
+ check(m->target); check(m->source);
+ } else if (auto c = s->asCJump()) {
+ check(c->cond);
+ } else if (auto r = s->asRet()) {
+ check(r->expr);
+ }
}
- virtual void visitSubscript(Subscript *e) { check(e->base); check(e->index); }
- virtual void visitMember(Member *e) { check(e->base); }
- virtual void visitExp(Exp *s) { check(s->expr); }
- virtual void visitMove(Move *s) { check(s->target); check(s->source); }
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { check(s->cond); }
- virtual void visitRet(Ret *s) { check(s->expr); }
- virtual void visitPhi(Phi *) {
- Q_UNREACHABLE();
+
+ void visit(Expr *e)
+ {
+ if (auto c = e->asConvert()) {
+ check(c->expr);
+ } else if (auto u = e->asUnop()) {
+ check(u->expr);
+ } else if (auto b = e->asBinop()) {
+ check(b->left); check(b->right);
+ } else if (auto c = e->asCall()) {
+ check(c->base);
+ for (ExprList *it = c->args; it; it = it->next) {
+ check(it->expr);
+ }
+ } else if (auto n = e->asNew()) {
+ check(n->base);
+ for (ExprList *it = n->args; it; it = it->next) {
+ check(it->expr);
+ }
+ } else if (auto s = e->asSubscript()) {
+ check(s->base); check(s->index);
+ } else if (auto m = e->asMember()) {
+ check(m->base);
+ }
}
-private:
void check(Expr *&e) {
if (ArgLocal *al = e->asArgLocal()) {
if (al->kind == ArgLocal::Local) {
@@ -4475,7 +4669,7 @@ private:
e = t;
}
} else {
- e->accept(this);
+ visit(e);
}
}
@@ -4498,7 +4692,7 @@ private:
std::vector<int> tempForLocal;
};
-class CloneBasicBlock: protected IR::StmtVisitor, protected CloneExpr
+class CloneBasicBlock: protected CloneExpr
{
public:
BasicBlock *operator()(IR::BasicBlock *originalBlock)
@@ -4506,38 +4700,37 @@ public:
block = new BasicBlock(originalBlock->function, 0);
for (Stmt *s : originalBlock->statements()) {
- s->accept(this);
+ visit(s);
clonedStmt->location = s->location;
}
return block;
}
-protected:
- virtual void visitExp(Exp *stmt)
- { clonedStmt = block->EXP(clone(stmt->expr)); }
-
- virtual void visitMove(Move *stmt)
- { clonedStmt = block->MOVE(clone(stmt->target), clone(stmt->source)); }
-
- virtual void visitJump(Jump *stmt)
- { clonedStmt = block->JUMP(stmt->target); }
-
- virtual void visitCJump(CJump *stmt)
- { clonedStmt = block->CJUMP(clone(stmt->cond), stmt->iftrue, stmt->iffalse); }
-
- virtual void visitRet(Ret *stmt)
- { clonedStmt = block->RET(clone(stmt->expr)); }
-
- virtual void visitPhi(Phi *stmt)
+private:
+ void visit(Stmt *s)
{
- Phi *phi = block->function->NewStmt<Phi>();
- clonedStmt = phi;
-
- phi->targetTemp = clone(stmt->targetTemp);
- foreach (Expr *in, stmt->incoming)
- phi->incoming.append(clone(in));
- block->appendStatement(phi);
+ if (auto e = s->asExp()) {
+ clonedStmt = block->EXP(clone(e->expr));
+ } else if (auto m = s->asMove()) {
+ clonedStmt = block->MOVE(clone(m->target), clone(m->source));
+ } else if (auto j = s->asJump()) {
+ clonedStmt = block->JUMP(j->target);
+ } else if (auto c = s->asCJump()) {
+ clonedStmt = block->CJUMP(clone(c->cond), c->iftrue, c->iffalse);
+ } else if (auto r = s->asRet()) {
+ clonedStmt = block->RET(clone(r->expr));
+ } else if (auto p = s->asPhi()) {
+ Phi *phi = block->function->NewStmt<Phi>();
+ clonedStmt = phi;
+
+ phi->targetTemp = clone(p->targetTemp);
+ for (Expr *in : p->incoming)
+ phi->incoming.append(clone(in));
+ block->appendStatement(phi);
+ } else {
+ Q_UNREACHABLE();
+ }
}
private:
@@ -4562,7 +4755,7 @@ public:
void run(const QVector<LoopDetection::LoopInfo *> &loops)
{
- foreach (LoopDetection::LoopInfo *loopInfo, loops)
+ for (LoopDetection::LoopInfo *loopInfo : loops)
peelLoop(loopInfo);
}
@@ -4666,7 +4859,7 @@ private:
// The original loop is now peeled off, and won't jump back to the loop header. Meaning, it
// is not a loop anymore, so unmark it.
loop->loopHeader->markAsGroupStart(false);
- foreach (BasicBlock *bb, loop->loopBody)
+ for (BasicBlock *bb : qAsConst(loop->loopBody))
bb->setContainingGroup(loop->loopHeader->containingGroup());
// calculate the idoms in a separate loop, because addBasicBlock in the previous loop will
@@ -4684,7 +4877,7 @@ private:
}
BasicBlockSet siblings(f);
- foreach (BasicBlock *bb, loopExits)
+ for (BasicBlock *bb : qAsConst(loopExits))
dt.collectSiblings(bb, siblings);
dt.recalculateIDoms(siblings, loop->loopHeader);
@@ -4706,13 +4899,20 @@ static void verifyCFG(IR::Function *function)
Q_ASSERT(function->basicBlock(bb->index()) == bb);
// Check the terminators:
- if (Jump *jump = bb->terminator()->asJump()) {
+ Stmt *terminator = bb->terminator();
+ if (terminator == nullptr) {
+ Stmt *last = bb->statements().last();
+ Call *call = last->asExp()->expr->asCall();
+ Name *baseName = call->base->asName();
+ Q_ASSERT(baseName->builtin == Name::builtin_rethrow);
+ Q_UNUSED(baseName);
+ } else if (Jump *jump = terminator->asJump()) {
Q_UNUSED(jump);
Q_ASSERT(jump->target);
Q_ASSERT(!jump->target->isRemoved());
Q_ASSERT(bb->out.size() == 1);
Q_ASSERT(bb->out.first() == jump->target);
- } else if (CJump *cjump = bb->terminator()->asCJump()) {
+ } else if (CJump *cjump = terminator->asCJump()) {
Q_UNUSED(cjump);
Q_ASSERT(bb->out.size() == 2);
Q_ASSERT(cjump->iftrue);
@@ -4721,7 +4921,7 @@ static void verifyCFG(IR::Function *function)
Q_ASSERT(cjump->iffalse);
Q_ASSERT(!cjump->iffalse->isRemoved());
Q_ASSERT(cjump->iffalse == bb->out[1]);
- } else if (bb->terminator()->asRet()) {
+ } else if (terminator->asRet()) {
Q_ASSERT(bb->out.size() == 0);
} else {
Q_UNREACHABLE();
@@ -4769,7 +4969,7 @@ static void verifyNoPointerSharing(IR::Function *function)
if (!DoVerification)
return;
- class : public StmtVisitor, public ExprVisitor {
+ class {
public:
void operator()(IR::Function *f)
{
@@ -4777,44 +4977,23 @@ static void verifyNoPointerSharing(IR::Function *function)
if (bb->isRemoved())
continue;
- for (Stmt *s : bb->statements())
- s->accept(this);
+ for (Stmt *s : bb->statements()) {
+ visit(s);
+ }
}
}
- protected:
- virtual void visitExp(Exp *s) { check(s); s->expr->accept(this); }
- virtual void visitMove(Move *s) { check(s); s->target->accept(this); s->source->accept(this); }
- virtual void visitJump(Jump *s) { check(s); }
- virtual void visitCJump(CJump *s) { check(s); s->cond->accept(this); }
- virtual void visitRet(Ret *s) { check(s); s->expr->accept(this); }
- virtual void visitPhi(Phi *s)
+ private:
+ void visit(Stmt *s)
{
check(s);
- s->targetTemp->accept(this);
- foreach (Expr *e, s->incoming)
- e->accept(this);
- }
-
- virtual void visitConst(Const *e) { check(e); }
- virtual void visitString(IR::String *e) { check(e); }
- virtual void visitRegExp(IR::RegExp *e) { check(e); }
- virtual void visitName(Name *e) { check(e); }
- virtual void visitTemp(Temp *e) { check(e); }
- virtual void visitArgLocal(ArgLocal *e) { check(e); }
- virtual void visitClosure(Closure *e) { check(e); }
- virtual void visitConvert(Convert *e) { check(e); e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { check(e); e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { check(e); e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(Call *e) { check(e); e->base->accept(this); check(e->args); }
- virtual void visitNew(New *e) { check(e); e->base->accept(this); check(e->args); }
- virtual void visitSubscript(Subscript *e) { check(e); e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { check(e); e->base->accept(this); }
-
- void check(ExprList *l)
+ STMT_VISIT_ALL_KINDS(s);
+ }
+
+ void visit(Expr *e)
{
- for (ExprList *it = l; it; it = it->next)
- check(it->expr);
+ check(e);
+ EXPR_VISIT_ALL_KINDS(e);
}
private:
@@ -4836,7 +5015,7 @@ static void verifyNoPointerSharing(IR::Function *function)
V(function);
}
-class RemoveLineNumbers: public SideEffectsChecker, public StmtVisitor
+class RemoveLineNumbers: private SideEffectsChecker
{
public:
static void run(IR::Function *function)
@@ -4854,28 +5033,95 @@ public:
}
private:
+ ~RemoveLineNumbers() {}
+
static bool hasSideEffects(Stmt *stmt)
{
RemoveLineNumbers checker;
- stmt->accept(&checker);
+ if (auto e = stmt->asExp()) {
+ checker.visit(e->expr);
+ } else if (auto m = stmt->asMove()) {
+ checker.visit(m->source);
+ if (!checker.seenSideEffects()) {
+ checker.visit(m->target);
+ }
+ } else if (auto c = stmt->asCJump()) {
+ checker.visit(c->cond);
+ } else if (auto r = stmt->asRet()) {
+ checker.visit(r->expr);
+ }
return checker.seenSideEffects();
}
- void visitExp(Exp *s) Q_DECL_OVERRIDE { s->expr->accept(this); }
- void visitMove(Move *s) Q_DECL_OVERRIDE { s->source->accept(this); s->target->accept(this); }
- void visitJump(Jump *) Q_DECL_OVERRIDE {}
- void visitCJump(CJump *s) Q_DECL_OVERRIDE { s->cond->accept(this); }
- void visitRet(Ret *s) Q_DECL_OVERRIDE { s->expr->accept(this); }
- void visitPhi(Phi *) Q_DECL_OVERRIDE {}
+ void visitTemp(Temp *) Q_DECL_OVERRIDE Q_DECL_FINAL {}
};
+void mergeBasicBlocks(IR::Function *function, DefUses *du, DominatorTree *dt)
+{
+ enum { DebugBlockMerging = 0 };
+
+ if (function->hasTry)
+ return;
+
+ showMeTheCode(function, "Before basic block merging");
+
+ // Now merge a basic block with its successor when there is one outgoing edge, and the
+ // successor has one incoming edge.
+ for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlock(i);
+
+ bb->nextLocation = QQmlJS::AST::SourceLocation(); // make sure appendStatement doesn't mess with the line info
+
+ if (bb->isRemoved()) continue; // the block has been removed, so ignore it
+ if (bb->out.size() != 1) continue; // more than one outgoing edge
+ BasicBlock *successor = bb->out.first();
+ if (successor->in.size() != 1) continue; // more than one incoming edge
+
+ // Ok, we can merge the two basic blocks.
+ if (DebugBlockMerging) {
+ qDebug("Merging L%d into L%d", successor->index(), bb->index());
+ }
+ Q_ASSERT(bb->terminator()->asJump());
+ bb->removeStatement(bb->statementCount() - 1); // remove the terminator, and replace it with:
+ for (Stmt *s : successor->statements()) {
+ bb->appendStatement(s); // add all statements from the successor to the current basic block
+ if (auto cjump = s->asCJump())
+ cjump->parent = bb;
+ }
+ bb->out = successor->out; // set the outgoing edges to the successor's so they're now in sync with our new terminator
+ for (auto newSuccessor : bb->out) {
+ for (auto &backlink : newSuccessor->in) {
+ if (backlink == successor) {
+ backlink = bb; // for all successors of our successor: set the incoming edges to come from bb, because we'll now jump there.
+ }
+ }
+ }
+ if (du) {
+ // all statements in successor have moved to bb, so make sure that the containing blocks
+ // stored in DefUses get updated (meaning: point to bb)
+ du->replaceBasicBlock(successor, bb);
+ }
+ if (dt) {
+ // update the immediate dominators to: any block that was dominated by the successor
+ // will now need to point to bb's immediate dominator. The reason is that bb itself
+ // won't be anyones immediate dominator, because it had just one outgoing edge.
+ dt->mergeIntoPredecessor(successor);
+ }
+ function->removeBasicBlock(successor);
+ --i; // re-run on the current basic-block, so any chain gets collapsed.
+ }
+
+ showMeTheCode(function, "After basic block merging");
+ verifyCFG(function);
+}
+
} // anonymous namespace
void LifeTimeInterval::setFrom(int from) {
Q_ASSERT(from > 0);
if (_ranges.isEmpty()) { // this is the case where there is no use, only a define
- _ranges.push_front(Range(from, from));
+ _ranges.prepend(Range(from, from));
if (_end == InvalidPosition)
_end = from;
} else {
@@ -4889,7 +5135,7 @@ void LifeTimeInterval::addRange(int from, int to) {
Q_ASSERT(to >= from);
if (_ranges.isEmpty()) {
- _ranges.push_front(Range(from, to));
+ _ranges.prepend(Range(from, to));
_end = to;
return;
}
@@ -4904,12 +5150,12 @@ void LifeTimeInterval::addRange(int from, int to) {
break;
p1->start = qMin(p->start, p1->start);
p1->end = qMax(p->end, p1->end);
- _ranges.pop_front();
+ _ranges.remove(0);
p = &_ranges.first();
}
} else {
if (to < p->start) {
- _ranges.push_front(Range(from, to));
+ _ranges.prepend(Range(from, to));
} else {
Q_ASSERT(from > _ranges.last().end);
_ranges.push_back(Range(from, to));
@@ -4950,7 +5196,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
}
if (newInterval._ranges.first().end == atPosition)
- newInterval._ranges.removeFirst();
+ newInterval._ranges.remove(0);
if (newStart == InvalidPosition) {
// the temp stays inactive for the rest of its lifetime
@@ -4970,7 +5216,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
break;
} else {
// the temp stays inactive for this interval, so remove it.
- newInterval._ranges.removeFirst();
+ newInterval._ranges.remove(0);
}
}
Q_ASSERT(!newInterval._ranges.isEmpty());
@@ -5001,15 +5247,6 @@ void LifeTimeInterval::dump(QTextStream &out) const {
out << " (register " << _reg << ")";
}
-bool LifeTimeInterval::lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2) {
- if (r1->_ranges.first().start == r2->_ranges.first().start) {
- if (r1->isSplitFromInterval() == r2->isSplitFromInterval())
- return r1->_ranges.last().end < r2->_ranges.last().end;
- else
- return r1->isSplitFromInterval();
- } else
- return r1->_ranges.first().start < r2->_ranges.first().start;
-}
bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval *r1, const LifeTimeInterval *r2)
{
@@ -5103,6 +5340,8 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA && statementCount <= 300) {
// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
+ mergeBasicBlocks(function, nullptr, nullptr);
+
ConvertArgLocals(function).toTemps();
showMeTheCode(function, "After converting arguments to locals");
@@ -5178,6 +5417,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
}
verifyNoPointerSharing(function);
+ mergeBasicBlocks(function, &defUses, &df);
// Basic-block cycles that are unreachable (i.e. for loops in a then-part where the
// condition is calculated to be always false) are not yet removed. This will choke the
@@ -5280,14 +5520,30 @@ LifeTimeIntervals::Ptr Optimizer::lifeTimeIntervals() const
return lifeRanges.intervals();
}
-QSet<Jump *> Optimizer::calculateOptionalJumps()
+static int countPhis(BasicBlock *bb)
{
- QSet<Jump *> optional;
- QSet<BasicBlock *> reachableWithoutJump;
+ int count = 0;
+ for (Stmt *s : bb->statements()) {
+ if (s->isa<Phi>())
+ ++count;
+ else
+ break;
+ }
+ return count;
+}
+
+// Basic blocks can have only 1 terminator. This function returns a bit vector, where a 1 on a
+// certain index indicates that the terminator (jump) at the end of the basic block with that index
+// can be omitted.
+BitVector Optimizer::calculateOptionalJumps()
+{
const int maxSize = function->basicBlockCount();
- optional.reserve(maxSize);
- reachableWithoutJump.reserve(maxSize);
+ BitVector optional(maxSize, false);
+ if (maxSize < 2)
+ return optional;
+
+ BitVector reachableWithoutJump(maxSize, false);
for (int i = maxSize - 1; i >= 0; --i) {
BasicBlock *bb = function->basicBlock(i);
@@ -5295,17 +5551,17 @@ QSet<Jump *> Optimizer::calculateOptionalJumps()
continue;
if (Jump *jump = bb->statements().last()->asJump()) {
- if (reachableWithoutJump.contains(jump->target)) {
- if (bb->statements().size() > 1)
+ if (reachableWithoutJump.at(jump->target->index())) {
+ if (bb->statements().size() - countPhis(bb)> 1)
reachableWithoutJump.clear();
- optional.insert(jump);
- reachableWithoutJump.insert(bb);
+ optional.setBit(bb->index());
+ reachableWithoutJump.setBit(bb->index());
continue;
}
}
reachableWithoutJump.clear();
- reachableWithoutJump.insert(bb);
+ reachableWithoutJump.setBit(bb->index());
}
return optional;
@@ -5404,7 +5660,7 @@ QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *functio
newMoves.reserve(_moves.size());
int insertionPoint = atEnd ? bb->statements().size() - 1 : 0;
- foreach (const Move &m, _moves) {
+ for (const Move &m : _moves) {
IR::Move *move = function->NewStmt<IR::Move>();
move->init(clone(m.to, function), clone(m.from, function));
move->swap = m.needsSwap;
@@ -5423,7 +5679,7 @@ void MoveMapping::dump() const
QTextStream os(&buf);
IRPrinter printer(&os);
os << "Move mapping has " << _moves.size() << " moves..." << endl;
- foreach (const Move &m, _moves) {
+ for (const Move &m : _moves) {
os << "\t";
printer.print(m.to);
if (m.needsSwap)
@@ -5440,8 +5696,8 @@ void MoveMapping::dump() const
MoveMapping::Action MoveMapping::schedule(const Move &m, QList<Move> &todo, QList<Move> &delayed,
QList<Move> &output, QList<Move> &swaps) const
{
- Moves usages = sourceUsages(m.to, todo) + sourceUsages(m.to, delayed);
- foreach (const Move &dependency, usages) {
+ const Moves usages = sourceUsages(m.to, todo) + sourceUsages(m.to, delayed);
+ for (const Move &dependency : usages) {
if (!output.contains(dependency)) {
if (delayed.contains(dependency)) {
// We have a cycle! Break it by swapping instead of assigning.
@@ -5452,7 +5708,7 @@ MoveMapping::Action MoveMapping::schedule(const Move &m, QList<Move> &todo, QLis
QTextStream out(&buf);
IRPrinter printer(&out);
out<<"we have a cycle! temps:" << endl;
- foreach (const Move &m, delayed) {
+ for (const Move &m : qAsConst(delayed)) {
out<<"\t";
printer.print(m.to);
out<<" <- ";
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index e608c08591..db8b6edd1a 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -52,6 +52,8 @@
//
#include "qv4jsir_p.h"
+#include "qv4isel_util_p.h"
+#include <private/qv4util_p.h>
#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
@@ -74,7 +76,7 @@ public:
bool covers(int position) const { return start <= position && position <= end; }
};
- typedef QVector<Range> Ranges;
+ typedef QVarLengthArray<Range, 4> Ranges;
private:
Temp _temp;
@@ -88,7 +90,7 @@ public:
enum { InvalidPosition = -1 };
enum { InvalidRegister = -1 };
- explicit LifeTimeInterval(int rangeCapacity = 2)
+ explicit LifeTimeInterval(int rangeCapacity = 4)
: _end(InvalidPosition)
, _reg(InvalidRegister)
, _isFixedInterval(0)
@@ -145,6 +147,17 @@ public:
}
};
+inline bool LifeTimeInterval::lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2)
+{
+ if (r1->_ranges.first().start == r2->_ranges.first().start) {
+ if (r1->isSplitFromInterval() == r2->isSplitFromInterval())
+ return r1->_ranges.last().end < r2->_ranges.last().end;
+ else
+ return r1->isSplitFromInterval();
+ } else
+ return r1->_ranges.first().start < r2->_ranges.first().start;
+}
+
class LifeTimeIntervals
{
Q_DISABLE_COPY(LifeTimeIntervals)
@@ -234,7 +247,7 @@ public:
LifeTimeIntervals::Ptr lifeTimeIntervals() const;
- QSet<IR::Jump *> calculateOptionalJumps();
+ BitVector calculateOptionalJumps();
static void showMeTheCode(Function *function, const char *marker);
@@ -277,6 +290,168 @@ private:
QList<Move> &swaps) const;
};
+/*
+ * stack slot allocation:
+ *
+ * foreach bb do
+ * foreach stmt do
+ * if the current statement is not a phi-node:
+ * purge ranges that end before the current statement
+ * check for life ranges to activate, and if they don't have a stackslot associated then allocate one
+ * renumber temps to stack
+ * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated
+ * if it's a jump:
+ * foreach phi node in the successor:
+ * allocate slots for each temp (both sources and targets) if they don't have one allocated already
+ * insert moves before the jump
+ */
+class AllocateStackSlots: protected ConvertTemps
+{
+ IR::LifeTimeIntervals::Ptr _intervals;
+ QVector<IR::LifeTimeInterval *> _unhandled;
+ QVector<IR::LifeTimeInterval *> _live;
+ QBitArray _slotIsInUse;
+ IR::Function *_function;
+
+ int defPosition(IR::Stmt *s) const
+ {
+ return usePosition(s) + 1;
+ }
+
+ int usePosition(IR::Stmt *s) const
+ {
+ return _intervals->positionForStatement(s);
+ }
+
+public:
+ AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals)
+ : _intervals(intervals)
+ , _slotIsInUse(intervals->size(), false)
+ , _function(0)
+ {
+ _live.reserve(8);
+ _unhandled = _intervals->intervals();
+ }
+
+ void forFunction(IR::Function *function)
+ {
+ IR::Optimizer::showMeTheCode(function, "Before stack slot allocation");
+ _function = function;
+ toStackSlots(function);
+ }
+
+protected:
+ int allocateFreeSlot() override
+ {
+ for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) {
+ if (!_slotIsInUse[i]) {
+ if (_nextUnusedStackSlot <= i) {
+ Q_ASSERT(_nextUnusedStackSlot == i);
+ _nextUnusedStackSlot = i + 1;
+ }
+ _slotIsInUse[i] = true;
+ return i;
+ }
+ }
+
+ Q_UNREACHABLE();
+ return -1;
+ }
+
+ void process(IR::Stmt *s) override
+ {
+// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id);
+
+ if (IR::Phi *phi = s->asPhi()) {
+ visitPhi(phi);
+ } else {
+ // purge ranges no longer alive:
+ for (int i = 0; i < _live.size(); ) {
+ const IR::LifeTimeInterval *lti = _live.at(i);
+ if (lti->end() < usePosition(s)) {
+// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index];
+ _live.remove(i);
+ Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]);
+ _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false;
+ continue;
+ } else {
+ ++i;
+ }
+ }
+
+ // active new ranges:
+ while (!_unhandled.isEmpty()) {
+ IR::LifeTimeInterval *lti = _unhandled.last();
+ if (lti->start() > defPosition(s))
+ break; // we're done
+ Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index));
+ _stackSlotForTemp[lti->temp().index] = allocateFreeSlot();
+// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index];
+ _live.append(lti);
+ _unhandled.removeLast();
+ }
+
+ visit(s);
+ }
+
+ if (IR::Jump *jump = s->asJump()) {
+ IR::MoveMapping moves;
+ for (IR::Stmt *succStmt : jump->target->statements()) {
+ if (IR::Phi *phi = succStmt->asPhi()) {
+ forceActivation(*phi->targetTemp);
+ for (int i = 0, ei = phi->incoming.size(); i != ei; ++i) {
+ IR::Expr *e = phi->incoming[i];
+ if (IR::Temp *t = e->asTemp()) {
+ forceActivation(*t);
+ }
+ if (jump->target->in[i] == _currentBasicBlock)
+ moves.add(phi->incoming[i], phi->targetTemp);
+ }
+ } else {
+ break;
+ }
+ }
+ moves.order();
+ const QList<IR::Move *> newMoves = moves.insertMoves(_currentBasicBlock, _function, true);
+ for (IR::Move *move : newMoves)
+ visit(move);
+ }
+ }
+
+ void forceActivation(const IR::Temp &t)
+ {
+ if (_stackSlotForTemp.contains(t.index))
+ return;
+
+ int i = _unhandled.size() - 1;
+ for (; i >= 0; --i) {
+ IR::LifeTimeInterval *lti = _unhandled[i];
+ if (lti->temp() == t) {
+ _live.append(lti);
+ _unhandled.remove(i);
+ break;
+ }
+ }
+ Q_ASSERT(i >= 0); // check that we always found the entry
+
+ _stackSlotForTemp[t.index] = allocateFreeSlot();
+// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index];
+ }
+
+ void visitPhi(IR::Phi *phi) override
+ {
+ Q_UNUSED(phi);
+#if !defined(QT_NO_DEBUG)
+ Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index));
+ Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]);
+ for (IR::Expr *e : phi->incoming) {
+ if (IR::Temp *t = e->asTemp())
+ Q_ASSERT(_stackSlotForTemp.contains(t->index));
+ }
+#endif // defined(QT_NO_DEBUG)
+ }
+};
+
} // IR namespace
} // QV4 namespace
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
index 30a44eedd1..da1ab867d4 100644
--- a/src/qml/debugger/debugger.pri
+++ b/src/qml/debugger/debugger.pri
@@ -1,21 +1,28 @@
-contains(QT_CONFIG, no-qml-debug):DEFINES += QT_NO_QML_DEBUGGER
+contains(QT_CONFIG, no-qml-debug) {
+ DEFINES += QT_NO_QML_DEBUGGER
+ MODULE_DEFINES += QT_NO_QML_DEBUGGER
+} else {
+ HEADERS += \
+ $$PWD/qqmldebugpluginmanager_p.h \
+ $$PWD/qqmldebugservicefactory_p.h
-SOURCES += \
- $$PWD/qqmldebug.cpp \
- $$PWD/qqmldebugconnector.cpp \
- $$PWD/qqmldebugservice.cpp \
- $$PWD/qqmldebugserviceinterfaces.cpp \
- $$PWD/qqmlabstractprofileradapter.cpp \
- $$PWD/qqmlprofiler.cpp
+ SOURCES += \
+ $$PWD/qqmldebug.cpp \
+ $$PWD/qqmldebugconnector.cpp \
+ $$PWD/qqmldebugservice.cpp \
+ $$PWD/qqmlabstractprofileradapter.cpp \
+ $$PWD/qqmlmemoryprofiler.cpp \
+ $$PWD/qqmlprofiler.cpp \
+ $$PWD/qqmldebugserviceinterfaces.cpp
+}
HEADERS += \
$$PWD/qqmldebugconnector_p.h \
- $$PWD/qqmldebugpluginmanager_p.h \
$$PWD/qqmldebugservice_p.h \
- $$PWD/qqmldebugservicefactory_p.h \
$$PWD/qqmldebugserviceinterfaces_p.h \
$$PWD/qqmldebugstatesdelegate_p.h \
$$PWD/qqmldebug.h \
+ $$PWD/qqmlmemoryprofiler_p.h \
$$PWD/qqmlprofilerdefinitions_p.h \
$$PWD/qqmlabstractprofileradapter_p.h \
$$PWD/qqmlprofiler_p.h
diff --git a/src/qml/debugger/qqmlabstractprofileradapter_p.h b/src/qml/debugger/qqmlabstractprofileradapter_p.h
index 8820c4311a..6a05a80f37 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter_p.h
+++ b/src/qml/debugger/qqmlabstractprofileradapter_p.h
@@ -59,6 +59,8 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QML_DEBUGGER
+
class QQmlProfilerService;
class Q_QML_PRIVATE_EXPORT QQmlAbstractProfilerAdapter : public QObject, public QQmlProfilerDefinitions {
Q_OBJECT
@@ -114,6 +116,8 @@ public:
#define QQmlAbstractProfilerAdapterFactory_iid "org.qt-project.Qt.QQmlAbstractProfilerAdapterFactory"
+#endif // QT_NO_QML_DEBUGGER
+
QT_END_NAMESPACE
#endif // QQMLABSTRACTPROFILERADAPTER_P_H
diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp
index 9276bd0544..386fb60b3a 100644
--- a/src/qml/debugger/qqmldebug.cpp
+++ b/src/qml/debugger/qqmldebug.cpp
@@ -47,15 +47,11 @@ QT_BEGIN_NAMESPACE
QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
{
-#ifndef QQML_NO_DEBUG_PROTOCOL
if (!QQmlEnginePrivate::qml_debugging_enabled
&& printWarning) {
qDebug("QML debugging is enabled. Only use this in a safe environment.");
}
QQmlEnginePrivate::qml_debugging_enabled = true;
-#else
- Q_UNUSED(printWarning);
-#endif
}
/*!
@@ -105,11 +101,7 @@ QStringList QQmlDebuggingEnabler::profilerServices()
*/
void QQmlDebuggingEnabler::setServices(const QStringList &services)
{
-#ifndef QQML_NO_DEBUG_PROTOCOL
QQmlDebugConnector::setServices(services);
-#else
- Q_UNUSED(services);
-#endif
}
/*!
@@ -172,16 +164,9 @@ bool QQmlDebuggingEnabler::connectToLocalDebugger(const QString &socketFileName,
bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName,
const QVariantHash &configuration)
{
-#ifndef QQML_NO_DEBUG_PROTOCOL
QQmlDebugConnector::setPluginKey(pluginName);
QQmlDebugConnector *connector = QQmlDebugConnector::instance();
- if (connector)
- return connector->open(configuration);
-#else
- Q_UNUSED(pluginName);
- Q_UNUSED(configuration);
-#endif
- return false;
+ return connector ? connector->open(configuration) : false;
}
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h
index 660b9e4d46..fb41039867 100644
--- a/src/qml/debugger/qqmldebug.h
+++ b/src/qml/debugger/qqmldebug.h
@@ -46,6 +46,7 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QML_DEBUGGER
struct Q_QML_EXPORT QQmlDebuggingEnabler
{
@@ -77,6 +78,8 @@ static QQmlDebuggingEnabler qQmlEnableDebuggingHelper(false);
static QQmlDebuggingEnabler qQmlEnableDebuggingHelper(true);
#endif
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUG_H
diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp
index 23440e7529..029df1e748 100644
--- a/src/qml/debugger/qqmldebugconnector.cpp
+++ b/src/qml/debugger/qqmldebugconnector.cpp
@@ -134,9 +134,11 @@ QQmlDebugConnector *QQmlDebugConnector::instance()
}
if (params->instance) {
- foreach (const QJsonObject &object, metaDataForQQmlDebugService()) {
- foreach (const QJsonValue &key, object.value(QLatin1String("MetaData")).toObject()
- .value(QLatin1String("Keys")).toArray()) {
+ const auto metaData = metaDataForQQmlDebugService();
+ for (const QJsonObject &object : metaData) {
+ const auto keys = object.value(QLatin1String("MetaData")).toObject()
+ .value(QLatin1String("Keys")).toArray();
+ for (const QJsonValue &key : keys) {
QString keyString = key.toString();
if (params->services.isEmpty() || params->services.contains(keyString))
loadQQmlDebugService(keyString);
diff --git a/src/qml/debugger/qqmldebugconnector_p.h b/src/qml/debugger/qqmldebugconnector_p.h
index 05755250bd..0d3e2e2e47 100644
--- a/src/qml/debugger/qqmldebugconnector_p.h
+++ b/src/qml/debugger/qqmldebugconnector_p.h
@@ -59,6 +59,29 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugConnector
+{
+public:
+ static QQmlDebugConnector *instance() { return nullptr; }
+
+ template<class Service>
+ static Service *service() { return nullptr; }
+
+ bool hasEngine(QJSEngine *) const { return false; }
+ void addEngine(QJSEngine *) {}
+ void removeEngine(QJSEngine *) {}
+
+ bool open(const QVariantHash &configuration = QVariantHash())
+ {
+ Q_UNUSED(configuration);
+ return false;
+ }
+};
+
+#else
+
class QQmlDebugService;
class Q_QML_PRIVATE_EXPORT QQmlDebugConnector : public QObject
{
@@ -106,6 +129,8 @@ public:
#define QQmlDebugConnectorFactory_iid "org.qt-project.Qt.QQmlDebugConnectorFactory"
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUGCONNECTOR_H
diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp
index b780735f48..b576c3bb85 100644
--- a/src/qml/debugger/qqmldebugservice.cpp
+++ b/src/qml/debugger/qqmldebugservice.cpp
@@ -132,7 +132,6 @@ public:
int nextId;
-private slots:
void remove(QObject *obj);
};
}
@@ -163,7 +162,7 @@ int QQmlDebugService::idForObject(QObject *object)
int id = hash->nextId++;
hash->ids.insert(id, object);
iter = hash->objects.insert(object, id);
- connect(object, SIGNAL(destroyed(QObject*)), hash, SLOT(remove(QObject*)));
+ connect(object, &QObject::destroyed, hash, &ObjectReferenceHash::remove);
}
return iter.value();
}
@@ -176,36 +175,6 @@ const QHash<int, QObject *> &QQmlDebugService::objectsForIds()
return objectReferenceHash()->ids;
}
-void QQmlDebugService::stateAboutToBeChanged(State)
-{
-}
-
-void QQmlDebugService::stateChanged(State)
-{
-}
-
-void QQmlDebugService::messageReceived(const QByteArray &)
-{
-}
-
-void QQmlDebugService::engineAboutToBeAdded(QJSEngine *engine)
-{
- emit attachedToEngine(engine);
-}
-
-void QQmlDebugService::engineAboutToBeRemoved(QJSEngine *engine)
-{
- emit detachedFromEngine(engine);
-}
-
-void QQmlDebugService::engineAdded(QJSEngine *)
-{
-}
-
-void QQmlDebugService::engineRemoved(QJSEngine *)
-{
-}
-
QT_END_NAMESPACE
#include "qqmldebugservice.moc"
diff --git a/src/qml/debugger/qqmldebugservice_p.h b/src/qml/debugger/qqmldebugservice_p.h
index 9ddc692ecc..42a57a39f2 100644
--- a/src/qml/debugger/qqmldebugservice_p.h
+++ b/src/qml/debugger/qqmldebugservice_p.h
@@ -58,6 +58,8 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QML_DEBUGGER
+
class QJSEngine;
class QQmlDebugServicePrivate;
@@ -65,7 +67,6 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugService : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlDebugService)
- Q_DISABLE_COPY(QQmlDebugService)
public:
~QQmlDebugService();
@@ -77,14 +78,15 @@ public:
State state() const;
void setState(State newState);
- virtual void stateAboutToBeChanged(State);
- virtual void stateChanged(State);
- virtual void messageReceived(const QByteArray &);
+ virtual void stateAboutToBeChanged(State) {}
+ virtual void stateChanged(State) {}
+ virtual void messageReceived(const QByteArray &) {}
+
+ virtual void engineAboutToBeAdded(QJSEngine *engine) { emit attachedToEngine(engine); }
+ virtual void engineAboutToBeRemoved(QJSEngine *engine) { emit detachedFromEngine(engine); }
- virtual void engineAboutToBeAdded(QJSEngine *);
- virtual void engineAboutToBeRemoved(QJSEngine *);
- virtual void engineAdded(QJSEngine *);
- virtual void engineRemoved(QJSEngine *);
+ virtual void engineAdded(QJSEngine *) {}
+ virtual void engineRemoved(QJSEngine *) {}
static const QHash<int, QObject *> &objectsForIds();
static int idForObject(QObject *);
@@ -101,6 +103,8 @@ signals:
void messagesToClient(const QString &name, const QList<QByteArray> &messages);
};
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUGSERVICE_H
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
index 8f66779872..ca6293c3ec 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces_p.h
+++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
@@ -62,7 +62,46 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QV4DebugService : protected QQmlDebugService
+class QWindow;
+class QQuickWindow;
+
+#ifdef QT_NO_QML_DEBUGGER
+
+struct QV4DebugService
+{
+ void signalEmitted(const QString &) {}
+};
+
+struct QQmlProfilerService
+{
+ void startProfiling(QJSEngine *engine, quint64 features = std::numeric_limits<quint64>::max())
+ {
+ Q_UNUSED(engine);
+ Q_UNUSED(features);
+ }
+
+ void stopProfiling(QJSEngine *) {}
+};
+
+struct QQmlEngineDebugService
+{
+ void objectCreated(QJSEngine *, QObject *) {}
+ virtual void setStatesDelegate(QQmlDebugStatesDelegate *) {}
+};
+
+struct QQmlInspectorService {
+ void addWindow(QQuickWindow *) {}
+ void setParentWindow(QQuickWindow *, QWindow *) {}
+ void removeWindow(QQuickWindow *) {}
+};
+
+struct QDebugMessageService {};
+struct QQmlEngineControlService {};
+struct QQmlNativeDebugService {};
+
+#else
+
+class Q_QML_PRIVATE_EXPORT QV4DebugService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -77,7 +116,7 @@ protected:
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlProfilerService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlProfilerService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -99,7 +138,7 @@ protected:
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -117,9 +156,7 @@ protected:
QQmlBoundSignal *nextSignal(QQmlBoundSignal *prev) { return prev->m_nextSignal; }
};
-class QWindow;
-class QQuickWindow;
-class Q_QML_PRIVATE_EXPORT QQmlInspectorService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlInspectorService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -136,7 +173,7 @@ protected:
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QDebugMessageService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QDebugMessageService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -151,7 +188,7 @@ protected:
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlEngineControlService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlEngineControlService : public QQmlDebugService
{
Q_OBJECT
public:
@@ -165,7 +202,7 @@ protected:
};
-class Q_QML_PRIVATE_EXPORT QQmlNativeDebugService : protected QQmlDebugService
+class Q_QML_PRIVATE_EXPORT QQmlNativeDebugService : public QQmlDebugService
{
Q_OBJECT
@@ -178,6 +215,8 @@ protected:
static const QString s_key;
};
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUGSERVICEINTERFACES_P_H
diff --git a/src/qml/debugger/qqmldebugstatesdelegate_p.h b/src/qml/debugger/qqmldebugstatesdelegate_p.h
index 42c4e94b50..95f727fb2d 100644
--- a/src/qml/debugger/qqmldebugstatesdelegate_p.h
+++ b/src/qml/debugger/qqmldebugstatesdelegate_p.h
@@ -57,6 +57,11 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+class QQmlDebugStatesDelegate {};
+
+#else
class QQmlContext;
class QQmlProperty;
@@ -90,6 +95,8 @@ private:
Q_DISABLE_COPY(QQmlDebugStatesDelegate)
};
+#endif
+
QT_END_NAMESPACE
#endif // QQMLDEBUGSTATESDELEGATE_P_H
diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/debugger/qqmlmemoryprofiler.cpp
index 60f6d96eaf..60f6d96eaf 100644
--- a/src/qml/qml/qqmlmemoryprofiler.cpp
+++ b/src/qml/debugger/qqmlmemoryprofiler.cpp
diff --git a/src/qml/qml/qqmlmemoryprofiler_p.h b/src/qml/debugger/qqmlmemoryprofiler_p.h
index 4b0ba823ba..59f08704ca 100644
--- a/src/qml/qml/qqmlmemoryprofiler_p.h
+++ b/src/qml/debugger/qqmlmemoryprofiler_p.h
@@ -55,6 +55,13 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+#define QML_MEMORY_SCOPE_URL(url)
+#define QML_MEMORY_SCOPE_STRING(s)
+
+#else
+
class QUrl;
class Q_QML_PRIVATE_EXPORT QQmlMemoryScope
@@ -83,5 +90,7 @@ public:
#define QML_MEMORY_SCOPE_URL(url) QQmlMemoryScope _qml_memory_scope(url)
#define QML_MEMORY_SCOPE_STRING(s) QQmlMemoryScope _qml_memory_scope(s)
+#endif
+
QT_END_NAMESPACE
#endif // QQMLMEMORYPROFILER_H
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 60851ac444..6643695d11 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -55,7 +55,6 @@
#include <private/qqmlboundsignal_p.h>
#include <private/qfinitestack_p.h>
#include <private/qqmlbinding_p.h>
-#include <private/qqmlcompiler_p.h>
#include "qqmlprofilerdefinitions_p.h"
#include "qqmlabstractprofileradapter_p.h"
@@ -64,6 +63,54 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+#define Q_QML_PROFILE_IF_ENABLED(feature, profiler, Code)
+#define Q_QML_PROFILE(feature, profiler, Method)
+#define Q_QML_OC_PROFILE(member, Code)
+
+struct QQmlProfiler {};
+
+struct QQmlBindingProfiler
+{
+ QQmlBindingProfiler(quintptr, QQmlBinding *, QV4::FunctionObject *) {}
+};
+
+struct QQmlHandlingSignalProfiler
+{
+ QQmlHandlingSignalProfiler(quintptr, QQmlBoundSignalExpression *) {}
+};
+
+struct QQmlCompilingProfiler
+{
+ QQmlCompilingProfiler(quintptr, QQmlDataBlob *) {}
+};
+
+struct QQmlVmeProfiler {
+ QQmlVmeProfiler() {}
+
+ void init(quintptr, int) {}
+
+ const QV4::CompiledData::Object *pop() { return nullptr; }
+ void push(const QV4::CompiledData::Object *) {}
+
+ static const quintptr profiler = 0;
+};
+
+struct QQmlObjectCreationProfiler
+{
+ QQmlObjectCreationProfiler(quintptr, const QV4::CompiledData::Object *) {}
+ void update(QV4::CompiledData::CompilationUnit *, const QV4::CompiledData::Object *,
+ const QString &, const QUrl &) {}
+};
+
+struct QQmlObjectCompletionProfiler
+{
+ QQmlObjectCompletionProfiler(QQmlVmeProfiler *) {}
+};
+
+#else
+
#define Q_QML_PROFILE_IF_ENABLED(feature, profiler, Code)\
if (profiler && (profiler->featuresEnabled & (1 << feature))) {\
Code;\
@@ -73,6 +120,9 @@ QT_BEGIN_NAMESPACE
#define Q_QML_PROFILE(feature, profiler, Method)\
Q_QML_PROFILE_IF_ENABLED(feature, profiler, profiler->Method)
+#define Q_QML_OC_PROFILE(member, Code)\
+ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code)
+
// This struct is somewhat dangerous to use:
// The messageType is a bit field. You can pack multiple messages into
// one object, e.g. RangeStart and RangeLocation. Each one will be read
@@ -95,7 +145,7 @@ struct Q_AUTOTEST_EXPORT QQmlProfilerData : public QQmlProfilerDefinitions
Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE);
-class QQmlProfiler : public QObject, public QQmlProfilerDefinitions {
+class Q_QML_PRIVATE_EXPORT QQmlProfiler : public QObject, public QQmlProfilerDefinitions {
Q_OBJECT
public:
@@ -154,7 +204,7 @@ public:
ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt), sent(false)
{}
- RefLocation(QQmlCompiledData *ref, const QUrl &url, const QV4::CompiledData::Object *obj,
+ RefLocation(QV4::CompiledData::CompilationUnit *ref, const QUrl &url, const QV4::CompiledData::Object *obj,
const QString &type) :
Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
locationType(Creating), ref(ref), sent(false)
@@ -226,7 +276,7 @@ public:
Creating, id(obj)));
}
- void updateCreating(const QV4::CompiledData::Object *obj, QQmlCompiledData *ref,
+ void updateCreating(const QV4::CompiledData::Object *obj, QV4::CompiledData::CompilationUnit *ref,
const QUrl &url, const QString &type)
{
quintptr locationId(id(obj));
@@ -251,7 +301,6 @@ public:
return reinterpret_cast<quintptr>(pointer);
}
-public slots:
void startProfiling(quint64 features);
void stopProfiling();
void reportData(bool trackLocations);
@@ -350,9 +399,6 @@ private:
QFiniteStack<const QV4::CompiledData::Object *> ranges;
};
-#define Q_QML_OC_PROFILE(member, Code)\
- Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code)
-
class QQmlObjectCreationProfiler {
public:
@@ -367,7 +413,7 @@ public:
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange<QQmlProfilerDefinitions::Creating>());
}
- void update(QQmlCompiledData *ref, const QV4::CompiledData::Object *obj,
+ void update(QV4::CompiledData::CompilationUnit *ref, const QV4::CompiledData::Object *obj,
const QString &typeName, const QUrl &url)
{
profiler->updateCreating(obj, ref, url, typeName);
@@ -400,4 +446,6 @@ QT_END_NAMESPACE
Q_DECLARE_METATYPE(QVector<QQmlProfilerData>)
Q_DECLARE_METATYPE(QQmlProfiler::LocationHash)
+#endif // QT_NO_QML_DEBUGGER
+
#endif // QQMLPROFILER_P_H
diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h
index 2b2eda22e1..c6ae4593a9 100644
--- a/src/qml/debugger/qqmlprofilerdefinitions_p.h
+++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h
@@ -56,6 +56,8 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QML_DEBUGGER
+
struct QQmlProfilerDefinitions {
enum Message {
Event,
@@ -161,6 +163,8 @@ struct QQmlProfilerDefinitions {
};
};
+#endif // QT_NO_QML_DEBUGGER
+
QT_END_NAMESPACE
#endif
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 0d875bd10f..cc2fe90483 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -249,6 +249,18 @@ parameter, the value can be created as a JavaScript \c Date object in QML, and
is automatically converted to a QDateTime value when it is passed to C++.
+\section2 QTime to JavaScript Date
+
+The QML engine provides automatic type conversion from QTime values to
+JavaScript \c Date objects. The date component of the resulting Date
+object should not be relied upon, as it is operating system dependent.
+Specifically, the year (and month and day) are set to zero. Conversion
+from a JavaScript \c Date object to QTime is done by converting to a
+QDateTime, and then relying on QVariant to convert it to a QTime. The end
+effect is that the date part of the \c Date object is ignored, but the
+local timezone will be used ignoring any DST complications it may have.
+
+
\section2 Sequence Type to JavaScript Array
Certain C++ sequence types are supported transparently in QML as JavaScript
@@ -381,6 +393,8 @@ Message {
}
\endqml
+To use an enum as a \l {QFlags}{flags} type in QML, see \l Q_FLAG().
+
\note The names of enum values must begin with a capital letter in order to
be accessible from QML.
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 593feb49e7..e06451b2bc 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -603,7 +603,7 @@ public:
RandomNumberGenerator(QObject *parent)
: QObject(parent), m_maxValue(100)
{
- qsrand(QDateTime::currentDateTime().toTime_t());
+ qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
QObject::connect(&m_timer, SIGNAL(timeout()), SLOT(updateProperty()));
m_timer.start(500);
}
diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
index f4f688520a..f5aea0b01a 100644
--- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
+++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
@@ -73,7 +73,7 @@ convert them as appropriately when used from QML. Additionally, C++ classes
that are \l{Registering C++ types with the QML type system}{registered} with
the QML type system can be can be used as data types, as can their enums if
appropriately registered. See \l{qtqml-cppintegration-data.html}{Data Type
-Conversion Between QML and C++} for details for further information.
+Conversion Between QML and C++} for further information.
Additionally, data ownership rules are taken into consideration when data is
transferred from C++ to QML. See \l {Data Ownership} for more details.
@@ -119,13 +119,13 @@ from C++:
\code
int main(int argc, char *argv[]) {
- QCoreApplication app(argc, argv);
+ QGuiApplication app(argc, argv);
- QQmlEngine engine;
+ QQuickView view;
Message msg;
- engine.rootContext()->setContextProperty("msg", &msg);
- QQmlComponent component(&engine, QUrl::fromLocalFile("MyItem.qml"));
- component.create();
+ view.engine()->rootContext()->setContextProperty("msg", &msg);
+ view.setSource(QUrl::fromLocalFile("MyItem.qml"));
+ view.show();
return app.exec();
}
diff --git a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
index c0cfc3e1aa..58cc650e01 100644
--- a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
+++ b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
@@ -389,7 +389,7 @@ directory.
When building this example on Windows or Linux, the \c Charts directory will be
located at the same level as the application that uses our new import module.
This way, the QML engine will find our module as the default search path for QML
-imports includes the directory of the application executable. On OS X, the
+imports includes the directory of the application executable. On \macos, the
plugin binary is copied to \c Contents/PlugIns in the the application bundle;
this path is set in \l {tutorials/extending-qml/chapter6-plugins/app.pro}
{chapter6-plugins/app.pro}:
diff --git a/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc b/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc
index acd7188db7..fffa783851 100644
--- a/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc
+++ b/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc
@@ -143,7 +143,7 @@ If the string of QML imports files using relative paths, the path should be
relative to the file in which the parent object (the second argument to the
method) is defined.
-\important When building static QML applications, which is enforced on platforms like iOS,
+\important When building static QML applications,
QML files are scanned to detect import dependencies. That way, all
necessary plugins and resources are resolved at compile time.
However, only explicit import statements are considered (those found at
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index e613c4fcfb..1e33f2f641 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -80,7 +80,10 @@ Note that QML makes the following modifications to native objects:
QML implements the following restrictions for JavaScript code:
\list
-\li JavaScript code cannot modify the global object.
+\li JavaScript code written in a \c .qml file cannot modify the global object.
+ JavaScript code in a .js file can modify the global object,
+ and those modifications will be visible to the .qml file when
+ \l {Importing a JavaScript Resource from a QML Document}{imported}.
In QML, the global object is constant - existing properties cannot be modified
or deleted, and no new properties may be created.
@@ -110,7 +113,7 @@ console.log("Result: " + a);
\endcode
Any attempt to modify the global object - either implicitly or explicitly - will
-cause an exception. If uncaught, this will result in an warning being printed,
+cause an exception. If uncaught, this will result in a warning being printed,
that includes the file and line number of the offending code.
\li Global code is run in a reduced scope.
@@ -120,7 +123,7 @@ code, it is executed in a scope that contains only the external file itself and
the global object. That is, it will not have access to the QML objects and
properties it \l {Scope and Naming Resolution}{normally would}.
-Global code that only accesses script local variable is permitted. This is an
+Global code that only accesses script local variables is permitted. This is an
example of valid global code.
\code
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 26fc40ff37..8b24d19891 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -180,6 +180,42 @@
*/
/*!
+ \fn static inline int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+ \relates QQmlEngine
+ \since 5.8
+
+ This function registers the \a staticMetaObject and its extension
+ in the QML system with the name \a qmlName in the library imported
+ from \a uri having version number composed from \a versionMajor and
+ \a versionMinor.
+
+ This function is useful to register Q_NAMESPACE namespaces.
+
+ Returns the QML type id.
+
+ Example:
+
+ \code
+ namespace MyNamespace {
+ Q_NAMESPACE
+ enum MyEnum {
+ Key1,
+ Key2,
+ };
+ Q_ENUMS(MyEnum)
+ }
+
+ //...
+ qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "io.qt", 1, 0, "MyNamespace", "Access to enums & flags only");
+ \endcode
+
+ Now on QML side you can use the registered enums:
+ \code
+ Component.onCompleted: console.log(MyNamespace.Key2)
+ \endcode
+*/
+
+/*!
\fn int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser)
\relates QQmlEngine
\internal
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 04d0d0ed2e..3692605c18 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -729,7 +729,7 @@ Rectangle {
MouseArea {
anchors.fill: parent
onPressed: root.activated(mouse.x, mouse.y)
- onRelased: root.deactivated()
+ onReleased: root.deactivated()
}
}
\endqml
@@ -855,7 +855,8 @@ are otherwise unavailable to the object. In particular, they allow objects to
access properties or signals that are specifically relevant to the individual
object.
-A QML type implementation may choose to create an \e {attaching type} with
+A QML type implementation may choose to \l {Providing Attached Objects for
+Data Annotations}{create an \e {attaching type} in C++} with
particular properties and signals. Instances of this type can then be created
and \e attached to specific objects at run time, allowing those objects to
access the properties and signals of the attaching type. These are accessed by
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index 33bb0c0750..747466281e 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -131,6 +131,19 @@ the QML code to interact with C++ code.
\li \l{The Declarative State Machine Framework}
\endlist
+\section1 Licenses and Attributions
+
+Qt QML is available under commercial licenses from \l{The Qt Company}.
+In addition, it is available under the
+\l{GNU Lesser General Public License, version 3}, or
+the \l{GNU General Public License, version 2}.
+See \l{Qt Licensing} for further details.
+
+Furthermore Qt QML potentially contains third party
+modules under following permissive licenses:
+
+\generatelist{groupsbymodule attributions-qtqml}
+
\section1 Guides and Other Information
Further information for writing QML applications:
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 7d0d93b63a..5e05f14192 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -79,20 +79,87 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
}
}
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
+{
+ const int codeAlignment = 16;
+ quint64 offset = WTF::roundUpToMultipleOf(codeAlignment, unit->unitSize);
+ Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
+ for (int i = 0; i < codeRefs.size(); ++i) {
+ CompiledData::Function *compiledFunction = const_cast<CompiledData::Function *>(unit->functionAt(i));
+ compiledFunction->codeOffset = offset;
+ compiledFunction->codeSize = codeRefs.at(i).size();
+ offset = WTF::roundUpToMultipleOf(codeAlignment, offset + compiledFunction->codeSize);
+ }
+}
+
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString)
+{
+ Q_ASSERT(device->pos() == unit->unitSize);
+ Q_ASSERT(device->atEnd());
+ Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
+
+ QByteArray padding;
+
+ for (int i = 0; i < codeRefs.size(); ++i) {
+ const CompiledData::Function *compiledFunction = unit->functionAt(i);
+
+ if (device->pos() > qint64(compiledFunction->codeOffset)) {
+ *errorString = QStringLiteral("Invalid state of cache file to write.");
+ return false;
+ }
+
+ const quint64 paddingSize = compiledFunction->codeOffset - device->pos();
+ padding.fill(0, paddingSize);
+ qint64 written = device->write(padding);
+ if (written != padding.size()) {
+ *errorString = device->errorString();
+ return false;
+ }
+
+ const void *undecoratedCodePtr = codeRefs.at(i).code().dataLocation();
+ written = device->write(reinterpret_cast<const char *>(undecoratedCodePtr), compiledFunction->codeSize);
+ if (written != qint64(compiledFunction->codeSize)) {
+ *errorString = device->errorString();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ codeRefs.resize(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
+ JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
+ JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
+ codeRefs[i] = codeRef;
+ }
+
+ return true;
+}
+
const Assembler::VoidType Assembler::Void;
Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
- : _constTable(this)
- , _function(function)
+ : _function(function)
, _nextBlock(0)
, _executableAllocator(executableAllocator)
, _isel(isel)
{
+ _addrs.resize(_function->basicBlockCount());
+ _patches.resize(_function->basicBlockCount());
+ _labelPatches.resize(_function->basicBlockCount());
}
void Assembler::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
{
- _addrs[block] = label();
+ _addrs[block->index()] = label();
catchBlock = block->catchBlock;
_nextBlock = nextBlock;
}
@@ -102,12 +169,12 @@ void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
Q_UNUSED(current);
if (target != _nextBlock)
- _patches[target].append(jump());
+ _patches[target->index()].push_back(jump());
}
void Assembler::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
{
- _patches[targetBlock].append(targetJump);
+ _patches[targetBlock->index()].push_back(targetJump);
}
void Assembler::addPatch(DataLabelPtr patch, Label target)
@@ -115,12 +182,12 @@ void Assembler::addPatch(DataLabelPtr patch, Label target)
DataLabelPatch p;
p.dataLabel = patch;
p.target = target;
- _dataLabelPatches.append(p);
+ _dataLabelPatches.push_back(p);
}
void Assembler::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
{
- _labelPatches[target].append(patch);
+ _labelPatches[target->index()].push_back(patch);
}
void Assembler::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
@@ -213,6 +280,19 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s
return Pointer(reg, id * sizeof(QV4::String*));
}
+Assembler::Address Assembler::loadConstant(IR::Const *c, RegisterID baseReg)
+{
+ return loadConstant(convertToValue(c), baseReg);
+}
+
+Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseReg)
+{
+ loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg);
+ loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg);
+ const int index = _isel->jsUnitGenerator()->registerConstant(v.asReturnedValue());
+ return Address(baseReg, index * sizeof(QV4::Value));
+}
+
void Assembler::loadStringRef(RegisterID reg, const QString &string)
{
const int id = _isel->registerString(string);
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index 9a681bc9ba..7d4d90882a 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -58,8 +58,6 @@
#include "private/qv4lookup_p.h"
#include "qv4targetplatform_p.h"
-#include <QtCore/QHash>
-#include <QtCore/QStack>
#include <config.h>
#include <wtf/Vector.h>
@@ -81,12 +79,14 @@ struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
- virtual void linkBackendToEngine(QV4::ExecutionEngine *engine);
+ void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
+ bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
// Coderef + execution engine
QVector<JSC::MacroAssemblerCodeRef> codeRefs;
- QList<QVector<QV4::Primitive> > constantValues;
};
struct LookupCall {
@@ -102,40 +102,10 @@ struct LookupCall {
struct RuntimeCall {
JSC::MacroAssembler::Address addr;
- inline RuntimeCall(uint offset = INT_MIN);
+ inline RuntimeCall(uint offset = uint(INT_MIN));
bool isValid() const { return addr.offset >= 0; }
};
-template <typename T>
-struct ExceptionCheck {
- enum { NeedsCheck = 1 };
-};
-// push_catch and pop context methods shouldn't check for exceptions
-template <>
-struct ExceptionCheck<void (*)(QV4::ExecutionEngine *)> {
- enum { NeedsCheck = 0 };
-};
-template <typename A>
-struct ExceptionCheck<void (*)(A, QV4::NoThrowEngine)> {
- enum { NeedsCheck = 0 };
-};
-template <>
-struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *)> {
- enum { NeedsCheck = 0 };
-};
-template <typename A>
-struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A)> {
- enum { NeedsCheck = 0 };
-};
-template <typename A, typename B>
-struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A, B)> {
- enum { NeedsCheck = 0 };
-};
-template <typename A, typename B, typename C>
-struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
- enum { NeedsCheck = 0 };
-};
-
class Assembler : public JSC::MacroAssembler, public TargetPlatform
{
Q_DISABLE_COPY(Assembler)
@@ -294,22 +264,6 @@ public:
int savedRegCount;
};
- class ConstantTable
- {
- public:
- ConstantTable(Assembler *as): _as(as) {}
-
- int add(const QV4::Primitive &v);
- Address loadValueAddress(IR::Const *c, RegisterID baseReg);
- Address loadValueAddress(const QV4::Primitive &v, RegisterID baseReg);
- void finalize(JSC::LinkBuffer &linkBuffer, InstructionSelection *isel);
-
- private:
- Assembler *_as;
- QVector<QV4::Primitive> _values;
- QVector<DataLabelPtr> _toPatch;
- };
-
struct VoidType { VoidType() {} };
static const VoidType Void;
@@ -338,11 +292,6 @@ public:
IR::Expr *value;
};
- struct ReentryBlock {
- ReentryBlock(IR::BasicBlock *b) : block(b) {}
- IR::BasicBlock *block;
- };
-
void callAbsolute(const char* /*functionName*/, const LookupCall &lookupCall)
{
call(lookupCall.addr);
@@ -384,6 +333,8 @@ public:
Pointer loadTempAddress(IR::Temp *t);
Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al);
Pointer loadStringAddress(RegisterID reg, const QString &string);
+ Address loadConstant(IR::Const *c, RegisterID baseReg);
+ Address loadConstant(const Primitive &v, RegisterID baseReg);
void loadStringRef(RegisterID reg, const QString &string);
Pointer stackSlotPointer(IR::Temp *t) const
{
@@ -431,13 +382,6 @@ public:
move(source, dest);
}
- void loadArgumentInRegister(TrustedImmPtr ptr, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- move(TrustedImmPtr(ptr), dest);
- }
-
void loadArgumentInRegister(const Pointer& ptr, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
@@ -447,7 +391,7 @@ public:
void loadArgumentInRegister(PointerToValue temp, RegisterID dest, int argumentNumber)
{
if (!temp.value) {
- loadArgumentInRegister(TrustedImmPtr(0), dest, argumentNumber);
+ move(TrustedImmPtr(0), dest);
} else {
Pointer addr = toAddress(dest, temp.value, argumentNumber);
loadArgumentInRegister(addr, dest, argumentNumber);
@@ -466,15 +410,6 @@ public:
loadArgumentInRegister(addr, dest, argumentNumber);
}
- void loadArgumentInRegister(ReentryBlock block, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- Q_ASSERT(block.block);
- DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), dest);
- addPatch(patch, block.block);
- }
-
#ifdef VALUE_FITS_IN_REGISTER
void loadArgumentInRegister(IR::Temp* temp, RegisterID dest, int argumentNumber)
{
@@ -534,11 +469,6 @@ public:
}
#endif
- void loadArgumentInRegister(QV4::String* string, RegisterID dest, int argumentNumber)
- {
- loadArgumentInRegister(TrustedImmPtr(string), dest, argumentNumber);
- }
-
void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
@@ -695,34 +625,6 @@ public:
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
}
- template <int StackSlot>
- void loadArgumentOnStack(ReentryBlock block, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- Q_ASSERT(block.block);
- DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), ScratchRegister);
- poke(ScratchRegister, StackSlot);
- addPatch(patch, block.block);
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(TrustedImmPtr ptr, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- move(TrustedImmPtr(ptr), ScratchRegister);
- poke(ScratchRegister, StackSlot);
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(QV4::String* name, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- poke(TrustedImmPtr(name), StackSlot);
- }
-
void loadDouble(IR::Expr *source, FPRegisterID dest)
{
IR::Temp *sourceTemp = source->asTemp();
@@ -875,7 +777,7 @@ public:
};
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
- void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
+ void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
{
int stackSpaceNeeded = SizeOnStack<0, Arg1>::Size
+ SizeOnStack<1, Arg2>::Size
@@ -918,7 +820,7 @@ public:
if (stackSpaceNeeded)
addPtr(TrustedImm32(stackSpaceNeeded), StackPointerRegister);
- if (ExceptionCheck<Callable>::NeedsCheck) {
+ if (needsExceptionCheck) {
checkException();
}
@@ -927,33 +829,33 @@ public:
}
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
- void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
{
- generateFunctionCallImp(r, functionName, function, arg1, arg2, arg3, arg4, arg5, VoidType());
+ generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, arg2, arg3, arg4, arg5, VoidType());
}
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
- void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
{
- generateFunctionCallImp(r, functionName, function, arg1, arg2, arg3, arg4, VoidType(), VoidType());
+ generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, arg2, arg3, arg4, VoidType(), VoidType());
}
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3>
- void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3)
{
- generateFunctionCallImp(r, functionName, function, arg1, arg2, arg3, VoidType(), VoidType(), VoidType());
+ generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, arg2, arg3, VoidType(), VoidType(), VoidType());
}
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2>
- void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2)
+ void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2)
{
- generateFunctionCallImp(r, functionName, function, arg1, arg2, VoidType(), VoidType(), VoidType(), VoidType());
+ generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, arg2, VoidType(), VoidType(), VoidType(), VoidType());
}
template <typename ArgRet, typename Callable, typename Arg1>
- void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1)
+ void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1)
{
- generateFunctionCallImp(r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType(), VoidType());
+ generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType(), VoidType());
}
Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset)
@@ -1080,7 +982,7 @@ public:
move(TrustedImm64(i), ReturnValueRegister);
move64ToDouble(ReturnValueRegister, target);
#else
- JSC::MacroAssembler::loadDouble(constantTable().loadValueAddress(c, ScratchRegister), target);
+ JSC::MacroAssembler::loadDouble(loadConstant(c, ScratchRegister), target);
#endif
return target;
}
@@ -1144,9 +1046,8 @@ public:
// it's not in signed int range, so load it as a double, and truncate it down
loadDouble(addr, FPGpr0);
- static const double magic = double(INT_MAX) + 1;
- move(TrustedImmPtr(&magic), scratchReg);
- subDouble(Address(scratchReg, 0), FPGpr0);
+ Address inversionAddress = loadConstant(QV4::Primitive::fromDouble(double(INT_MAX) + 1), scratchReg);
+ subDouble(inversionAddress, FPGpr0);
Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg);
canNeverHappen.link(this);
or32(TrustedImm32(1 << 31), scratchReg);
@@ -1163,17 +1064,15 @@ public:
void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave);
const StackLayout &stackLayout() const { return *_stackLayout.data(); }
- ConstantTable &constantTable() { return _constTable; }
Label exceptionReturnLabel;
IR::BasicBlock * catchBlock;
QVector<Jump> exceptionPropagationJumps;
private:
QScopedPointer<const StackLayout> _stackLayout;
- ConstantTable _constTable;
IR::Function *_function;
- QHash<IR::BasicBlock *, Label> _addrs;
- QHash<IR::BasicBlock *, QVector<Jump> > _patches;
+ std::vector<Label> _addrs;
+ std::vector<std::vector<Jump>> _patches;
#ifndef QT_NO_DEBUG
QVector<CallInfo> _callInfos;
#endif
@@ -1182,9 +1081,9 @@ private:
DataLabelPtr dataLabel;
Label target;
};
- QList<DataLabelPatch> _dataLabelPatches;
+ std::vector<DataLabelPatch> _dataLabelPatches;
- QHash<IR::BasicBlock *, QVector<DataLabelPtr> > _labelPatches;
+ std::vector<std::vector<DataLabelPtr>> _labelPatches;
IR::BasicBlock *_nextBlock;
QV4::ExecutableAllocator *_executableAllocator;
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index c09fc6fdca..9c535bb0bb 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -45,17 +45,17 @@ using namespace QV4;
using namespace JIT;
#define OP(op) \
- { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, 0, 0 }
+ { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
#define OPCONTEXT(op) \
- { "Runtime::" isel_stringIfy(op), INT_MIN, offsetof(QV4::Runtime, op), 0, 0 }
+ { "Runtime::" isel_stringIfy(op), INT_MIN, offsetof(QV4::Runtime, op), 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
#define INLINE_OP(op, memOp, immOp) \
- { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, memOp, immOp }
+ { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, memOp, immOp, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
#define INLINE_OPCONTEXT(op, memOp, immOp) \
- { "Runtime::" isel_stringIfy(op), INT_MIN, offsetof(QV4::Runtime, op), memOp, immOp }
+ { "Runtime::" isel_stringIfy(op), INT_MIN, offsetof(QV4::Runtime, op), memOp, immOp, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
#define NULL_OP \
- { 0, 0, 0, 0, 0 }
+ { 0, 0, 0, 0, 0, false }
const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
NULL_OP, // OpInvalid
@@ -128,11 +128,11 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
RuntimeCall fallBack(info.fallbackImplementation);
RuntimeCall context(info.contextImplementation);
if (fallBack.isValid()) {
- as->generateFunctionCallImp(target, info.name, fallBack,
+ as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, fallBack,
Assembler::PointerToValue(lhs),
Assembler::PointerToValue(rhs));
} else if (context.isValid()) {
- as->generateFunctionCallImp(target, info.name, context,
+ as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, context,
Assembler::EngineRegister,
Assembler::PointerToValue(lhs),
Assembler::PointerToValue(rhs));
@@ -162,7 +162,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Assembler::Address addr = as->constantTable().loadValueAddress(c, Assembler::ScratchRegister);
+ Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister);
as->addDouble(addr, targetReg);
break;
}
@@ -184,7 +184,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Assembler::Address addr = as->constantTable().loadValueAddress(c, Assembler::ScratchRegister);
+ Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister);
as->mulDouble(addr, targetReg);
break;
}
@@ -203,7 +203,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Assembler::Address addr = as->constantTable().loadValueAddress(c, Assembler::ScratchRegister);
+ Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister);
as->subDouble(addr, targetReg);
break;
}
@@ -231,7 +231,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Assembler::Address addr = as->constantTable().loadValueAddress(c, Assembler::ScratchRegister);
+ Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister);
as->divDouble(addr, targetReg);
break;
}
diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h
index c246ee43b0..37601f54ba 100644
--- a/src/qml/jit/qv4binop_p.h
+++ b/src/qml/jit/qv4binop_p.h
@@ -81,6 +81,7 @@ struct Binop {
int contextImplementation; // offsetOf(Runtime,...)
MemRegOp inlineMemRegOp;
ImmRegOp inlineImmRegOp;
+ bool needsExceptionCheck;
};
static const OpInfo operations[IR::LastAluOp + 1];
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 1f5a247a17..12b1eb4473 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -49,7 +49,6 @@
#include "qv4assembler_p.h"
#include "qv4unop_p.h"
#include "qv4binop_p.h"
-#include <private/qqmlpropertycache_p.h>
#include <QtCore/QBuffer>
#include <QtCore/QCoreApplication>
@@ -114,8 +113,7 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput, const Q
{
for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end();
it != end; ++it) {
- QByteArray ptrString = QByteArray::number(quintptr(it.key()), 16);
- ptrString.prepend("0x");
+ const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16);
int idx = processedOutput.indexOf(ptrString);
if (idx < 0)
continue;
@@ -146,13 +144,10 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
Label endOfCode = label();
{
- QHashIterator<IR::BasicBlock *, QVector<Jump> > it(_patches);
- while (it.hasNext()) {
- it.next();
- IR::BasicBlock *block = it.key();
- Label target = _addrs.value(block);
+ for (size_t i = 0, ei = _patches.size(); i != ei; ++i) {
+ Label target = _addrs.at(i);
Q_ASSERT(target.isSet());
- foreach (Jump jump, it.value())
+ for (Jump jump : qAsConst(_patches.at(i)))
jump.linkTo(target, this);
}
}
@@ -160,25 +155,21 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
JSC::JSGlobalData dummy(_executableAllocator);
JSC::LinkBuffer linkBuffer(dummy, this, 0);
- foreach (const DataLabelPatch &p, _dataLabelPatches)
+ for (const DataLabelPatch &p : qAsConst(_dataLabelPatches))
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
// link exception handlers
- foreach(Jump jump, exceptionPropagationJumps)
+ for (Jump jump : qAsConst(exceptionPropagationJumps))
linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel));
{
- QHashIterator<IR::BasicBlock *, QVector<DataLabelPtr> > it(_labelPatches);
- while (it.hasNext()) {
- it.next();
- IR::BasicBlock *block = it.key();
- Label target = _addrs.value(block);
+ for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) {
+ Label target = _addrs.at(i);
Q_ASSERT(target.isSet());
- foreach (DataLabelPtr label, it.value())
+ for (DataLabelPtr label : _labelPatches.at(i))
linkBuffer.patch(label, linkBuffer.locationOf(target));
}
}
- _constTable.finalize(linkBuffer, _isel);
*codeSize = linkBuffer.offsetOf(endOfCode);
@@ -190,7 +181,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
if (showCode) {
QHash<void*, const char*> functions;
#ifndef QT_NO_DEBUG
- foreach (CallInfo call, _callInfos)
+ for (CallInfo call : qAsConst(_callInfos))
functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName;
#endif
@@ -199,11 +190,8 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
WTF::setDataFile(new QIODevicePrintStream(&buf));
name = _function->name->toUtf8();
- if (name.isEmpty()) {
- name = QByteArray::number(quintptr(_function), 16);
- name.prepend("IR::Function(0x");
- name.append(')');
- }
+ if (name.isEmpty())
+ name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')';
codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
WTF::setDataFile(stderr);
@@ -240,11 +228,8 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
// this may have been pre-populated, if QV4_SHOW_ASM was on
if (name.isEmpty()) {
name = _function->name->toUtf8();
- if (name.isEmpty()) {
- name = QByteArray::number(quintptr(_function), 16);
- name.prepend("IR::Function(0x");
- name.append(')');
- }
+ if (name.isEmpty())
+ name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')';
}
fprintf(pmap, "%llx %x %.*s\n",
@@ -259,14 +244,15 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
return codeRef;
}
-InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator)
- : EvalInstructionSelection(execAllocator, module, jsGenerator)
+InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
+ : EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
, _block(0)
, _as(0)
, compilationUnit(new CompilationUnit)
, qmlEngine(qmlEngine)
{
compilationUnit->codeRefs.resize(module->functions.size());
+ module->unitFlags |= QV4::CompiledData::Unit::ContainsMachineCode;
}
InstructionSelection::~InstructionSelection()
@@ -295,7 +281,7 @@ void InstructionSelection::run(int functionIndex)
IR::Optimizer::showMeTheCode(_function, "After stack slot allocation");
calculateRegistersToSave(Assembler::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
}
- QSet<IR::Jump *> removableJumps = opt.calculateOptionalJumps();
+ BitVector removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
Assembler* oldAssembler = _as;
@@ -345,7 +331,7 @@ void InstructionSelection::run(int functionIndex)
continue;
_as->registerBlock(_block, nextBlock);
- foreach (IR::Stmt *s, _block->statements()) {
+ for (IR::Stmt *s : _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
_as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
@@ -354,7 +340,7 @@ void InstructionSelection::run(int functionIndex)
lastLine = s->location.startLine;
}
}
- s->accept(this);
+ visit(s);
}
}
@@ -371,16 +357,6 @@ void InstructionSelection::run(int functionIndex)
qSwap(_removableJumps, removableJumps);
}
-const void *InstructionSelection::addConstantTable(QVector<Primitive> *values)
-{
- compilationUnit->constantValues.append(*values);
- values->clear();
-
- QVector<QV4::Primitive> &finalValues = compilationUnit->constantValues.last();
- finalValues.squeeze();
- return finalValues.constData();
-}
-
QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep()
{
QQmlRefPointer<QV4::CompiledData::CompilationUnit> result;
@@ -754,94 +730,20 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::
}
}
-void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target)
+void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
{
- if (property && property->hasAccessors() && property->isFullyResolved()) {
- if (kind == IR::Member::MemberOfQmlScopeObject) {
- if (property->propType == QMetaType::QReal) {
- generateRuntimeCall(target, accessQmlScopeObjectQRealProperty,
- Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors));
- return;
- } else if (property->isQObject()) {
- generateRuntimeCall(target, accessQmlScopeObjectQObjectProperty,
- Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors));
- return;
- } else if (property->propType == QMetaType::Int) {
- generateRuntimeCall(target, accessQmlScopeObjectIntProperty,
- Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors));
- return;
- } else if (property->propType == QMetaType::Bool) {
- generateRuntimeCall(target, accessQmlScopeObjectBoolProperty,
- Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors));
- return;
- } else if (property->propType == QMetaType::QString) {
- generateRuntimeCall(target, accessQmlScopeObjectQStringProperty,
- Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors));
- return;
- }
- }
- }
-
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
+ generateRuntimeCall(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(target, getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
+ generateRuntimeCall(target, getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired));
else if (kind == IR::Member::MemberOfIdObjectsArray)
generateRuntimeCall(target, getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
else
Q_ASSERT(false);
}
-void InstructionSelection::getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
+void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
{
- if (property && property->hasAccessors() && property->isFullyResolved()) {
- if (!attachedPropertiesId && !isSingleton) {
- const int notifyIndex = captureRequired ? property->notifyIndex : -1;
- if (property->propType == QMetaType::QReal) {
- generateRuntimeCall(target, accessQObjectQRealProperty,
- Assembler::EngineRegister, Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors),
- Assembler::TrustedImm32(property->coreIndex),
- Assembler::TrustedImm32(notifyIndex));
- return;
- } else if (property->isQObject()) {
- generateRuntimeCall(target, accessQObjectQObjectProperty,
- Assembler::EngineRegister, Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors),
- Assembler::TrustedImm32(property->coreIndex),
- Assembler::TrustedImm32(notifyIndex));
- return;
- } else if (property->propType == QMetaType::Int) {
- generateRuntimeCall(target, accessQObjectIntProperty,
- Assembler::EngineRegister, Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors),
- Assembler::TrustedImm32(property->coreIndex),
- Assembler::TrustedImm32(notifyIndex));
- return;
- } else if (property->propType == QMetaType::Bool) {
- generateRuntimeCall(target, accessQObjectBoolProperty,
- Assembler::EngineRegister, Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors),
- Assembler::TrustedImm32(property->coreIndex),
- Assembler::TrustedImm32(notifyIndex));
- return;
- } else if (property->propType == QMetaType::QString) {
- generateRuntimeCall(target, accessQObjectQStringProperty,
- Assembler::EngineRegister, Assembler::PointerToValue(base),
- Assembler::TrustedImmPtr(property->accessors),
- Assembler::TrustedImm32(property->coreIndex),
- Assembler::TrustedImm32(notifyIndex));
- return;
- }
- }
- }
-
- const int propertyIndex = property->coreIndex;
if (attachedPropertiesId != 0)
generateRuntimeCall(target, getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
else if (isSingleton)
@@ -1056,9 +958,15 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
}
#define setOp(op, opName, operation) \
- do { op = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); } while (0)
+ do { \
+ op = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
+ } while (0)
#define setOpContext(op, opName, operation) \
- do { opContext = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); } while (0)
+ do { \
+ opContext = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
+ } while (0)
void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
{
@@ -1469,7 +1377,7 @@ void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, I
void InstructionSelection::visitJump(IR::Jump *s)
{
- if (!_removableJumps.contains(s))
+ if (!_removableJumps.at(_block->index()))
_as->jumpToBlock(_block, s->target);
}
@@ -1532,18 +1440,19 @@ void InstructionSelection::visitCJump(IR::CJump *s)
RuntimeCall op;
RuntimeCall opContext;
const char *opName = 0;
+ bool needsExceptionCheck;
switch (b->op) {
default: Q_UNREACHABLE(); Q_ASSERT(!"todo"); break;
- case IR::OpGt: setOp(op, opName, Runtime::compareGreaterThan); break;
- case IR::OpLt: setOp(op, opName, Runtime::compareLessThan); break;
- case IR::OpGe: setOp(op, opName, Runtime::compareGreaterEqual); break;
- case IR::OpLe: setOp(op, opName, Runtime::compareLessEqual); break;
- case IR::OpEqual: setOp(op, opName, Runtime::compareEqual); break;
- case IR::OpNotEqual: setOp(op, opName, Runtime::compareNotEqual); break;
- case IR::OpStrictEqual: setOp(op, opName, Runtime::compareStrictEqual); break;
- case IR::OpStrictNotEqual: setOp(op, opName, Runtime::compareStrictNotEqual); break;
- case IR::OpInstanceof: setOpContext(op, opName, Runtime::compareInstanceof); break;
- case IR::OpIn: setOpContext(op, opName, Runtime::compareIn); break;
+ case IR::OpGt: setOp(op, opName, compareGreaterThan); break;
+ case IR::OpLt: setOp(op, opName, compareLessThan); break;
+ case IR::OpGe: setOp(op, opName, compareGreaterEqual); break;
+ case IR::OpLe: setOp(op, opName, compareLessEqual); break;
+ case IR::OpEqual: setOp(op, opName, compareEqual); break;
+ case IR::OpNotEqual: setOp(op, opName, compareNotEqual); break;
+ case IR::OpStrictEqual: setOp(op, opName, compareStrictEqual); break;
+ case IR::OpStrictNotEqual: setOp(op, opName, compareStrictNotEqual); break;
+ case IR::OpInstanceof: setOpContext(op, opName, compareInstanceof); break;
+ case IR::OpIn: setOpContext(op, opName, compareIn); break;
} // switch
// TODO: in SSA optimization, do constant expression evaluation.
@@ -1552,12 +1461,14 @@ void InstructionSelection::visitCJump(IR::CJump *s)
// Of course, after folding the CJUMP to a JUMP, dead-code (dead-basic-block)
// elimination (which isn't there either) would remove the whole else block.
if (opContext.isValid())
- _as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, opContext,
+ _as->generateFunctionCallImp(needsExceptionCheck,
+ Assembler::ReturnValueRegister, opName, opContext,
Assembler::EngineRegister,
Assembler::PointerToValue(b->left),
Assembler::PointerToValue(b->right));
else
- _as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, op,
+ _as->generateFunctionCallImp(needsExceptionCheck,
+ Assembler::ReturnValueRegister, opName, op,
Assembler::PointerToValue(b->left),
Assembler::PointerToValue(b->right));
@@ -1765,7 +1676,7 @@ void InstructionSelection::calculateRegistersToSave(const RegisterInformation &u
regularRegistersToSave.clear();
fpRegistersToSave.clear();
- foreach (const RegisterInfo &ri, Assembler::getRegisterInfo()) {
+ for (const RegisterInfo &ri : Assembler::getRegisterInfo()) {
#if defined(RESTORE_EBX_ON_CALL)
if (ri.isRegularRegister() && ri.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
regularRegistersToSave.append(ri);
@@ -1794,38 +1705,6 @@ bool operator==(const Primitive &v1, const Primitive &v2)
} // QV4 namespace
QT_END_NAMESPACE
-int Assembler::ConstantTable::add(const Primitive &v)
-{
- int idx = _values.indexOf(v);
- if (idx == -1) {
- idx = _values.size();
- _values.append(v);
- }
- return idx;
-}
-
-Assembler::Address Assembler::ConstantTable::loadValueAddress(IR::Const *c, RegisterID baseReg)
-{
- return loadValueAddress(convertToValue(c), baseReg);
-}
-
-Assembler::Address Assembler::ConstantTable::loadValueAddress(const Primitive &v, RegisterID baseReg)
-{
- _toPatch.append(_as->moveWithPatch(TrustedImmPtr(0), baseReg));
- Address addr(baseReg);
- addr.offset = add(v) * sizeof(QV4::Primitive);
- Q_ASSERT(addr.offset >= 0);
- return addr;
-}
-
-void Assembler::ConstantTable::finalize(JSC::LinkBuffer &linkBuffer, InstructionSelection *isel)
-{
- const void *tablePtr = isel->addConstantTable(&_values);
-
- foreach (DataLabelPtr label, _toPatch)
- linkBuffer.patch(label, const_cast<void *>(tablePtr));
-}
-
bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
{
@@ -2036,5 +1915,11 @@ void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *tru
_block, trueBlock, falseBlock);
}
+QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
+{
+ QQmlRefPointer<CompiledData::CompilationUnit> result;
+ result.adopt(new JIT::CompilationUnit);
+ return result;
+}
#endif // ENABLE(ASSEMBLER)
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index db9d440e83..1742ff9a36 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -54,6 +54,7 @@
#include "private/qv4jsir_p.h"
#include "private/qv4isel_p.h"
#include "private/qv4isel_util_p.h"
+#include "private/qv4util_p.h"
#include "private/qv4value_p.h"
#include "private/qv4lookup_p.h"
@@ -76,12 +77,11 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory);
~InstructionSelection();
virtual void run(int functionIndex);
- const void *addConstantTable(QVector<QV4::Primitive> *values);
protected:
virtual QQmlRefPointer<QV4::CompiledData::CompilationUnit> backendCompileStep();
@@ -124,8 +124,8 @@ protected:
virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
virtual void initClosure(IR::Closure *closure, IR::Expr *target);
virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target);
- virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target);
- virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
+ virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target);
+ virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName);
virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex);
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex);
@@ -245,7 +245,7 @@ private:
#define isel_stringIfy(s) isel_stringIfyx(s)
#define generateRuntimeCall(t, function, ...) \
- _as->generateFunctionCallImp(t, "Runtime::" isel_stringIfy(function), RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
+ _as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
int prepareVariableArguments(IR::ExprList* args);
int prepareCallData(IR::ExprList* args, IR::Expr *thisObject);
@@ -261,7 +261,7 @@ private:
// address.
Assembler::Pointer lookupAddr(Assembler::ReturnValueRegister, index * sizeof(QV4::Lookup));
- _as->generateFunctionCallImp(retval, "lookup getter/setter",
+ _as->generateFunctionCallImp(true, retval, "lookup getter/setter",
LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
arg1, arg2, arg3);
}
@@ -273,7 +273,7 @@ private:
}
IR::BasicBlock *_block;
- QSet<IR::Jump *> _removableJumps;
+ BitVector _removableJumps;
Assembler* _as;
QScopedPointer<CompilationUnit> compilationUnit;
@@ -285,11 +285,13 @@ private:
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
+ ISelFactory() : EvalISelFactory(QStringLiteral("jit")) {}
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
- virtual bool jitCompileRegexps() const
+ EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) Q_DECL_OVERRIDE Q_DECL_FINAL
+ { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator, this); }
+ bool jitCompileRegexps() const Q_DECL_OVERRIDE Q_DECL_FINAL
{ return true; }
+ QQmlRefPointer<CompiledData::CompilationUnit> createUnitForLoading() Q_DECL_OVERRIDE Q_DECL_FINAL;
};
} // end of namespace JIT
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index 6b5b79e458..63d542b5c8 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -87,7 +87,7 @@ public:
{}
protected:
- void addStmtNr(Stmt *s)
+ void addStmtNr(Stmt *s) Q_DECL_OVERRIDE Q_DECL_FINAL
{
addJustifiedNr(intervals->positionForStatement(s));
}
@@ -115,7 +115,7 @@ public:
}
protected:
- void visitTemp(Temp *e)
+ void visitTemp(Temp *e) Q_DECL_OVERRIDE Q_DECL_FINAL
{
switch (e->kind) {
case Temp::PhysicalRegister: {
@@ -184,7 +184,7 @@ public:
_currentBB = bb;
for (Stmt *s : bb->statements()) {
_currentStmt = s;
- s->accept(this);
+ visit(s);
}
}
}
@@ -272,32 +272,32 @@ public:
}
protected: // IRDecoder
- virtual void callBuiltinInvalid(IR::Name *, IR::ExprList *, IR::Expr *) {}
- virtual void callBuiltinTypeofQmlContextProperty(IR::Expr *, IR::Member::MemberKind, int, IR::Expr *) {}
- virtual void callBuiltinTypeofMember(IR::Expr *, const QString &, IR::Expr *) {}
- virtual void callBuiltinTypeofSubscript(IR::Expr *, IR::Expr *, IR::Expr *) {}
- virtual void callBuiltinTypeofName(const QString &, IR::Expr *) {}
- virtual void callBuiltinTypeofValue(IR::Expr *, IR::Expr *) {}
- virtual void callBuiltinDeleteMember(IR::Expr *, const QString &, IR::Expr *) {}
- virtual void callBuiltinDeleteSubscript(IR::Expr *, IR::Expr *, IR::Expr *) {}
- virtual void callBuiltinDeleteName(const QString &, IR::Expr *) {}
- virtual void callBuiltinDeleteValue(IR::Expr *) {}
- virtual void callBuiltinThrow(IR::Expr *) {}
- virtual void callBuiltinReThrow() {}
- virtual void callBuiltinUnwindException(IR::Expr *) {}
- virtual void callBuiltinPushCatchScope(const QString &) {};
- virtual void callBuiltinForeachIteratorObject(IR::Expr *, IR::Expr *) {}
+ void callBuiltinInvalid(IR::Name *, IR::ExprList *, IR::Expr *) override {}
+ void callBuiltinTypeofQmlContextProperty(IR::Expr *, IR::Member::MemberKind, int, IR::Expr *) override {}
+ void callBuiltinTypeofMember(IR::Expr *, const QString &, IR::Expr *) override {}
+ void callBuiltinTypeofSubscript(IR::Expr *, IR::Expr *, IR::Expr *) override {}
+ void callBuiltinTypeofName(const QString &, IR::Expr *) override {}
+ void callBuiltinTypeofValue(IR::Expr *, IR::Expr *) override {}
+ void callBuiltinDeleteMember(IR::Expr *, const QString &, IR::Expr *) override {}
+ void callBuiltinDeleteSubscript(IR::Expr *, IR::Expr *, IR::Expr *) override {}
+ void callBuiltinDeleteName(const QString &, IR::Expr *) override {}
+ void callBuiltinDeleteValue(IR::Expr *) override {}
+ void callBuiltinThrow(IR::Expr *) override {}
+ void callBuiltinReThrow() override {}
+ void callBuiltinUnwindException(IR::Expr *) override {}
+ void callBuiltinPushCatchScope(const QString &) override {};
+ void callBuiltinForeachIteratorObject(IR::Expr *, IR::Expr *) override {}
virtual void callBuiltinForeachNextProperty(IR::Temp *, IR::Temp *) {}
- virtual void callBuiltinForeachNextPropertyname(IR::Expr *, IR::Expr *) {}
- virtual void callBuiltinPushWithScope(IR::Expr *) {}
- virtual void callBuiltinPopScope() {}
- virtual void callBuiltinDeclareVar(bool , const QString &) {}
- virtual void callBuiltinDefineArray(IR::Expr *, IR::ExprList *) {}
- virtual void callBuiltinDefineObjectLiteral(IR::Expr *, int, IR::ExprList *, IR::ExprList *, bool) {}
- virtual void callBuiltinSetupArgumentObject(IR::Expr *) {}
- virtual void callBuiltinConvertThisToObject() {}
+ void callBuiltinForeachNextPropertyname(IR::Expr *, IR::Expr *) override {}
+ void callBuiltinPushWithScope(IR::Expr *) override {}
+ void callBuiltinPopScope() override {}
+ void callBuiltinDeclareVar(bool , const QString &) override {}
+ void callBuiltinDefineArray(IR::Expr *, IR::ExprList *) override {}
+ void callBuiltinDefineObjectLiteral(IR::Expr *, int, IR::ExprList *, IR::ExprList *, bool) override {}
+ void callBuiltinSetupArgumentObject(IR::Expr *) override {}
+ void callBuiltinConvertThisToObject() override {}
- virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
+ void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) override
{
addDef(result);
if (IR::Temp *tempValue = value->asTemp())
@@ -306,7 +306,8 @@ protected: // IRDecoder
addCall();
}
- virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int propertyIndex, IR::ExprList *args, IR::Expr *result)
+ void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int propertyIndex,
+ IR::ExprList *args, IR::Expr *result) override
{
Q_UNUSED(propertyIndex)
@@ -316,8 +317,8 @@ protected: // IRDecoder
addCall();
}
- virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
- IR::Expr *result)
+ void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
+ IR::Expr *result) override
{
Q_UNUSED(name)
@@ -327,8 +328,8 @@ protected: // IRDecoder
addCall();
}
- virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
- IR::Expr *result)
+ void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
+ IR::Expr *result) override
{
addDef(result);
addUses(base->asTemp(), Use::CouldHaveRegister);
@@ -337,7 +338,7 @@ protected: // IRDecoder
addCall();
}
- virtual void convertType(IR::Expr *source, IR::Expr *target)
+ void convertType(IR::Expr *source, IR::Expr *target) override
{
addDef(target);
@@ -410,14 +411,14 @@ protected: // IRDecoder
addHint(target->asTemp(), sourceTemp);
}
- virtual void constructActivationProperty(IR::Name *, IR::ExprList *args, IR::Expr *result)
+ void constructActivationProperty(IR::Name *, IR::ExprList *args, IR::Expr *result) override
{
addDef(result);
addUses(args, Use::CouldHaveRegister);
addCall();
}
- virtual void constructProperty(IR::Expr *base, const QString &, IR::ExprList *args, IR::Expr *result)
+ void constructProperty(IR::Expr *base, const QString &, IR::ExprList *args, IR::Expr *result) override
{
addDef(result);
addUses(base, Use::CouldHaveRegister);
@@ -425,7 +426,7 @@ protected: // IRDecoder
addCall();
}
- virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
+ void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) override
{
addDef(result);
addUses(value, Use::CouldHaveRegister);
@@ -433,24 +434,24 @@ protected: // IRDecoder
addCall();
}
- virtual void loadThisObject(IR::Expr *temp)
+ void loadThisObject(IR::Expr *temp) override
{
addDef(temp);
}
- virtual void loadQmlContext(IR::Expr *temp)
+ void loadQmlContext(IR::Expr *temp) override
{
addDef(temp);
addCall();
}
- virtual void loadQmlImportedScripts(IR::Expr *temp)
+ void loadQmlImportedScripts(IR::Expr *temp) override
{
addDef(temp);
addCall();
}
- virtual void loadQmlSingleton(const QString &/*name*/, Expr *temp)
+ void loadQmlSingleton(const QString &/*name*/, Expr *temp) override
{
Q_UNUSED(temp);
@@ -458,21 +459,21 @@ protected: // IRDecoder
addCall();
}
- virtual void loadConst(IR::Const *sourceConst, Expr *targetTemp)
+ void loadConst(IR::Const *sourceConst, Expr *targetTemp) override
{
Q_UNUSED(sourceConst);
addDef(targetTemp);
}
- virtual void loadString(const QString &str, Expr *targetTemp)
+ void loadString(const QString &str, Expr *targetTemp) override
{
Q_UNUSED(str);
addDef(targetTemp);
}
- virtual void loadRegexp(IR::RegExp *sourceRegexp, Expr *targetTemp)
+ void loadRegexp(IR::RegExp *sourceRegexp, Expr *targetTemp) override
{
Q_UNUSED(sourceRegexp);
@@ -480,19 +481,19 @@ protected: // IRDecoder
addCall();
}
- virtual void getActivationProperty(const IR::Name *, Expr *temp)
+ void getActivationProperty(const IR::Name *, Expr *temp) override
{
addDef(temp);
addCall();
}
- virtual void setActivationProperty(IR::Expr *source, const QString &)
+ void setActivationProperty(IR::Expr *source, const QString &) override
{
addUses(source->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void initClosure(IR::Closure *closure, Expr *target)
+ void initClosure(IR::Closure *closure, Expr *target) override
{
Q_UNUSED(closure);
@@ -500,49 +501,52 @@ protected: // IRDecoder
addCall();
}
- virtual void getProperty(IR::Expr *base, const QString &, Expr *target)
+ void getProperty(IR::Expr *base, const QString &, Expr *target) override
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &)
+ void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &) override
{
addUses(source->asTemp(), Use::CouldHaveRegister);
addUses(targetBase->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind /*kind*/, int /*propertyIndex*/)
+ void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase,
+ IR::Member::MemberKind /*kind*/, int /*propertyIndex*/) override
{
addUses(source->asTemp(), Use::CouldHaveRegister);
addUses(targetBase->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int /*propertyIndex*/)
+ void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int /*propertyIndex*/) override
{
addUses(source->asTemp(), Use::CouldHaveRegister);
addUses(targetBase->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, QQmlPropertyData * /*property*/, int /*index*/, IR::Expr *target)
+ void getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int /*index*/,
+ bool /*captureRequired*/, IR::Expr *target) override
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData * /*property*/, bool /*captureRequired*/, bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target)
+ void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/,
+ bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target) override
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void getElement(IR::Expr *base, IR::Expr *index, Expr *target)
+ void getElement(IR::Expr *base, IR::Expr *index, Expr *target) override
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
@@ -550,7 +554,7 @@ protected: // IRDecoder
addCall();
}
- virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
+ void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) override
{
addUses(source->asTemp(), Use::CouldHaveRegister);
addUses(targetBase->asTemp(), Use::CouldHaveRegister);
@@ -558,7 +562,7 @@ protected: // IRDecoder
addCall();
}
- virtual void copyValue(Expr *source, Expr *target)
+ void copyValue(Expr *source, Expr *target) override
{
addDef(target);
Temp *sourceTemp = source->asTemp();
@@ -570,13 +574,13 @@ protected: // IRDecoder
addHint(targetTemp, sourceTemp);
}
- virtual void swapValues(Expr *, Expr *)
+ void swapValues(Expr *, Expr *) override
{
// Inserted by the register allocator, so it cannot occur here.
Q_UNREACHABLE();
}
- virtual void unop(AluOp oper, Expr *source, Expr *target)
+ void unop(AluOp oper, Expr *source, Expr *target) override
{
addDef(target);
@@ -612,7 +616,7 @@ protected: // IRDecoder
}
}
- virtual void binop(AluOp oper, Expr *leftSource, Expr *rightSource, Expr *target)
+ void binop(AluOp oper, Expr *leftSource, Expr *rightSource, Expr *target) override
{
bool needsCall = true;
@@ -675,8 +679,8 @@ protected: // IRDecoder
}
}
- virtual void visitJump(IR::Jump *) {}
- virtual void visitCJump(IR::CJump *s)
+ void visitJump(IR::Jump *) override {}
+ void visitCJump(IR::CJump *s) override
{
if (Temp *t = s->cond->asTemp()) {
#if 0 // TODO: change masm to generate code
@@ -696,10 +700,10 @@ protected: // IRDecoder
}
}
- virtual void visitRet(IR::Ret *s)
+ void visitRet(IR::Ret *s) override
{ addUses(s->expr->asTemp(), Use::CouldHaveRegister); }
- virtual void visitPhi(IR::Phi *s)
+ void visitPhi(IR::Phi *s) override
{
addDef(s->targetTemp, true);
for (int i = 0, ei = s->incoming.size(); i < ei; ++i) {
@@ -716,7 +720,7 @@ protected: // IRDecoder
}
protected:
- virtual void callBuiltin(IR::Call *c, IR::Expr *result)
+ void callBuiltin(IR::Call *c, IR::Expr *result) override
{
addDef(result);
addUses(c->base, Use::CouldHaveRegister);
@@ -809,14 +813,15 @@ using namespace QT_PREPEND_NAMESPACE(QV4::IR);
using namespace QT_PREPEND_NAMESPACE(QV4);
namespace {
-class ResolutionPhase: protected StmtVisitor, protected ExprVisitor {
+class ResolutionPhase
+{
Q_DISABLE_COPY(ResolutionPhase)
LifeTimeIntervals::Ptr _intervals;
- QVector<LifeTimeInterval *> _unprocessed;
+ QVector<LifeTimeInterval *> _unprocessedReverseOrder;
IR::Function *_function;
const std::vector<int> &_assignedSpillSlots;
- QHash<IR::Temp, const LifeTimeInterval *> _intervalForTemp;
+ std::vector<const LifeTimeInterval *> _liveIntervals;
const QVector<const RegisterInfo *> &_intRegs;
const QVector<const RegisterInfo *> &_fpRegs;
@@ -824,25 +829,26 @@ class ResolutionPhase: protected StmtVisitor, protected ExprVisitor {
std::vector<Move *> _loads;
std::vector<Move *> _stores;
- QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtStart;
- QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtEnd;
+ std::vector<std::vector<const LifeTimeInterval *> > _liveAtStart;
+ std::vector<std::vector<const LifeTimeInterval *> > _liveAtEnd;
public:
- ResolutionPhase(const QVector<LifeTimeInterval *> &unprocessed,
+ ResolutionPhase(QVector<LifeTimeInterval *> &&unprocessedReversedOrder,
const LifeTimeIntervals::Ptr &intervals,
IR::Function *function,
const std::vector<int> &assignedSpillSlots,
const QVector<const RegisterInfo *> &intRegs,
const QVector<const RegisterInfo *> &fpRegs)
: _intervals(intervals)
+ , _unprocessedReverseOrder(unprocessedReversedOrder)
, _function(function)
, _assignedSpillSlots(assignedSpillSlots)
, _intRegs(intRegs)
, _fpRegs(fpRegs)
+ , _currentStmt(0)
{
- _unprocessed = unprocessed;
- _liveAtStart.reserve(function->basicBlockCount());
- _liveAtEnd.reserve(function->basicBlockCount());
+ _liveAtStart.resize(function->basicBlockCount());
+ _liveAtEnd.resize(function->basicBlockCount());
}
void run() {
@@ -881,7 +887,7 @@ private:
cleanOldIntervals(_intervals->startPosition(bb));
addNewIntervals(_intervals->startPosition(bb));
- _liveAtStart[bb] = _intervalForTemp.values();
+ _liveAtStart[bb->index()] = _liveIntervals;
for (int i = 0, ei = statements.size(); i != ei; ++i) {
_currentStmt = statements.at(i);
@@ -891,7 +897,7 @@ private:
addNewIntervals(usePosition(_currentStmt));
else
addNewIntervals(defPosition(_currentStmt));
- _currentStmt->accept(this);
+ visit(_currentStmt);
for (Move *load : _loads)
newStatements.append(load);
if (_currentStmt->asPhi())
@@ -903,24 +909,24 @@ private:
}
cleanOldIntervals(_intervals->endPosition(bb));
- _liveAtEnd[bb] = _intervalForTemp.values();
+ _liveAtEnd[bb->index()] = _liveIntervals;
if (DebugRegAlloc) {
QBuffer buf;
buf.open(QIODevice::WriteOnly);
QTextStream os(&buf);
os << "Intervals live at the start of L" << bb->index() << ":" << endl;
- if (_liveAtStart[bb].isEmpty())
+ if (_liveAtStart[bb->index()].empty())
os << "\t(none)" << endl;
- for (const LifeTimeInterval *i : _liveAtStart.value(bb)) {
+ for (const LifeTimeInterval *i : _liveAtStart.at(bb->index())) {
os << "\t";
i->dump(os);
os << endl;
}
os << "Intervals live at the end of L" << bb->index() << ":" << endl;
- if (_liveAtEnd[bb].isEmpty())
+ if (_liveAtEnd[bb->index()].empty())
os << "\t(none)" << endl;
- for (const LifeTimeInterval *i : _liveAtEnd.value(bb)) {
+ for (const LifeTimeInterval *i : _liveAtEnd.at(bb->index())) {
os << "\t";
i->dump(os);
os << endl;
@@ -933,9 +939,19 @@ private:
}
+ const LifeTimeInterval *findLiveInterval(Temp *t) const
+ {
+ for (const LifeTimeInterval *lti : _liveIntervals) {
+ if (lti->temp() == *t)
+ return lti;
+ }
+
+ return nullptr;
+ }
+
void maybeGenerateSpill(Temp *t)
{
- const LifeTimeInterval *i = _intervalForTemp[*t];
+ const LifeTimeInterval *i = findLiveInterval(t);
if (i->reg() == LifeTimeInterval::InvalidRegister)
return;
@@ -951,26 +967,27 @@ private:
if (position == Stmt::InvalidId)
return;
- while (!_unprocessed.isEmpty()) {
- const LifeTimeInterval *i = _unprocessed.constFirst();
+ while (!_unprocessedReverseOrder.isEmpty()) {
+ const LifeTimeInterval *i = _unprocessedReverseOrder.constLast();
if (i->start() > position)
break;
Q_ASSERT(!i->isFixedInterval());
- _intervalForTemp[i->temp()] = i;
+ _liveIntervals.push_back(i);
// qDebug() << "-- Activating interval for temp" << i->temp().index;
- _unprocessed.removeFirst();
+ _unprocessedReverseOrder.removeLast();
}
}
void cleanOldIntervals(int position)
{
- QMutableHashIterator<Temp, const LifeTimeInterval *> it(_intervalForTemp);
- while (it.hasNext()) {
- const LifeTimeInterval *i = it.next().value();
- if (i->end() < position || i->isFixedInterval())
- it.remove();
+ for (size_t it = 0; it != _liveIntervals.size(); ) {
+ const LifeTimeInterval *lti = _liveIntervals.at(it);
+ if (lti->end() < position || lti->isFixedInterval())
+ _liveIntervals.erase(_liveIntervals.begin() + it);
+ else
+ ++it;
}
}
@@ -1017,7 +1034,7 @@ private:
int successorStart = _intervals->startPosition(successor);
Q_ASSERT(successorStart > 0);
- for (const LifeTimeInterval *it : _liveAtStart.value(successor)) {
+ for (const LifeTimeInterval *it : _liveAtStart.at(successor->index())) {
bool isPhiTarget = false;
Expr *moveFrom = 0;
@@ -1031,7 +1048,7 @@ private:
Temp *t = opd->asTemp();
Q_ASSERT(t);
- for (const LifeTimeInterval *it2 : _liveAtEnd.value(predecessor)) {
+ for (const LifeTimeInterval *it2 : _liveAtEnd.at(predecessor->index())) {
if (it2->temp() == *t
&& it2->reg() != LifeTimeInterval::InvalidRegister
&& it2->covers(predecessorEnd)) {
@@ -1046,7 +1063,7 @@ private:
}
}
} else {
- for (const LifeTimeInterval *predIt : _liveAtEnd.value(predecessor)) {
+ for (const LifeTimeInterval *predIt : _liveAtEnd.at(predecessor->index())) {
if (predIt->temp() == it->temp()) {
if (predIt->reg() != LifeTimeInterval::InvalidRegister
&& predIt->covers(predecessorEnd)) {
@@ -1178,13 +1195,25 @@ private:
return load;
}
-protected:
- virtual void visitTemp(Temp *t)
+private:
+ void visit(Expr *e)
+ {
+ switch (e->exprKind) {
+ case Expr::TempExpr:
+ visitTemp(e->asTemp());
+ break;
+ default:
+ EXPR_VISIT_ALL_KINDS(e);
+ break;
+ }
+ }
+
+ void visitTemp(Temp *t)
{
if (t->kind != Temp::VirtualRegister)
return;
- const LifeTimeInterval *i = _intervalForTemp[*t];
+ const LifeTimeInterval *i = findLiveInterval(t);
Q_ASSERT(i->isValid());
if (_currentStmt != 0 && i->start() == usePosition(_currentStmt)) {
@@ -1209,47 +1238,25 @@ protected:
}
}
- virtual void visitArgLocal(ArgLocal *) {}
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { e->base->accept(this); }
-
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
-
- virtual void visitMove(Move *s)
+ void visit(Stmt *s)
{
- if (Temp *t = s->target->asTemp())
- maybeGenerateSpill(t);
-
- s->source->accept(this);
- s->target->accept(this);
- }
+ switch (s->stmtKind) {
+ case Stmt::MoveStmt: {
+ auto m = s->asMove();
+ if (Temp *t = m->target->asTemp())
+ maybeGenerateSpill(t);
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(Phi *s)
- {
- maybeGenerateSpill(s->targetTemp);
+ visit(m->source);
+ visit(m->target);
+ } break;
+ case Stmt::PhiStmt: {
+ auto p = s->asPhi();
+ maybeGenerateSpill(p->targetTemp);
+ } break;
+ default:
+ STMT_VISIT_ALL_KINDS(s);
+ break;
+ }
}
};
} // anonymous namespace
@@ -1322,8 +1329,13 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
if (DebugRegAlloc)
dump(function);
- std::sort(_handled.begin(), _handled.end(), LifeTimeInterval::lessThan);
- ResolutionPhase(_handled, _lifeTimeIntervals, function, _assignedSpillSlots, _normalRegisters, _fpRegisters).run();
+ // sort the ranges in reverse order, so the ResolutionPhase can take from the end (and thereby
+ // prevent the copy overhead that taking from the beginning would give).
+ std::sort(_handled.begin(), _handled.end(),
+ [](const LifeTimeInterval *r1, const LifeTimeInterval *r2) -> bool {
+ return LifeTimeInterval::lessThan(r2, r1);
+ });
+ ResolutionPhase(std::move(_handled), _lifeTimeIntervals, function, _assignedSpillSlots, _normalRegisters, _fpRegisters).run();
function->tempCount = *std::max_element(_assignedSpillSlots.begin(), _assignedSpillSlots.end()) + 1;
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
index 54b17c4f07..7e265258d5 100644
--- a/src/qml/jit/qv4targetplatform_p.h
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -152,7 +152,7 @@ public:
#endif // Windows on x86
-#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X) || OS(FREEBSD) || defined(Q_OS_IOS))
+#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X) || OS(FREEBSD) || OS(QNX) || defined(Q_OS_IOS))
enum { RegAllocIsSupported = 1 };
static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
@@ -563,7 +563,7 @@ public:
#endif // Linux on MIPS (32 bit)
public: // utility functions
- static RegisterInformation getRegisterInfo()
+ static const RegisterInformation getRegisterInfo()
{
static const RegisterInformation info = getPlatformRegisterInfo();
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
index 6a32069ac4..799103849b 100644
--- a/src/qml/jit/qv4unop.cpp
+++ b/src/qml/jit/qv4unop.cpp
@@ -47,10 +47,14 @@ using namespace JIT;
#define stringIfyx(s) #s
#define stringIfy(s) stringIfyx(s)
#define setOp(operation) \
- do { call = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); } while (0)
+ do { \
+ call = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \
+ needsExceptionCheck = Runtime::Method_##operation##_NeedsExceptionCheck; \
+ } while (0)
void Unop::generate(IR::Expr *source, IR::Expr *target)
{
+ bool needsExceptionCheck;
RuntimeCall call;
const char *name = 0;
switch (op) {
@@ -71,7 +75,7 @@ void Unop::generate(IR::Expr *source, IR::Expr *target)
} // switch
Q_ASSERT(call.isValid());
- _as->generateFunctionCallImp(target, name, call, Assembler::PointerToValue(source));
+ _as->generateFunctionCallImp(needsExceptionCheck, target, name, call, Assembler::PointerToValue(source));
}
void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 09e8bbda55..4404a5d79f 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -166,6 +166,17 @@ Q_DECLARE_METATYPE(QList<int>)
properties of the proxy object. No binding code is needed because it
is done dynamically using the Qt meta object system.
+ Use newQMetaObject() to wrap a QMetaObject; this gives you a
+ "script representation" of a QObject-based class. newQMetaObject()
+ returns a proxy script object; enum values of the class are available
+ as properties of the proxy object.
+
+ Constructors exposed to the meta-object system ( using Q_INVOKABLE ) can be
+ called from the script to create a new QObject instance with
+ JavaScriptOwnership.
+
+
+
\snippet code/src_script_qjsengine.cpp 5
\section1 Extensions
@@ -511,6 +522,38 @@ QJSValue QJSEngine::newQObject(QObject *object)
}
/*!
+ \since 5.8
+
+ Creates a JavaScript object that wraps the given QMetaObject
+ The metaObject must outlive the script engine. It is recommended to only
+ use this method with static metaobjects.
+
+
+ When called as a constructor, a new instance of the class will be created.
+ Only constructors exposed by Q_INVOKABLE will be visible from the script engine.
+
+ \sa newQObject()
+*/
+
+QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) {
+ Q_D(QJSEngine);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(d);
+ QV4::Scope scope(v4);
+ QV4::ScopedValue v(scope, QV4::QMetaObjectWrapper::create(v4, metaObject));
+ return QJSValue(v4, v->asReturnedValue());
+}
+
+/*! \fn QJSValue QJSEngine::newQMetaObject<T>()
+
+ \since 5.8
+ Creates a JavaScript object that wraps the static QMetaObject associated
+ with class \c{T}.
+
+ \sa newQObject()
+*/
+
+
+/*!
Returns this engine's Global Object.
By default, the Global Object contains the built-in objects that are
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 6ecd0c7ec0..41c4b81270 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -74,6 +74,14 @@ public:
QJSValue newQObject(QObject *object);
+ QJSValue newQMetaObject(const QMetaObject* metaObject);
+
+ template <typename T>
+ QJSValue newQMetaObject()
+ {
+ return newQMetaObject(&T::staticMetaObject);
+ }
+
template <typename T>
inline QJSValue toScriptValue(const T &value)
{
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 4860908bd3..a4a96a96a7 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -178,7 +178,7 @@ QJSValue::QJSValue(SpecialValue value)
: d(0)
{
if (value == NullValue)
- QJSValuePrivate::setVariant(this, QVariant(QMetaType::VoidStar, (void *)0));
+ QJSValuePrivate::setVariant(this, QVariant::fromValue(nullptr));
}
/*!
@@ -293,7 +293,10 @@ bool QJSValue::isNull() const
if (val)
return val->isNull();
QVariant *variant = QJSValuePrivate::getVariant(this);
- return variant && variant->userType() == QMetaType::VoidStar;
+ if (!variant)
+ return false;
+ const int type = variant->userType();
+ return type == QMetaType::Nullptr || type == QMetaType::VoidStar;
}
/*!
@@ -582,7 +585,7 @@ quint32 QJSValue::toUInt() const
\table
\header \li Input Type \li Result
\row \li Undefined \li An invalid QVariant.
- \row \li Null \li A QVariant containing a null pointer (QMetaType::VoidStar).
+ \row \li Null \li A QVariant containing a null pointer (QMetaType::Nullptr).
\row \li Boolean \li A QVariant containing the value of the boolean.
\row \li Number \li A QVariant containing the value of the number.
\row \li String \li A QVariant containing the value of the string.
@@ -619,7 +622,7 @@ QVariant QJSValue::toVariant() const
return QVariant(val->asDouble());
}
if (val->isNull())
- return QVariant(QMetaType::VoidStar, 0);
+ return QVariant(QMetaType::Nullptr, 0);
Q_ASSERT(val->isUndefined());
return QVariant();
}
@@ -663,11 +666,11 @@ QJSValue QJSValue::call(const QJSValueList &args)
callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
}
- ScopedValue result(scope, f->call(callData));
+ f->call(scope, callData);
if (engine->hasException)
- result = engine->catchException();
+ scope.result = engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValue(engine, scope.result.asReturnedValue());
}
/*!
@@ -719,11 +722,11 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
}
- ScopedValue result(scope, f->call(callData));
+ f->call(scope, callData);
if (engine->hasException)
- result = engine->catchException();
+ scope.result = engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValue(engine, scope.result.asReturnedValue());
}
/*!
@@ -767,11 +770,11 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
}
- ScopedValue result(scope, f->construct(callData));
+ f->construct(scope, callData);
if (engine->hasException)
- result = engine->catchException();
+ scope.result = engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValue(engine, scope.result.asReturnedValue());
}
#ifdef QT_DEPRECATED
@@ -1234,6 +1237,28 @@ QObject *QJSValue::toQObject() const
}
/*!
+ \since 5.8
+
+ * If this QJSValue is a QMetaObject, returns the QMetaObject pointer
+ * that the QJSValue represents; otherwise, returns 0.
+ *
+ * \sa isQMetaObject()
+ */
+const QMetaObject *QJSValue::toQMetaObject() const
+{
+ QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
+ if (!engine)
+ return 0;
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::getValue(this));
+ if (!wrapper)
+ return 0;
+
+ return wrapper->metaObject();
+}
+
+
+/*!
Returns a QDateTime representation of this value, in local time.
If this QJSValue is not a date, or the value of the date is NaN
(Not-a-Number), an invalid QDateTime is returned.
@@ -1286,4 +1311,18 @@ bool QJSValue::isQObject() const
return val && val->as<QV4::QObjectWrapper>() != 0;
}
+/*!
+ \since 5.8
+
+ Returns true if this QJSValue is a QMetaObject; otherwise returns
+ false.
+
+ \sa toQMetaObject(), QJSEngine::newQMetaObject()
+*/
+bool QJSValue::isQMetaObject() const
+{
+ QV4::Value *val = QJSValuePrivate::getValue(this);
+ return val && val->as<QV4::QMetaObjectWrapper>() != 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index e207e1b099..ab20a2607d 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -98,6 +98,7 @@ public:
bool isUndefined() const;
bool isVariant() const;
bool isQObject() const;
+ bool isQMetaObject() const;
bool isObject() const;
bool isDate() const;
bool isRegExp() const;
@@ -111,6 +112,7 @@ public:
bool toBool() const;
QVariant toVariant() const;
QObject *toQObject() const;
+ const QMetaObject *toQMetaObject() const;
QDateTime toDateTime() const;
bool equals(const QJSValue &other) const;
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index 25afd9275c..c4761ad6ea 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -132,6 +132,7 @@ public:
case QMetaType::Void:
*v = QV4::Encode::undefined();
break;
+ case QMetaType::Nullptr:
case QMetaType::VoidStar:
*v = QV4::Encode::null();
break;
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 6ef92511e2..63cf8779d2 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -6,7 +6,6 @@ SOURCES += \
$$PWD/qv4engine.cpp \
$$PWD/qv4context.cpp \
$$PWD/qv4persistent.cpp \
- $$PWD/qv4debugging.cpp \
$$PWD/qv4lookup.cpp \
$$PWD/qv4identifier.cpp \
$$PWD/qv4identifiertable.cpp \
@@ -40,11 +39,12 @@ SOURCES += \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
$$PWD/qv4vme_moth.cpp \
- $$PWD/qv4profiling.cpp \
$$PWD/qv4arraybuffer.cpp \
$$PWD/qv4typedarray.cpp \
$$PWD/qv4dataview.cpp
+!contains(QT_CONFIG, no-qml-debug): SOURCES += $$PWD/qv4profiling.cpp
+
HEADERS += \
$$PWD/qv4global_p.h \
$$PWD/qv4engine_p.h \
@@ -83,7 +83,6 @@ HEADERS += \
$$PWD/qv4serialize_p.h \
$$PWD/qv4script_p.h \
$$PWD/qv4scopedvalue_p.h \
- $$PWD/qv4util_p.h \
$$PWD/qv4executableallocator_p.h \
$$PWD/qv4sequenceobject_p.h \
$$PWD/qv4include_p.h \
@@ -102,6 +101,7 @@ HEADERS += \
$$PWD/qv4runtimeapi_p.h \
$$PWD/qv4value_p.h \
$$PWD/qv4string_p.h \
+ $$PWD/qv4util_p.h \
$$PWD/qv4value_p.h
SOURCES += \
@@ -112,3 +112,7 @@ SOURCES += \
valgrind {
DEFINES += V4_USE_VALGRIND
}
+
+heaptrack {
+ DEFINES += V4_USE_HEAPTRACK
+}
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 94f418cae1..156c21ca66 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -46,9 +46,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ArgumentsObject);
Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context)
- : context(context->d())
- , fullyCreated(false)
+ : fullyCreated(false)
{
+ this->context = context->d();
Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
ExecutionEngine *v4 = context->d()->engine;
@@ -134,7 +134,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
ScopedCallData callData(scope, 1);
callData->thisObject = this->asReturnedValue();
callData->args[0] = desc->value;
- setter->call(callData);
+ setter->call(scope, callData);
if (attrs.isWritable()) {
setArrayAttributes(index, mapAttrs);
@@ -203,33 +203,35 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction);
-ReturnedValue ArgumentsGetterFunction::call(const Managed *getter, CallData *callData)
+void ArgumentsGetterFunction::call(const Managed *getter, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine();
- Scope scope(v4);
Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
- if (!o)
- return v4->throwTypeError();
+ if (!o) {
+ scope.result = v4->throwTypeError();
+ return;
+ }
Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->callData->argc));
- return o->context()->callData->args[g->index()].asReturnedValue();
+ scope.result = o->context()->callData->args[g->index()];
}
DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction);
-ReturnedValue ArgumentsSetterFunction::call(const Managed *setter, CallData *callData)
+void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine();
- Scope scope(v4);
Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
- if (!o)
- return v4->throwTypeError();
+ if (!o) {
+ scope.result = v4->throwTypeError();
+ return;
+ }
Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->callData->argc));
o->context()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined();
- return Encode::undefined();
+ scope.result = Encode::undefined();
}
void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index eeedcaf995..6ccfd89fd4 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -88,7 +88,7 @@ struct ArgumentsGetterFunction: FunctionObject
V4_OBJECT2(ArgumentsGetterFunction, FunctionObject)
uint index() const { return d()->index; }
- static ReturnedValue call(const Managed *that, CallData *d);
+ static void call(const Managed *that, Scope &scope, CallData *d);
};
inline
@@ -103,7 +103,7 @@ struct ArgumentsSetterFunction: FunctionObject
V4_OBJECT2(ArgumentsSetterFunction, FunctionObject)
uint index() const { return d()->index; }
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
inline
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index d170bde0e8..34c7746684 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -51,29 +51,34 @@ Heap::ArrayBufferCtor::ArrayBufferCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue ArrayBufferCtor::construct(const Managed *m, CallData *callData)
+void ArrayBufferCtor::construct(const Managed *m, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const Object *>(m)->engine();
- Scope scope(v4);
ScopedValue l(scope, callData->argument(0));
double dl = l->toInteger();
- if (v4->hasException)
- return Encode::undefined();
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
uint len = (uint)qBound(0., dl, (double)UINT_MAX);
- if (len != dl)
- return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length"));
+ if (len != dl) {
+ scope.result = v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length"));
+ return;
+ }
Scoped<ArrayBuffer> a(scope, v4->newArrayBuffer(len));
- if (scope.engine->hasException)
- return Encode::undefined();
- return a.asReturnedValue();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ } else {
+ scope.result = a->asReturnedValue();
+ }
}
-ReturnedValue ArrayBufferCtor::call(const Managed *that, CallData *callData)
+void ArrayBufferCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx)
@@ -149,6 +154,7 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(engine->id_constructor(), (o = ctor));
defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0);
defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
+ defineDefaultProperty(QStringLiteral("toString"), method_toString, 0);
}
ReturnedValue ArrayBufferPrototype::method_get_byteLength(CallContext *ctx)
@@ -184,7 +190,8 @@ ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx)
ScopedCallData callData(scope, 1);
double newLen = qMax(final - first, 0.);
callData->args[0] = QV4::Encode(newLen);
- QV4::Scoped<ArrayBuffer> newBuffer(scope, constructor->construct(callData));
+ constructor->construct(scope, callData);
+ QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result.asReturnedValue());
if (!newBuffer || newBuffer->d()->data->size < (int)newLen)
return scope.engine->throwTypeError();
@@ -192,3 +199,12 @@ ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx)
return newBuffer.asReturnedValue();
}
+
+ReturnedValue ArrayBufferPrototype::method_toString(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<ArrayBuffer> a(scope, ctx->thisObject());
+ if (!a)
+ return Encode::undefined();
+ return Encode(ctx->engine()->newString(QString::fromUtf8(a->asByteArray())));
+}
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index 0413d2f28d..b552cef9f1 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -78,8 +78,8 @@ struct ArrayBufferCtor: FunctionObject
{
V4_OBJECT2(ArrayBufferCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
static ReturnedValue method_isView(CallContext *ctx);
@@ -106,6 +106,7 @@ struct ArrayBufferPrototype: Object
static ReturnedValue method_get_byteLength(CallContext *ctx);
static ReturnedValue method_slice(CallContext *ctx);
+ static ReturnedValue method_toString(CallContext *ctx);
};
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 4c4639c94f..74c83b1940 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -99,8 +99,8 @@ Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SparseArrayData));
static Q_ALWAYS_INLINE void storeValue(ReturnedValue *target, uint value)
{
- Value v = Value::fromReturnedValue(*target);
- v.setValue(value);
+ Value v;
+ v.setTagValue(Value::fromReturnedValue(*target).tag(), value);
*target = v.asReturnedValue();
}
@@ -143,13 +143,13 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
Scoped<ArrayData> newData(scope);
if (newType < Heap::ArrayData::Sparse) {
Heap::SimpleArrayData *n = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
- new (n) Heap::SimpleArrayData;
+ n->init();
n->offset = 0;
n->len = d ? d->d()->len : 0;
newData = n;
} else {
Heap::SparseArrayData *n = scope.engine->memoryManager->allocManaged<SparseArrayData>(size);
- new (n) Heap::SparseArrayData;
+ n->init();
newData = n;
}
newData->setAlloc(alloc);
@@ -195,7 +195,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
n->value = i;
} else {
storeValue(lastFree, i);
- sparse->arrayData[i].setTag(Value::Empty_Type);
+ sparse->arrayData[i].setEmpty();
lastFree = &sparse->arrayData[i].rawValueRef();
}
}
@@ -204,7 +204,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
if (toCopy < sparse->alloc) {
for (uint i = toCopy; i < sparse->alloc; ++i) {
storeValue(lastFree, i);
- sparse->arrayData[i].setTag(Value::Empty_Type);
+ sparse->arrayData[i].setEmpty();
lastFree = &sparse->arrayData[i].rawValueRef();
}
storeValue(lastFree, UINT_MAX);
@@ -402,7 +402,7 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
// found two slots in a row
uint idx = Value::fromReturnedValue(*last).uint_32();
Value lastV = Value::fromReturnedValue(*last);
- lastV.setValue(dd->arrayData[lastV.value() + 1].value());
+ lastV.setTagValue(lastV.tag(), dd->arrayData[lastV.value() + 1].value());
*last = lastV.rawValue();
dd->attrs[idx] = Attr_Accessor;
return idx;
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 8ad4704227..d7ee4798b0 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -133,6 +133,7 @@ struct ArrayData : public Base {
}
};
+Q_STATIC_ASSERT(std::is_trivial<ArrayData>::value);
struct SimpleArrayData : public ArrayData {
uint mappedIndex(uint index) const { return (index + offset) % alloc; }
@@ -152,6 +153,7 @@ struct SimpleArrayData : public ArrayData {
return attrs ? attrs[i] : Attr_Data;
}
};
+Q_STATIC_ASSERT(std::is_trivial<SimpleArrayData>::value);
struct SparseArrayData : public ArrayData {
inline ~SparseArrayData();
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 3521673461..4d15c6c137 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -54,18 +54,19 @@ Heap::ArrayCtor::ArrayCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData)
+void ArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const ArrayCtor *>(m)->engine();
- Scope scope(v4);
ScopedArrayObject a(scope, v4->newArrayObject());
uint len;
if (callData->argc == 1 && callData->args[0].isNumber()) {
bool ok;
len = callData->args[0].asArrayLength(&ok);
- if (!ok)
- return v4->throwRangeError(callData->args[0]);
+ if (!ok) {
+ scope.result = v4->throwRangeError(callData->args[0]);
+ return;
+ }
if (len < 0x1000)
a->arrayReserve(len);
@@ -76,12 +77,12 @@ ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData)
}
a->setArrayLengthUnchecked(len);
- return a.asReturnedValue();
+ scope.result = a.asReturnedValue();
}
-ReturnedValue ArrayCtor::call(const Managed *that, CallData *callData)
+void ArrayCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -132,7 +133,8 @@ ReturnedValue ArrayPrototype::method_toString(CallContext *ctx)
if (!!f) {
ScopedCallData d(scope, 0);
d->thisObject = ctx->thisObject();
- return f->call(d);
+ f->call(scope, d);
+ return scope.result.asReturnedValue();
}
return ObjectPrototype::method_toString(ctx);
}
@@ -704,7 +706,6 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
ScopedCallData callData(scope, 3);
callData->args[2] = instance;
callData->thisObject = ctx->argument(1);
- ScopedValue r(scope);
ScopedValue v(scope);
bool ok = true;
@@ -716,8 +717,8 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- r = callback->call(callData);
- ok = r->toBoolean();
+ callback->call(scope, callData);
+ ok = scope.result.toBoolean();
}
return Encode(ok);
}
@@ -740,7 +741,6 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
callData->args[2] = instance;
ScopedValue v(scope);
- ScopedValue r(scope);
for (uint k = 0; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
@@ -749,8 +749,8 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- r = callback->call(callData);
- if (r->toBoolean())
+ callback->call(scope, callData);
+ if (scope.result.toBoolean())
return Encode(true);
}
return Encode(false);
@@ -782,7 +782,7 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- callback->call(callData);
+ callback->call(scope, callData);
}
return Encode::undefined();
}
@@ -804,7 +804,6 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);
- ScopedValue mapped(scope);
ScopedCallData callData(scope, 3);
callData->thisObject = ctx->argument(1);
callData->args[2] = instance;
@@ -818,8 +817,8 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- mapped = callback->call(callData);
- a->arraySet(k, mapped);
+ callback->call(scope, callData);
+ a->arraySet(k, scope.result);
}
return a.asReturnedValue();
}
@@ -840,7 +839,6 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject());
a->arrayReserve(len);
- ScopedValue selected(scope);
ScopedCallData callData(scope, 3);
callData->thisObject = ctx->argument(1);
callData->args[2] = instance;
@@ -856,8 +854,8 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
callData->args[0] = v;
callData->args[1] = Primitive::fromDouble(k);
- selected = callback->call(callData);
- if (selected->toBoolean()) {
+ callback->call(scope, callData);
+ if (scope.result.toBoolean()) {
a->arraySet(to, v);
++to;
}
@@ -879,17 +877,16 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
return ctx->engine()->throwTypeError();
uint k = 0;
- ScopedValue acc(scope);
ScopedValue v(scope);
if (ctx->argc() > 1) {
- acc = ctx->argument(1);
+ scope.result = ctx->argument(1);
} else {
bool kPresent = false;
while (k < len && !kPresent) {
v = instance->getIndexed(k, &kPresent);
if (kPresent)
- acc = v;
+ scope.result = v;
++k;
}
if (!kPresent)
@@ -898,21 +895,21 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
ScopedCallData callData(scope, 4);
callData->thisObject = Primitive::undefinedValue();
- callData->args[0] = acc;
+ callData->args[0] = scope.result;
callData->args[3] = instance;
while (k < len) {
bool kPresent;
v = instance->getIndexed(k, &kPresent);
if (kPresent) {
- callData->args[0] = acc;
+ callData->args[0] = scope.result;
callData->args[1] = v;
callData->args[2] = Primitive::fromDouble(k);
- acc = callback->call(callData);
+ callback->call(scope, callData);
}
++k;
}
- return acc->asReturnedValue();
+ return scope.result.asReturnedValue();
}
ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
@@ -935,16 +932,15 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
}
uint k = len;
- ScopedValue acc(scope);
ScopedValue v(scope);
if (ctx->argc() > 1) {
- acc = ctx->argument(1);
+ scope.result = ctx->argument(1);
} else {
bool kPresent = false;
while (k > 0 && !kPresent) {
v = instance->getIndexed(k - 1, &kPresent);
if (kPresent)
- acc = v;
+ scope.result = v;
--k;
}
if (!kPresent)
@@ -959,13 +955,13 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
bool kPresent;
v = instance->getIndexed(k - 1, &kPresent);
if (kPresent) {
- callData->args[0] = acc;
+ callData->args[0] = scope.result;
callData->args[1] = v;
callData->args[2] = Primitive::fromDouble(k - 1);
- acc = callback->call(callData);
+ callback->call(scope, callData);
}
--k;
}
- return acc->asReturnedValue();
+ return scope.result.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index bae5f9e0da..f49ed76b02 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -70,8 +70,8 @@ struct ArrayCtor: FunctionObject
{
V4_OBJECT2(ArrayCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct ArrayPrototype: ArrayObject
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index d9da7d7754..57c54e15c4 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -50,17 +50,16 @@ Heap::BooleanCtor::BooleanCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue BooleanCtor::construct(const Managed *m, CallData *callData)
+void BooleanCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const BooleanCtor *>(m)->engine());
bool n = callData->argc ? callData->args[0].toBoolean() : false;
- return Encode(scope.engine->newBooleanObject(n));
+ scope.result = Encode(scope.engine->newBooleanObject(n));
}
-ReturnedValue BooleanCtor::call(const Managed *, CallData *callData)
+void BooleanCtor::call(const Managed *, Scope &scope, CallData *callData)
{
bool value = callData->argc ? callData->args[0].toBoolean() : 0;
- return Encode(value);
+ scope.result = Encode(value);
}
void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor)
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index eedafa6126..17543e33e0 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -70,8 +70,8 @@ struct BooleanCtor: FunctionObject
{
V4_OBJECT2(BooleanCtor, FunctionObject)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct BooleanPrototype: BooleanObject
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 97b3e26a26..390a5e7d7a 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -61,8 +61,9 @@ Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *functi
{
Q_ASSERT(function->function());
- Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>(requiredMemoryForExecutionContect(function, callData->argc));
- new (c) Heap::CallContext(d()->engine, Heap::ExecutionContext::Type_CallContext);
+ Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>(
+ requiredMemoryForExecutionContect(function, callData->argc));
+ c->init(d()->engine, Heap::ExecutionContext::Type_CallContext);
c->function = function->d();
@@ -73,6 +74,7 @@ Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *functi
c->compilationUnit = function->function()->compilationUnit;
c->lookups = c->compilationUnit->runtimeLookups;
+ c->constantTable = c->compilationUnit->constants;
c->locals = (Value *)((quintptr(c + 1) + 7) & ~7);
const CompiledData::Function *compiledFunction = function->function()->compiledFunction;
@@ -159,44 +161,35 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
activation->__defineOwnProperty__(scope.engine, name, desc, attrs);
}
-
-Heap::GlobalContext::GlobalContext(ExecutionEngine *eng)
- : Heap::ExecutionContext(eng, Heap::ExecutionContext::Type_GlobalContext)
+void Heap::GlobalContext::init(ExecutionEngine *eng)
{
+ Heap::ExecutionContext::init(eng, Heap::ExecutionContext::Type_GlobalContext);
global = eng->globalObject->d();
}
-Heap::WithContext::WithContext(ExecutionContext *outerContext, Object *with)
- : Heap::ExecutionContext(outerContext->engine, Heap::ExecutionContext::Type_WithContext)
-{
- outer = outerContext;
- callData = outer->callData;
- lookups = outer->lookups;
- compilationUnit = outer->compilationUnit;
-
- withObject = with;
-}
-
-Heap::CatchContext::CatchContext(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue)
- : Heap::ExecutionContext(outerContext->engine, Heap::ExecutionContext::Type_CatchContext)
+void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName,
+ const Value &exceptionValue)
{
+ Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_CatchContext);
outer = outerContext;
strictMode = outer->strictMode;
callData = outer->callData;
lookups = outer->lookups;
+ constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
this->exceptionVarName = exceptionVarName;
this->exceptionValue = exceptionValue;
}
-Heap::QmlContext::QmlContext(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml)
- : Heap::ExecutionContext(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext)
+void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml)
{
+ Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext);
outer = outerContext->d();
strictMode = false;
callData = outer->callData;
lookups = outer->lookups;
+ constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
this->qml = qml->d();
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 2e6773a927..ffedf737ce 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -101,36 +101,41 @@ struct ExecutionContext : Base {
Type_CallContext = 0x6
};
- inline ExecutionContext(ExecutionEngine *engine, ContextType t);
+ void init(ExecutionEngine *engine, ContextType t)
+ {
+ Base::init();
+
+ callData = nullptr;
+ this->engine = engine;
+ outer = nullptr;
+ lookups = nullptr;
+ constantTable = nullptr;
+ compilationUnit = nullptr;
+ type = t;
+ strictMode = false;
+ lineNumber = -1;
+ }
CallData *callData;
ExecutionEngine *engine;
Pointer<ExecutionContext> outer;
Lookup *lookups;
+ const QV4::Value *constantTable;
CompiledData::CompilationUnit *compilationUnit;
ContextType type : 8;
bool strictMode : 8;
int lineNumber;
};
-
-inline
-ExecutionContext::ExecutionContext(ExecutionEngine *engine, ContextType t)
- : engine(engine)
- , outer(0)
- , lookups(0)
- , compilationUnit(0)
- , type(t)
- , strictMode(false)
- , lineNumber(-1)
-{}
-
+Q_STATIC_ASSERT(std::is_trivial<ExecutionContext>::value);
struct CallContext : ExecutionContext {
- CallContext(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
- : ExecutionContext(engine, t)
+ static CallContext createOnStack(ExecutionEngine *v4);
+
+ void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
{
+ ExecutionContext::init(engine, t);
function = 0;
locals = 0;
activation = 0;
@@ -140,27 +145,43 @@ struct CallContext : ExecutionContext {
Value *locals;
Pointer<Object> activation;
};
+Q_STATIC_ASSERT(std::is_trivial<CallContext>::value);
struct GlobalContext : ExecutionContext {
- GlobalContext(ExecutionEngine *engine);
+ void init(ExecutionEngine *engine);
Pointer<Object> global;
};
+Q_STATIC_ASSERT(std::is_trivial<GlobalContext>::value);
struct CatchContext : ExecutionContext {
- CatchContext(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue);
+ void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue);
Pointer<String> exceptionVarName;
Value exceptionValue;
};
+Q_STATIC_ASSERT(std::is_trivial<CatchContext>::value);
struct WithContext : ExecutionContext {
- WithContext(ExecutionContext *outerContext, Object *with);
+ void init(ExecutionContext *outerContext, Object *with)
+ {
+ Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext);
+ outer = outerContext;
+ callData = outer->callData;
+ lookups = outer->lookups;
+ constantTable = outer->constantTable;
+ compilationUnit = outer->compilationUnit;
+
+ withObject = with;
+ }
+
Pointer<Object> withObject;
};
+Q_STATIC_ASSERT(std::is_trivial<WithContext>::value);
struct QmlContextWrapper;
struct QmlContext : ExecutionContext {
- QmlContext(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml);
+ void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml);
+
Pointer<QmlContextWrapper> qml;
};
@@ -277,6 +298,16 @@ inline const WithContext *ExecutionContext::asWithContext() const
return d()->type == Heap::ExecutionContext::Type_WithContext ? static_cast<const WithContext *>(this) : 0;
}
+inline Heap::CallContext Heap::CallContext::createOnStack(ExecutionEngine *v4)
+{
+ Heap::CallContext ctxt;
+ memset(&ctxt, 0, sizeof(Heap::CallContext));
+ ctxt.mm_data = 0;
+ ctxt.setVtable(QV4::CallContext::staticVTable());
+ ctxt.init(v4);
+ return ctxt;
+}
+
/* Function *f, int argc */
#define requiredMemoryForExecutionContect(f, argc) \
((sizeof(CallContext::Data) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData)
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index f296ffd71e..fac3d5316c 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -54,32 +54,34 @@ Heap::DataViewCtor::DataViewCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue DataViewCtor::construct(const Managed *m, CallData *callData)
+void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const Object *>(m)->engine());
Scoped<ArrayBuffer> buffer(scope, callData->argument(0));
- if (!buffer)
- return scope.engine->throwTypeError();
+ if (!buffer) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
double bo = callData->argc > 1 ? callData->args[1].toNumber() : 0;
uint byteOffset = (uint)bo;
uint bufferLength = buffer->d()->data->size;
double bl = callData->argc < 3 || callData->args[2].isUndefined() ? (bufferLength - bo) : callData->args[2].toNumber();
uint byteLength = (uint)bl;
- if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength)
- return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
+ if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) {
+ scope.result = scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
+ return;
+ }
Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>());
a->d()->buffer = buffer->d();
a->d()->byteLength = byteLength;
a->d()->byteOffset = byteOffset;
- return a.asReturnedValue();
-
+ scope.result = a.asReturnedValue();
}
-ReturnedValue DataViewCtor::call(const Managed *that, CallData *callData)
+void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 2e8e94cecd..f996a4c2f1 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -76,8 +76,8 @@ struct DataViewCtor: FunctionObject
{
V4_OBJECT2(DataViewCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct DataView : Object
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 0cd72d6811..04358fe3b5 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -565,7 +565,7 @@ static inline QString ToString(double t)
{
if (std::isnan(t))
return QStringLiteral("Invalid Date");
- QString str = ToDateTime(t, Qt::LocalTime).toString() + QStringLiteral(" GMT");
+ QString str = ToDateTime(t, Qt::LocalTime).toString() + QLatin1String(" GMT");
double tzoffset = LocalTZA + DaylightSavingTA(t);
if (tzoffset) {
int hours = static_cast<int>(::fabs(tzoffset) / 1000 / 60 / 60);
@@ -639,6 +639,28 @@ Heap::DateObject::DateObject(const QDateTime &date)
this->date = date.isValid() ? date.toMSecsSinceEpoch() : qt_qnan();
}
+Heap::DateObject::DateObject(const QTime &time)
+{
+ if (!time.isValid()) {
+ date = qt_qnan();
+ return;
+ }
+
+ /* All programmers know that stuff starts at 0. Whatever that may mean in this context (and
+ * local timezone), it's before the epoch, so there is defenitely no DST problem. Specifically:
+ * you can't start with a date before the epoch, add some[*] hours, and end up with a date
+ * after. That's a problem for timezones where new year happens during DST, like
+ * Australia/Hobart, because we have to ignore DST before the epoch (but honor it after the
+ * epoch).
+ *
+ * [*] Well, when "some" is in the range 0-24. If you add something like 1M then this might
+ * still happen.
+ */
+ static const double d = MakeDay(0, 0, 0);
+ double t = MakeTime(time.hour(), time.minute(), time.second(), time.msec());
+ date = TimeClip(UTC(MakeDate(d, t)));
+}
+
QDateTime DateObject::toQDateTime() const
{
return ToDateTime(date(), Qt::LocalTime);
@@ -651,9 +673,8 @@ Heap::DateCtor::DateCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue DateCtor::construct(const Managed *m, CallData *callData)
+void DateCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const DateCtor *>(m)->engine());
double t = 0;
if (callData->argc == 0)
@@ -687,13 +708,13 @@ ReturnedValue DateCtor::construct(const Managed *m, CallData *callData)
t = TimeClip(UTC(t));
}
- return Encode(scope.engine->newDateObject(Primitive::fromDouble(t)));
+ scope.result = Encode(scope.engine->newDateObject(Primitive::fromDouble(t)));
}
-ReturnedValue DateCtor::call(const Managed *m, CallData *)
+void DateCtor::call(const Managed *m, Scope &scope, CallData *)
{
double t = currentTime();
- return static_cast<const DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue();
+ scope.result = static_cast<const DateCtor *>(m)->engine()->newString(ToString(t));
}
void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -1311,7 +1332,8 @@ ReturnedValue DatePrototype::method_toJSON(CallContext *ctx)
ScopedCallData callData(scope);
callData->thisObject = ctx->thisObject();
- return toIso->call(callData);
+ toIso->call(scope, callData);
+ return scope.result.asReturnedValue();
}
void DatePrototype::timezoneUpdated()
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index e3615d76a7..c67acdcfa2 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -74,6 +74,8 @@ struct DateObject : Object {
}
DateObject(const QDateTime &date);
double date;
+
+ DateObject(const QTime &time);
};
@@ -104,8 +106,8 @@ struct DateCtor: FunctionObject
{
V4_OBJECT2(DateCtor, FunctionObject)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *);
};
struct DatePrototype: DateObject
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 9dca7e9979..3b589a41f1 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -59,6 +59,19 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Debugging {
+#ifdef QT_NO_QML_DEBUGGER
+
+struct Debugger
+{
+ bool pauseAtNextOpportunity() const { return false; }
+ void maybeBreakAtInstruction() {}
+ void enteringFunction() {}
+ void leavingFunction(const ReturnedValue &) {}
+ void aboutToThrow() {}
+};
+
+#else
+
class Q_QML_EXPORT Debugger : public QObject
{
Q_OBJECT
@@ -72,6 +85,8 @@ public:
virtual void aboutToThrow() = 0;
};
+#endif // QT_NO_QML_DEBUGGING
+
} // namespace Debugging
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index d603a1982a..fea6bbbd70 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -136,8 +136,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, currentContext(0)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
- , debugger(0)
- , profiler(0)
, globalCode(0)
, v8Engine(0)
, argumentsAccessors(0)
@@ -145,6 +143,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(0)
, m_multiplyWrappedQObjects(0)
+#ifndef QT_NO_QML_DEBUGGER
+ , m_debugger(0)
+ , m_profiler(0)
+#endif
{
if (maxCallDepth == -1) {
bool ok = false;
@@ -188,6 +190,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
/* writable */ true, /* executable */ false,
/* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
+#ifdef V4_USE_VALGRIND
+ VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit);
+#endif
+
jsStackTop = jsStackBase;
exceptionValue = jsAlloca(1);
@@ -197,10 +203,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes));
jsStrings = jsAlloca(NJSStrings);
-#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit);
-#endif
-
// set up stack limits
jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value);
@@ -442,10 +444,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
ExecutionEngine::~ExecutionEngine()
{
- delete debugger;
- debugger = 0;
- delete profiler;
- profiler = 0;
+#ifndef QT_NO_QML_DEBUGGER
+ delete m_debugger;
+ m_debugger = 0;
+ delete m_profiler;
+ m_profiler = 0;
+#endif
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = 0;
delete identifierTable;
@@ -453,7 +457,7 @@ ExecutionEngine::~ExecutionEngine()
QSet<QV4::CompiledData::CompilationUnit*> remainingUnits;
qSwap(compilationUnits, remainingUnits);
- foreach (QV4::CompiledData::CompilationUnit *unit, remainingUnits)
+ for (QV4::CompiledData::CompilationUnit *unit : qAsConst(remainingUnits))
unit->unlink();
emptyClass->destroy();
@@ -467,23 +471,26 @@ ExecutionEngine::~ExecutionEngine()
delete [] argumentsAccessors;
}
-void ExecutionEngine::setDebugger(Debugging::Debugger *debugger_)
+#ifndef QT_NO_QML_DEBUGGER
+void ExecutionEngine::setDebugger(Debugging::Debugger *debugger)
{
- Q_ASSERT(!debugger);
- debugger = debugger_;
+ Q_ASSERT(!m_debugger);
+ m_debugger = debugger;
}
-void ExecutionEngine::enableProfiler()
+void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
{
- Q_ASSERT(!profiler);
- profiler = new QV4::Profiling::Profiler(this);
+ Q_ASSERT(!m_profiler);
+ m_profiler = profiler;
}
+#endif // QT_NO_QML_DEBUGGER
void ExecutionEngine::initRootContext()
{
Scope scope(this);
- Scoped<GlobalContext> r(scope, memoryManager->allocManaged<GlobalContext>(sizeof(GlobalContext::Data) + sizeof(CallData)));
- new (r->d()) GlobalContext::Data(this);
+ Scoped<GlobalContext> r(scope, memoryManager->allocManaged<GlobalContext>(
+ sizeof(GlobalContext::Data) + sizeof(CallData)));
+ r->d_unchecked()->init(this);
r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1);
r->d()->callData->tag = QV4::Value::Integer_Type_Internal;
r->d()->callData->argc = 0;
@@ -566,7 +573,7 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng
if (length) {
size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
- new (d) Heap::SimpleArrayData;
+ d->init();
d->alloc = length;
d->type = Heap::ArrayData::Simple;
d->offset = 0;
@@ -615,6 +622,13 @@ Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dt)
return object->d();
}
+Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t)
+{
+ Scope scope(this);
+ Scoped<DateObject> object(scope, memoryManager->allocObject<DateObject>(t));
+ return object->d();
+}
+
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
{
bool global = (flags & IR::RegExp::RegExp_Global);
@@ -910,8 +924,8 @@ ReturnedValue ExecutionEngine::throwError(const Value &value)
else
exceptionStackTrace = stackTrace();
- if (debugger)
- debugger->aboutToThrow();
+ if (QV4::Debugging::Debugger *debug = debugger())
+ debug->aboutToThrow();
return Encode::undefined();
}
@@ -969,7 +983,7 @@ ReturnedValue ExecutionEngine::throwReferenceError(const Value &value)
{
Scope scope(this);
ScopedString s(scope, value.toString(this));
- QString msg = s->toQString() + QStringLiteral(" is not defined");
+ QString msg = s->toQString() + QLatin1String(" is not defined");
ScopedObject error(scope, newReferenceErrorObject(msg));
return throwError(error);
}
@@ -993,7 +1007,7 @@ ReturnedValue ExecutionEngine::throwRangeError(const Value &value)
{
Scope scope(this);
ScopedString s(scope, value.toString(this));
- QString msg = s->toQString() + QStringLiteral(" out of range");
+ QString msg = s->toQString() + QLatin1String(" out of range");
ScopedObject error(scope, newRangeErrorObject(msg));
return throwError(error);
}
@@ -1008,7 +1022,7 @@ ReturnedValue ExecutionEngine::throwURIError(const Value &msg)
ReturnedValue ExecutionEngine::throwUnimplemented(const QString &message)
{
Scope scope(this);
- ScopedValue v(scope, newString(QStringLiteral("Unimplemented ") + message));
+ ScopedValue v(scope, newString(QLatin1String("Unimplemented ") + message));
v = newErrorObject(v);
return throwError(v);
}
@@ -1124,15 +1138,20 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
if (value.isUndefined())
return QVariant();
if (value.isNull())
- return QVariant(QMetaType::VoidStar, (void *)0);
+ return QVariant::fromValue(nullptr);
if (value.isBoolean())
return value.booleanValue();
if (value.isInteger())
return value.integerValue();
if (value.isNumber())
return value.asDouble();
- if (value.isString())
- return value.stringValue()->toQString();
+ if (value.isString()) {
+ const QString &str = value.toQString();
+ // QChars are stored as a strings
+ if (typeHint == QVariant::Char && str.size() == 1)
+ return str.at(0);
+ return str;
+ }
if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
return ld->d()->locale;
if (const QV4::DateObject *d = value.as<DateObject>())
@@ -1249,6 +1268,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
case QMetaType::UnknownType:
case QMetaType::Void:
return QV4::Encode::undefined();
+ case QMetaType::Nullptr:
case QMetaType::VoidStar:
return QV4::Encode::null();
case QMetaType::Bool:
@@ -1274,9 +1294,9 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
case QMetaType::UShort:
return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(ptr));
case QMetaType::Char:
- return newString(QChar::fromLatin1(*reinterpret_cast<const char *>(ptr)))->asReturnedValue();
+ return QV4::Encode((int)*reinterpret_cast<const char*>(ptr));
case QMetaType::UChar:
- return newString(QChar::fromLatin1(*reinterpret_cast<const unsigned char *>(ptr)))->asReturnedValue();
+ return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(ptr));
case QMetaType::QChar:
return newString(*reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
case QMetaType::QDateTime:
@@ -1284,7 +1304,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
case QMetaType::QDate:
return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(ptr))));
case QMetaType::QTime:
- return QV4::Encode(newDateObject(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr))));
+ return QV4::Encode(newDateObjectFromTime(*reinterpret_cast<const QTime *>(ptr)));
case QMetaType::QRegExp:
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
case QMetaType::QObjectStar:
@@ -1420,6 +1440,7 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
case QMetaType::UnknownType:
case QMetaType::Void:
return QV4::Encode::undefined();
+ case QMetaType::Nullptr:
case QMetaType::VoidStar:
return QV4::Encode::null();
case QMetaType::Bool:
@@ -1506,6 +1527,11 @@ void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject)
Q_UNUSED(baseObject);
}
+void ExecutionEngine::failStackLimitCheck(Scope &scope)
+{
+ scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
+}
+
// Converts a JS value to a meta-type.
// data must point to a place that can store a value of the given type.
// Returns true if conversion succeeded, false otherwise.
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 933241ea27..843a6f4d94 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -54,7 +54,6 @@
#include "private/qv4isel_p.h"
#include "qv4managed_p.h"
#include "qv4context_p.h"
-#include "qv4internalclass_p.h"
#include "qv4runtimeapi_p.h"
#include <private/qintrusivelist_p.h>
@@ -86,6 +85,9 @@ namespace CompiledData {
struct CompilationUnit;
}
+struct InternalClass;
+struct InternalClassPool;
+
struct Q_QML_EXPORT ExecutionEngine
{
private:
@@ -135,9 +137,6 @@ public:
IdentifierTable *identifierTable;
- QV4::Debugging::Debugger *debugger;
- QV4::Profiling::Profiler *profiler;
-
Object *globalObject;
Function *globalCode;
@@ -380,8 +379,19 @@ public:
ExecutionEngine(EvalISelFactory *iselFactory = 0);
~ExecutionEngine();
+#ifdef QT_NO_QML_DEBUGGER
+ QV4::Debugging::Debugger *debugger() const { return nullptr; }
+ QV4::Profiling::Profiler *profiler() const { return nullptr; }
+
+ void setDebugger(Debugging::Debugger *) {}
+ void setProfiler(Profiling::Profiler *) {}
+#else
+ QV4::Debugging::Debugger *debugger() const { return m_debugger; }
+ QV4::Profiling::Profiler *profiler() const { return m_profiler; }
+
void setDebugger(Debugging::Debugger *debugger);
- void enableProfiler();
+ void setProfiler(Profiling::Profiler *profiler);
+#endif // QT_NO_QML_DEBUGGER
ExecutionContext *pushGlobalContext();
void pushContext(Heap::ExecutionContext *context);
@@ -409,6 +419,7 @@ public:
Heap::DateObject *newDateObject(const Value &value);
Heap::DateObject *newDateObject(const QDateTime &dt);
+ Heap::DateObject *newDateObjectFromTime(const QTime &t);
Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags);
Heap::RegExpObject *newRegExpObject(RegExp *re, bool global);
@@ -478,7 +489,15 @@ public:
void assertObjectBelongsToEngine(const Heap::Base &baseObject);
- bool checkStackLimits(ReturnedValue &exception);
+ bool checkStackLimits(Scope &scope);
+
+private:
+ void failStackLimitCheck(Scope &scope);
+
+#ifndef QT_NO_QML_DEBUGGER
+ QV4::Debugging::Debugger *m_debugger;
+ QV4::Profiling::Profiler *m_profiler;
+#endif
};
// This is a trick to tell the code generators that functions taking a NoThrowContext won't
@@ -571,7 +590,7 @@ inline void Value::mark(ExecutionEngine *e)
o->mark(e);
}
-#define CHECK_STACK_LIMITS(v4) { ReturnedValue e; if ((v4)->checkStackLimits(e)) return e; } \
+#define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
struct ExecutionEngineCallDepthRecorder
@@ -582,10 +601,10 @@ struct ExecutionEngineCallDepthRecorder
~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
};
-inline bool ExecutionEngine::checkStackLimits(ReturnedValue &exception)
+inline bool ExecutionEngine::checkStackLimits(Scope &scope)
{
if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) {
- exception = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
+ failStackLimitCheck(scope);
return true;
}
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 2db04bbfda..3763bf2613 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -239,16 +239,15 @@ Heap::ErrorCtor::ErrorCtor(QV4::ExecutionContext *scope, const QString &name)
{
}
-ReturnedValue ErrorCtor::construct(const Managed *m, CallData *callData)
+void ErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const ErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<ErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<ErrorObject>(scope.engine, v);
}
-ReturnedValue ErrorCtor::call(const Managed *that, CallData *callData)
+void ErrorCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return static_cast<const Object *>(that)->construct(callData);
+ static_cast<const Object *>(that)->construct(scope, callData);
}
Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope)
@@ -256,11 +255,10 @@ Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue EvalErrorCtor::construct(const Managed *m, CallData *callData)
+void EvalErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const EvalErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<EvalErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<EvalErrorObject>(scope.engine, v);
}
Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope)
@@ -268,11 +266,10 @@ Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue RangeErrorCtor::construct(const Managed *m, CallData *callData)
+void RangeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const RangeErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<RangeErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<RangeErrorObject>(scope.engine, v);
}
Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope)
@@ -280,11 +277,10 @@ Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue ReferenceErrorCtor::construct(const Managed *m, CallData *callData)
+void ReferenceErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const ReferenceErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<ReferenceErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<ReferenceErrorObject>(scope.engine, v);
}
Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope)
@@ -292,11 +288,10 @@ Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue SyntaxErrorCtor::construct(const Managed *m, CallData *callData)
+void SyntaxErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const SyntaxErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<SyntaxErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<SyntaxErrorObject>(scope.engine, v);
}
Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope)
@@ -304,11 +299,10 @@ Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue TypeErrorCtor::construct(const Managed *m, CallData *callData)
+void TypeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const TypeErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<TypeErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<TypeErrorObject>(scope.engine, v);
}
Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope)
@@ -316,11 +310,10 @@ Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue URIErrorCtor::construct(const Managed *m, CallData *callData)
+void URIErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const URIErrorCtor *>(m)->engine());
ScopedValue v(scope, callData->argument(0));
- return ErrorObject::create<URIErrorObject>(scope.engine, v)->asReturnedValue();
+ scope.result = ErrorObject::create<URIErrorObject>(scope.engine, v);
}
void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t)
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 1ca2fedd7b..42a3d05d9f 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -221,50 +221,50 @@ struct ErrorCtor: FunctionObject
{
V4_OBJECT2(ErrorCtor, FunctionObject)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct EvalErrorCtor: ErrorCtor
{
V4_OBJECT2(EvalErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
struct RangeErrorCtor: ErrorCtor
{
V4_OBJECT2(RangeErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
};
struct ReferenceErrorCtor: ErrorCtor
{
V4_OBJECT2(ReferenceErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
struct SyntaxErrorCtor: ErrorCtor
{
V4_OBJECT2(SyntaxErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
struct TypeErrorCtor: ErrorCtor
{
V4_OBJECT2(TypeErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
struct URIErrorCtor: ErrorCtor
{
V4_OBJECT2(URIErrorCtor, ErrorCtor)
- static ReturnedValue construct(const Managed *m, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index 6fe25f192d..64ac1267ce 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -147,7 +147,7 @@ ExecutableAllocator::ExecutableAllocator()
ExecutableAllocator::~ExecutableAllocator()
{
- foreach (ChunkOfPages *chunk, chunks) {
+ for (ChunkOfPages *chunk : qAsConst(chunks)) {
for (Allocation *allocation = chunk->firstAllocation; allocation; allocation = allocation->next)
if (!allocation->free)
allocation->invalidate();
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index f314e20863..300e538d3d 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -59,7 +59,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
Q_UNUSED(engine);
internalClass = engine->emptyClass;
- const quint32 *formalsIndices = compiledFunction->formalsTable();
+ const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable();
// iterate backwards, so we get the right ordering for duplicate names
Scope scope(engine);
ScopedString arg(scope);
@@ -73,12 +73,12 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
}
// duplicate arguments, need some trick to store them
MemoryManager *mm = engine->memoryManager;
- arg = mm->alloc<String>(mm, arg->d(), engine->newString(QString(0xfffe)));
+ arg = mm->alloc<String>(mm, arg->d(), engine->newString(QString(0xfffe)), true);
}
}
nFormals = compiledFunction->nFormals;
- const quint32 *localsIndices = compiledFunction->localsTable();
+ const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
@@ -105,12 +105,12 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
break;
}
// duplicate arguments, need some trick to store them
- arg = engine->memoryManager->alloc<String>(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe)));
+ arg = engine->memoryManager->alloc<String>(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe)), true);
}
}
nFormals = parameters.size();
- const quint32 *localsIndices = compiledFunction->localsTable();
+ const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 5d2c57a2ba..e160dd8a36 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -69,18 +69,18 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String *name, bool createProto)
- : scope(scope->d())
- , function(Q_NULLPTR)
+ : function(Q_NULLPTR)
{
+ this->scope = scope->d();
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
f->init(name, createProto);
}
Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *function, bool createProto)
- : scope(scope->d())
- , function(Q_NULLPTR)
+ : function(Q_NULLPTR)
{
+ this->scope = scope->d();
Scope s(scope->engine());
ScopedString name(s, function->name());
ScopedFunctionObject f(s, this);
@@ -88,9 +88,9 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *fun
}
Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString &name, bool createProto)
- : scope(scope->d())
- , function(Q_NULLPTR)
+ : function(Q_NULLPTR)
{
+ this->scope = scope->d();
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
ScopedString n(s, s.engine->newString(name));
@@ -98,9 +98,9 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString
}
Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto)
- : scope(scope)
- , function(Q_NULLPTR)
+ : function(Q_NULLPTR)
{
+ this->scope = scope;
Scope s(scope->engine);
ScopedFunctionObject f(s, this);
ScopedString n(s, s.engine->newString(name));
@@ -108,9 +108,9 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &nam
}
Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name)
- : scope(scope->d())
- , function(Q_NULLPTR)
+ : function(Q_NULLPTR)
{
+ this->scope = scope->d();
Scope s(scope);
ScopedFunctionObject f(s, this);
ScopedString n(s, name);
@@ -118,9 +118,9 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const Returne
}
Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name)
- : scope(scope)
- , function(Q_NULLPTR)
+ : function(Q_NULLPTR)
{
+ this->scope = scope;
Scope s(scope->engine);
ScopedFunctionObject f(s, this);
ScopedString n(s, name);
@@ -128,9 +128,9 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValu
}
Heap::FunctionObject::FunctionObject()
- : scope(internalClass->engine->rootContext()->d())
- , function(Q_NULLPTR)
+ : function(Q_NULLPTR)
{
+ this->scope = internalClass->engine->rootContext()->d();
Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype);
*propertyData(Index_Prototype) = Encode::undefined();
}
@@ -166,22 +166,14 @@ ReturnedValue FunctionObject::name() const
return get(scope()->engine->id_name());
}
-
-ReturnedValue FunctionObject::newInstance()
+void FunctionObject::construct(const Managed *that, Scope &scope, CallData *)
{
- Scope scope(internalClass()->engine);
- ScopedCallData callData(scope);
- return construct(callData);
+ scope.result = static_cast<const FunctionObject *>(that)->engine()->throwTypeError();
}
-ReturnedValue FunctionObject::construct(const Managed *that, CallData *)
+void FunctionObject::call(const Managed *, Scope &scope, CallData *)
{
- return static_cast<const FunctionObject *>(that)->engine()->throwTypeError();
-}
-
-ReturnedValue FunctionObject::call(const Managed *, CallData *)
-{
- return Encode::undefined();
+ scope.result = Encode::undefined();
}
void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e)
@@ -251,9 +243,8 @@ Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope)
}
// 15.3.2
-ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
+void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const Object *>(that)->engine());
Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that));
QString arguments;
@@ -266,8 +257,10 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
}
body = callData->args[callData->argc - 1].toQString();
}
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1Char('}');
@@ -278,15 +271,19 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
const bool parsed = parser.parseExpression();
- if (!parsed)
- return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ if (!parsed) {
+ scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ return;
+ }
using namespace QQmlJS::AST;
FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
- if (!fe)
- return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ if (!fe) {
+ scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ return;
+ }
- IR::Module module(scope.engine->debugger != 0);
+ IR::Module module(scope.engine->debugger() != 0);
QQmlJS::RuntimeCodegen cg(scope.engine, f->strictMode());
cg.generateFromFunctionExpression(QString(), function, fe, &module);
@@ -297,13 +294,13 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
Function *vmf = compilationUnit->linkToEngine(scope.engine);
ExecutionContext *global = scope.engine->rootContext();
- return FunctionObject::createScriptFunction(global, vmf)->asReturnedValue();
+ scope.result = FunctionObject::createScriptFunction(global, vmf);
}
// 15.3.1: This is equivalent to new Function(...)
-ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData)
+void FunctionCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
DEFINE_OBJECT_VTABLE(FunctionPrototype);
@@ -376,7 +373,8 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
}
callData->thisObject = ctx->argument(0);
- return o->call(callData);
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
@@ -393,7 +391,9 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
callData->args[i - 1] = ctx->args()[i];
}
callData->thisObject = ctx->argument(0);
- return o->call(callData);
+
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
@@ -422,19 +422,20 @@ Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *fun
{
}
-ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData)
+void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
- InternalClass *ic = scope.engine->emptyClass;
+ InternalClass *ic = v4->emptyClass;
ScopedObject proto(scope, f->protoForConstructor());
ScopedObject obj(scope, v4->newObject(ic, proto));
@@ -442,39 +443,37 @@ ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData)
Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData));
v4->pushContext(ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
+ scope.result = Q_V4_PROFILE(v4, f->function());
if (f->function()->compiledFunction->hasQmlDependencies())
- QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction);
-
- if (v4->hasException)
- return Encode::undefined();
+ QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
- if (result->isObject())
- return result->asReturnedValue();
- return obj.asReturnedValue();
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ } else if (!scope.result.isObject()) {
+ scope.result = obj.asReturnedValue();
+ }
}
-ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData)
+void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData));
v4->pushContext(ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
+ scope.result = Q_V4_PROFILE(v4, f->function());
if (f->function()->compiledFunction->hasQmlDependencies())
- QQmlPropertyCapture::registerQmlDependencies(scope.engine, f->function()->compiledFunction);
-
- return result->asReturnedValue();
+ QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
}
DEFINE_OBJECT_VTABLE(SimpleScriptFunction);
@@ -511,14 +510,15 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F
}
}
-ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *callData)
+void SimpleScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that));
@@ -527,14 +527,13 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal
ScopedObject proto(scope, f->protoForConstructor());
callData->thisObject = v4->newObject(ic, proto);
- CallContext::Data ctx(v4);
- ctx.mm_data = 0;
- ctx.setVtable(CallContext::staticVTable());
+ CallContext::Data ctx = CallContext::Data::createOnStack(v4);
ctx.strictMode = f->strictMode();
ctx.callData = callData;
ctx.function = f->d();
ctx.compilationUnit = f->function()->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
+ ctx.constantTable = ctx.compilationUnit->constants;
ctx.outer = f->scope();
ctx.locals = scope.alloc(f->varCount());
for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i)
@@ -542,36 +541,38 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal
v4->pushContext(&ctx);
Q_ASSERT(v4->current == &ctx);
- ScopedObject result(scope, Q_V4_PROFILE(v4, f->function()));
+ scope.result = Q_V4_PROFILE(v4, f->function());
if (f->function()->compiledFunction->hasQmlDependencies())
- QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction);
+ QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
- if (!result)
- return callData->thisObject.asReturnedValue();
- return result.asReturnedValue();
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ } else if (!scope.result.isObject()) {
+ scope.result = callData->thisObject;
+ }
}
-ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData)
+void SimpleScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const SimpleScriptFunction *>(that)->internalClass()->engine;
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that));
- CallContext::Data ctx(v4);
- ctx.mm_data = 0;
- ctx.setVtable(CallContext::staticVTable());
+ CallContext::Data ctx = CallContext::Data::createOnStack(v4);
ctx.strictMode = f->strictMode();
ctx.callData = callData;
ctx.function = f->d();
ctx.compilationUnit = f->function()->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
+ ctx.constantTable = ctx.compilationUnit->constants;
ctx.outer = f->scope();
ctx.locals = scope.alloc(f->varCount());
for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i)
@@ -579,12 +580,10 @@ ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData
v4->pushContext(&ctx);
Q_ASSERT(v4->current == &ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
+ scope.result = Q_V4_PROFILE(v4, f->function());
if (f->function()->compiledFunction->hasQmlDependencies())
- QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction);
-
- return result->asReturnedValue();
+ QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
}
Heap::Object *SimpleScriptFunction::protoForConstructor()
@@ -606,53 +605,51 @@ Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String
{
}
-ReturnedValue BuiltinFunction::construct(const Managed *f, CallData *)
+void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
{
- return static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
+ scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
}
-ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData)
+void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that);
- ExecutionEngine *v4 = f->internalClass()->engine;
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data ctx(v4);
- ctx.mm_data = 0;
- ctx.setVtable(CallContext::staticVTable());
+ CallContext::Data ctx = CallContext::Data::createOnStack(v4);
ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
v4->pushContext(&ctx);
Q_ASSERT(v4->current == &ctx);
- return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext));
+ scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext));
}
-ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData)
+void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that);
- ExecutionEngine *v4 = f->internalClass()->engine;
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data ctx(v4);
- ctx.mm_data = 0;
- ctx.setVtable(CallContext::staticVTable());
+ CallContext::Data ctx = CallContext::Data::createOnStack(v4);
ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
v4->pushContext(&ctx);
Q_ASSERT(v4->current == &ctx);
- return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index);
+ scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index);
}
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
@@ -662,9 +659,9 @@ DEFINE_OBJECT_VTABLE(BoundFunction);
Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
const Value &boundThis, QV4::MemberData *boundArgs)
: Heap::FunctionObject(scope, QStringLiteral("__bound function__"))
- , target(target->d())
- , boundArgs(boundArgs ? boundArgs->d() : 0)
{
+ this->target = target->d();
+ this->boundArgs = boundArgs ? boundArgs->d() : 0;
this->boundThis = boundThis;
Scope s(scope);
@@ -685,12 +682,13 @@ Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionOb
f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
-ReturnedValue BoundFunction::call(const Managed *that, CallData *dd)
+void BoundFunction::call(const Managed *that, Scope &scope, CallData *dd)
{
const BoundFunction *f = static_cast<const BoundFunction *>(that);
- Scope scope(f->engine());
- if (scope.hasException())
- return Encode::undefined();
+ if (scope.hasException()) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<MemberData> boundArgs(scope, f->boundArgs());
ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc);
@@ -702,15 +700,16 @@ ReturnedValue BoundFunction::call(const Managed *that, CallData *dd)
}
memcpy(argp, dd->args, dd->argc*sizeof(Value));
ScopedFunctionObject t(scope, f->target());
- return t->call(callData);
+ t->call(scope, callData);
}
-ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd)
+void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd)
{
const BoundFunction *f = static_cast<const BoundFunction *>(that);
- Scope scope(f->engine());
- if (scope.hasException())
- return Encode::undefined();
+ if (scope.hasException()) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<MemberData> boundArgs(scope, f->boundArgs());
ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc);
@@ -721,7 +720,7 @@ ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd)
}
memcpy(argp, dd->args, dd->argc*sizeof(Value));
ScopedFunctionObject t(scope, f->target());
- return t->construct(callData);
+ t->construct(scope, callData);
}
void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 4a4545eca4..182b762606 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -145,12 +145,10 @@ struct Q_QML_EXPORT FunctionObject: Object {
void init(String *name, bool createProto);
- ReturnedValue newInstance();
-
using Object::construct;
using Object::call;
- static ReturnedValue construct(const Managed *that, CallData *);
- static ReturnedValue call(const Managed *that, CallData *d);
+ static void construct(const Managed *that, Scope &scope, CallData *);
+ static void call(const Managed *that, Scope &scope, CallData *d);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true);
static Heap::FunctionObject *createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction,
@@ -178,8 +176,8 @@ struct FunctionCtor: FunctionObject
{
V4_OBJECT2(FunctionCtor, FunctionObject)
- static ReturnedValue construct(const Managed *that, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *that, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct FunctionPrototype: FunctionObject
@@ -202,20 +200,20 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject {
return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code);
}
- static ReturnedValue construct(const Managed *, CallData *);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct IndexedBuiltinFunction: FunctionObject
{
V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *)
+ static void construct(const Managed *m, Scope &scope, CallData *)
{
- return static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError();
+ scope.result = static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError();
}
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scope, uint index,
@@ -231,8 +229,8 @@ struct SimpleScriptFunction: FunctionObject {
V4_OBJECT2(SimpleScriptFunction, FunctionObject)
V4_INTERNALCLASS(simpleScriptFunctionClass)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
Heap::Object *protoForConstructor();
};
@@ -240,8 +238,8 @@ struct SimpleScriptFunction: FunctionObject {
struct ScriptFunction: SimpleScriptFunction {
V4_OBJECT2(ScriptFunction, FunctionObject)
- static ReturnedValue construct(const Managed *, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
@@ -257,8 +255,8 @@ struct BoundFunction: FunctionObject {
Value boundThis() const { return d()->boundThis; }
Heap::MemberData *boundArgs() const { return d()->boundArgs; }
- static ReturnedValue construct(const Managed *, CallData *d);
- static ReturnedValue call(const Managed *that, CallData *dd);
+ static void construct(const Managed *, Scope &scope, CallData *d);
+ static void call(const Managed *that, Scope &scope, CallData *dd);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 921edbc883..184375a9b6 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -135,7 +135,7 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
#define ENABLE_JIT 0
#endif
-#if defined(Q_OS_QNX)
+#if defined(Q_OS_QNX) && defined(_CPPLIB_VER)
#include <math.h>
#undef isnan
#undef isfinite
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 2c767e3302..b88e271a26 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -338,13 +338,14 @@ Heap::EvalFunction::EvalFunction(QV4::ExecutionContext *scope)
f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1));
}
-ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const
+void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) const
{
- if (callData->argc < 1)
- return Encode::undefined();
+ if (callData->argc < 1) {
+ scope.result = Encode::undefined();
+ return;
+ }
ExecutionEngine *v4 = engine();
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
ExecutionContext *currentContext = v4->currentContext;
@@ -356,8 +357,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const
ctx = v4->pushGlobalContext();
}
- if (!callData->args[0].isString())
- return callData->args[0].asReturnedValue();
+ if (!callData->args[0].isString()) {
+ scope.result = callData->args[0].asReturnedValue();
+ return;
+ }
const QString code = callData->args[0].stringValue()->toQString();
bool inheritContext = !ctx->d()->strictMode;
@@ -366,18 +369,23 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const
script.strictMode = (directCall && currentContext->d()->strictMode);
script.inheritContext = inheritContext;
script.parse();
- if (v4->hasException)
- return Encode::undefined();
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
Function *function = script.function();
- if (!function)
- return Encode::undefined();
+ if (!function) {
+ scope.result = Encode::undefined();
+ return;
+ }
if (function->isStrict() || (ctx->d()->strictMode)) {
ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
ScopedCallData callData(scope, 0);
callData->thisObject = ctx->thisObject();
- return e->call(callData);
+ e->call(scope, callData);
+ return;
}
ContextStateSaver stateSaver(scope, ctx);
@@ -386,14 +394,14 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const
ctx->d()->strictMode = false;
ctx->d()->compilationUnit = function->compilationUnit;
- return Q_V4_PROFILE(ctx->engine(), function);
+ scope.result = Q_V4_PROFILE(ctx->engine(), function);
}
-ReturnedValue EvalFunction::call(const Managed *that, CallData *callData)
+void EvalFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
// indirect call
- return static_cast<const EvalFunction *>(that)->evalCall(callData, false);
+ static_cast<const EvalFunction *>(that)->evalCall(scope, callData, false);
}
@@ -512,7 +520,7 @@ ReturnedValue GlobalFunctions::method_parseFloat(CallContext *ctx)
if (trimmed.startsWith(QLatin1String("Infinity"))
|| trimmed.startsWith(QLatin1String("+Infinity")))
return Encode(Q_INFINITY);
- if (trimmed.startsWith(QStringLiteral("-Infinity")))
+ if (trimmed.startsWith(QLatin1String("-Infinity")))
return Encode(-Q_INFINITY);
QByteArray ba = trimmed.toLatin1();
bool ok;
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index ea7a3b06ce..403639f8c1 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -69,9 +69,9 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject
{
V4_OBJECT2(EvalFunction, FunctionObject)
- ReturnedValue evalCall(CallData *callData, bool directCall) const;
+ void evalCall(Scope &scope, CallData *callData, bool directCall) const;
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct GlobalFunctions
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index b3462fe9b1..c33d2cad11 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -122,7 +122,7 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status)
QV4::ScopedCallData callData(scope, 1);
callData->thisObject = v4->globalObject->asReturnedValue();
callData->args[0] = status;
- f->call(callData);
+ f->call(scope, callData);
if (scope.hasException())
scope.engine->catchException();
}
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 9660a5e76d..bac45e18c8 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -101,20 +101,6 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
++d->size;
}
-uint PropertyHash::lookup(const Identifier *identifier) const
-{
- Q_ASSERT(d->entries);
-
- uint idx = identifier->hashValue % d->alloc;
- while (1) {
- if (d->entries[idx].identifier == identifier)
- return d->entries[idx].index;
- if (!d->entries[idx].identifier)
- return UINT_MAX;
- ++idx;
- idx %= d->alloc;
- }
-}
InternalClass::InternalClass(ExecutionEngine *engine)
: engine(engine)
@@ -161,8 +147,8 @@ static void insertHoleIntoPropertyData(Object *object, int idx)
static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
{
int inlineSize = object->d()->inlineMemberSize;
- int icSize = object->internalClass()->size;
int delta = (accessor ? 2 : 1);
+ int oldSize = object->internalClass()->size + delta;
int to = idx;
int from = to + delta;
if (from < inlineSize) {
@@ -170,15 +156,15 @@ static void removeFromPropertyData(Object *object, int idx, bool accessor = fals
to = inlineSize - delta;
from = inlineSize;
}
- if (to < inlineSize && from < icSize) {
+ if (to < inlineSize && from < oldSize) {
Q_ASSERT(from >= inlineSize);
memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value));
to = inlineSize;
from = inlineSize + delta;
}
- if (from < icSize + delta) {
+ if (from < oldSize) {
Q_ASSERT(to >= inlineSize && from > to);
- memmove(object->propertyData(to), object->d()->propertyData(from), (icSize + delta - to)*sizeof(Value));
+ memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value));
}
}
@@ -360,18 +346,6 @@ void InternalClass::removeMember(Object *object, Identifier *id)
Q_ASSERT(t.lookup);
}
-uint InternalClass::find(const String *string)
-{
- engine->identifierTable->identifier(string);
- const Identifier *id = string->d()->identifier;
-
- uint index = propertyTable.lookup(id);
- if (index < size)
- return index;
-
- return UINT_MAX;
-}
-
uint InternalClass::find(const Identifier *id)
{
uint index = propertyTable.lookup(id);
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index c10af4ce01..dcda949c97 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -54,6 +54,8 @@
#include <QHash>
#include <private/qqmljsmemorypool_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4identifiertable_p.h>
QT_BEGIN_NAMESPACE
@@ -117,6 +119,20 @@ inline PropertyHash::~PropertyHash()
delete d;
}
+inline uint PropertyHash::lookup(const Identifier *identifier) const
+{
+ Q_ASSERT(d->entries);
+
+ uint idx = identifier->hashValue % d->alloc;
+ while (1) {
+ if (d->entries[idx].identifier == identifier)
+ return d->entries[idx].index;
+ if (!d->entries[idx].identifier)
+ return UINT_MAX;
+ ++idx;
+ idx %= d->alloc;
+ }
+}
template <typename T>
struct SharedInternalClassData {
@@ -245,7 +261,7 @@ struct InternalClass : public QQmlJS::Managed {
InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0);
static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0);
static void removeMember(Object *object, Identifier *id);
- uint find(const String *s);
+ uint find(const String *string);
uint find(const Identifier *id);
InternalClass *sealed();
@@ -261,6 +277,18 @@ private:
InternalClass(const InternalClass &other);
};
+inline uint InternalClass::find(const String *string)
+{
+ engine->identifierTable->identifier(string);
+ const Identifier *id = string->d()->identifier;
+
+ uint index = propertyTable.lookup(id);
+ if (index < size)
+ return index;
+
+ return UINT_MAX;
+}
+
struct InternalClassPool : public QQmlJS::MemoryPool
{
void markObjects(ExecutionEngine *engine);
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 0ae7c33dea..5b665d8836 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -643,34 +643,37 @@ struct Stringify
static QString quote(const QString &str)
{
- QString product = QStringLiteral("\"");
- for (int i = 0; i < str.length(); ++i) {
+ QString product;
+ const int length = str.length();
+ product.reserve(length + 2);
+ product += QLatin1Char('"');
+ for (int i = 0; i < length; ++i) {
QChar c = str.at(i);
switch (c.unicode()) {
case '"':
- product += QStringLiteral("\\\"");
+ product += QLatin1String("\\\"");
break;
case '\\':
- product += QStringLiteral("\\\\");
+ product += QLatin1String("\\\\");
break;
case '\b':
- product += QStringLiteral("\\b");
+ product += QLatin1String("\\b");
break;
case '\f':
- product += QStringLiteral("\\f");
+ product += QLatin1String("\\f");
break;
case '\n':
- product += QStringLiteral("\\n");
+ product += QLatin1String("\\n");
break;
case '\r':
- product += QStringLiteral("\\r");
+ product += QLatin1String("\\r");
break;
case '\t':
- product += QStringLiteral("\\t");
+ product += QLatin1String("\\t");
break;
default:
if (c.unicode() <= 0x1f) {
- product += QStringLiteral("\\u00");
+ product += QLatin1String("\\u00");
product += (c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0')) +
QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]);
} else {
@@ -685,53 +688,53 @@ static QString quote(const QString &str)
QString Stringify::Str(const QString &key, const Value &v)
{
Scope scope(v4);
+ scope.result = v;
- ScopedValue value(scope, v);
- ScopedObject o(scope, value);
+ ScopedObject o(scope, scope.result);
if (o) {
ScopedString s(scope, v4->newString(QStringLiteral("toJSON")));
ScopedFunctionObject toJSON(scope, o->get(s));
if (!!toJSON) {
ScopedCallData callData(scope, 1);
- callData->thisObject = value;
+ callData->thisObject = scope.result;
callData->args[0] = v4->newString(key);
- value = toJSON->call(callData);
+ toJSON->call(scope, callData);
}
}
if (replacerFunction) {
ScopedObject holder(scope, v4->newObject());
- holder->put(scope.engine, QString(), value);
+ holder->put(scope.engine, QString(), scope.result);
ScopedCallData callData(scope, 2);
callData->args[0] = v4->newString(key);
- callData->args[1] = value;
+ callData->args[1] = scope.result;
callData->thisObject = holder;
- value = replacerFunction->call(callData);
+ replacerFunction->call(scope, callData);
}
- o = value->asReturnedValue();
+ o = scope.result.asReturnedValue();
if (o) {
if (NumberObject *n = o->as<NumberObject>())
- value = Encode(n->value());
+ scope.result = Encode(n->value());
else if (StringObject *so = o->as<StringObject>())
- value = so->d()->string;
+ scope.result = so->d()->string;
else if (BooleanObject *b = o->as<BooleanObject>())
- value = Encode(b->value());
+ scope.result = Encode(b->value());
}
- if (value->isNull())
+ if (scope.result.isNull())
return QStringLiteral("null");
- if (value->isBoolean())
- return value->booleanValue() ? QStringLiteral("true") : QStringLiteral("false");
- if (value->isString())
- return quote(value->stringValue()->toQString());
-
- if (value->isNumber()) {
- double d = value->toNumber();
- return std::isfinite(d) ? value->toQString() : QStringLiteral("null");
+ if (scope.result.isBoolean())
+ return scope.result.booleanValue() ? QStringLiteral("true") : QStringLiteral("false");
+ if (scope.result.isString())
+ return quote(scope.result.stringValue()->toQString());
+
+ if (scope.result.isNumber()) {
+ double d = scope.result.toNumber();
+ return std::isfinite(d) ? scope.result.toQString() : QStringLiteral("null");
}
- o = value->asReturnedValue();
+ o = scope.result.asReturnedValue();
if (o) {
if (!o->as<FunctionObject>()) {
if (o->as<ArrayObject>()) {
@@ -806,10 +809,10 @@ QString Stringify::JO(Object *o)
if (partial.isEmpty()) {
result = QStringLiteral("{}");
} else if (gap.isEmpty()) {
- result = QStringLiteral("{") + partial.join(QLatin1Char(',')) + QLatin1Char('}');
+ result = QLatin1Char('{') + partial.join(QLatin1Char(',')) + QLatin1Char('}');
} else {
- QString separator = QStringLiteral(",\n") + indent;
- result = QStringLiteral("{\n") + indent + partial.join(separator) + QLatin1Char('\n')
+ QString separator = QLatin1String(",\n") + indent;
+ result = QLatin1String("{\n") + indent + partial.join(separator) + QLatin1Char('\n')
+ stepback + QLatin1Char('}');
}
@@ -852,10 +855,10 @@ QString Stringify::JA(ArrayObject *a)
if (partial.isEmpty()) {
result = QStringLiteral("[]");
} else if (gap.isEmpty()) {
- result = QStringLiteral("[") + partial.join(QLatin1Char(',')) + QStringLiteral("]");
+ result = QLatin1Char('[') + partial.join(QLatin1Char(',')) + QLatin1Char(']');
} else {
- QString separator = QStringLiteral(",\n") + indent;
- result = QStringLiteral("[\n") + indent + partial.join(separator) + QStringLiteral("\n") + stepback + QStringLiteral("]");
+ QString separator = QLatin1String(",\n") + indent;
+ result = QLatin1String("[\n") + indent + partial.join(separator) + QLatin1Char('\n') + stepback + QLatin1Char(']');
}
indent = stepback;
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 46e47307ef..42e561bc7c 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -451,7 +451,8 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
l->getter = getterFallback;
@@ -473,7 +474,8 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
l->getter = getterFallback;
@@ -498,7 +500,8 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
}
@@ -542,7 +545,8 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
l->getter = getterGeneric;
@@ -562,7 +566,8 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin
ScopedCallData callData(scope, 0);
callData->thisObject = object;
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
l->getter = getterGeneric;
@@ -665,7 +670,8 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine)
ScopedCallData callData(scope, 0);
callData->thisObject = Primitive::undefinedValue();
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -683,7 +689,8 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine)
ScopedCallData callData(scope, 0);
callData->thisObject = Primitive::undefinedValue();
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -704,7 +711,8 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine)
ScopedCallData callData(scope, 0);
callData->thisObject = Primitive::undefinedValue();
- return getter->call(callData);
+ getter->call(scope, callData);
+ return scope.result.asReturnedValue();
}
}
}
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 1109760fc0..764a8e7f3f 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -85,7 +85,12 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
static const QV4::VTable static_vtbl; \
static inline const QV4::VTable *staticVTable() { return &static_vtbl; } \
V4_MANAGED_SIZE_TEST \
- QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m()); }
+ QV4::Heap::DataClass *d_unchecked() const { return static_cast<QV4::Heap::DataClass *>(m()); } \
+ QV4::Heap::DataClass *d() const { \
+ QV4::Heap::DataClass *dptr = d_unchecked(); \
+ if (std::is_trivial<QV4::Heap::DataClass>::value) dptr->_checkIsInitialized(); \
+ return dptr; \
+ }
#define V4_MANAGED(DataClass, superClass) \
private: \
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index 62e4f0a14d..5646a44891 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -58,9 +58,9 @@ static Heap::MemberData *reallocateHelper(ExecutionEngine *e, Heap::MemberData *
Scope scope(e);
Scoped<MemberData> newMemberData(scope, e->memoryManager->allocManaged<MemberData>(alloc));
if (old)
- memcpy(newMemberData->d(), old, sizeof(Heap::MemberData) + old->size * sizeof(Value));
+ memcpy(newMemberData->d_unchecked(), old, sizeof(Heap::MemberData) + old->size * sizeof(Value));
else
- new (newMemberData->d()) Heap::MemberData;
+ newMemberData->d_unchecked()->init();
newMemberData->d()->size = n;
return newMemberData->d();
}
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index 2742e0b212..41da730428 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -66,6 +66,7 @@ struct MemberData : Base {
};
Value data[1];
};
+Q_STATIC_ASSERT(std::is_trivial<MemberData>::value);
}
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index f6b3e9a2b3..444a4cd6f0 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -63,7 +63,9 @@ NumberLocale::NumberLocale() : QLocale(QLocale::C),
// -128 means shortest string that can accurately represent the number.
defaultDoublePrecision(0xffffff80)
{
- setNumberOptions(QLocale::OmitGroupSeparator | QLocale::OmitLeadingZeroInExponent);
+ setNumberOptions(QLocale::OmitGroupSeparator |
+ QLocale::OmitLeadingZeroInExponent |
+ QLocale::IncludeTrailingZeroesAfterDot);
}
const NumberLocale *NumberLocale::instance()
@@ -76,17 +78,16 @@ Heap::NumberCtor::NumberCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue NumberCtor::construct(const Managed *m, CallData *callData)
+void NumberCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(m->cast<NumberCtor>()->engine());
double dbl = callData->argc ? callData->args[0].toNumber() : 0.;
- return Encode(scope.engine->newNumberObject(dbl));
+ scope.result = Encode(scope.engine->newNumberObject(dbl));
}
-ReturnedValue NumberCtor::call(const Managed *, CallData *callData)
+void NumberCtor::call(const Managed *, Scope &scope, CallData *callData)
{
double dbl = callData->argc ? callData->args[0].toNumber() : 0.;
- return Encode(dbl);
+ scope.result = Encode(dbl);
}
void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -286,7 +287,7 @@ ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx)
if (!ctx->argc() || ctx->args()[0].isUndefined())
return RuntimeHelpers::toString(scope.engine, v);
- double precision = ctx->args()[0].toInt32();
+ int precision = ctx->args()[0].toInt32();
if (precision < 1 || precision > 21) {
ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range")));
return ctx->engine()->throwRangeError(error);
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index bbe22af4bb..2416165c78 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -79,8 +79,8 @@ struct NumberCtor: FunctionObject
{
V4_OBJECT2(NumberCtor, FunctionObject)
- static ReturnedValue construct(const Managed *that, CallData *callData);
- static ReturnedValue call(const Managed *, CallData *callData);
+ static void construct(const Managed *that, Scope &scope, CallData *callData);
+ static void call(const Managed *, Scope &scope, CallData *callData);
};
struct NumberPrototype: NumberObject
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index ff3208485e..aeb185049f 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -109,7 +109,8 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property
Scope scope(f->engine());
ScopedCallData callData(scope);
callData->thisObject = thisObject;
- return f->call(callData);
+ f->call(scope, callData);
+ return scope.result.asReturnedValue();
}
void Object::putValue(uint memberIndex, const Value &value)
@@ -128,7 +129,7 @@ void Object::putValue(uint memberIndex, const Value &value)
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
- setter->call(callData);
+ setter->call(scope, callData);
return;
}
goto reject;
@@ -389,14 +390,14 @@ bool Object::hasOwnProperty(uint index) const
return false;
}
-ReturnedValue Object::construct(const Managed *m, CallData *)
+void Object::construct(const Managed *m, Scope &scope, CallData *)
{
- return static_cast<const Object *>(m)->engine()->throwTypeError();
+ scope.result = static_cast<const Object *>(m)->engine()->throwTypeError();
}
-ReturnedValue Object::call(const Managed *m, CallData *)
+void Object::call(const Managed *m, Scope &scope, CallData *)
{
- return static_cast<const Object *>(m)->engine()->throwTypeError();
+ scope.result = static_cast<const Object *>(m)->engine()->throwTypeError();
}
ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty)
@@ -744,7 +745,7 @@ void Object::internalPut(String *name, const Value &value)
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
- setter->call(callData);
+ setter->call(scope, callData);
return;
}
@@ -753,7 +754,7 @@ void Object::internalPut(String *name, const Value &value)
reject:
if (engine()->current->strictMode) {
- QString message = QStringLiteral("Cannot assign to read-only property \"") +
+ QString message = QLatin1String("Cannot assign to read-only property \"") +
name->toQString() + QLatin1Char('\"');
engine()->throwTypeError(message);
}
@@ -814,7 +815,7 @@ void Object::internalPutIndexed(uint index, const Value &value)
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
- setter->call(callData);
+ setter->call(scope, callData);
return;
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index e4431a9fc9..54ce2ea60d 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -56,6 +56,9 @@
#include "qv4engine_p.h"
#include "qv4scopedvalue_p.h"
#include "qv4value_p.h"
+#include "qv4internalclass_p.h"
+
+#include <QtCore/qtypetraits.h>
QT_BEGIN_NAMESPACE
@@ -65,7 +68,7 @@ namespace QV4 {
namespace Heap {
struct Object : Base {
- inline Object() {}
+ inline Object() { Base::init(); }
const Value *propertyData(uint index) const { if (index < inlineMemberSize) return reinterpret_cast<const Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; }
Value *propertyData(uint index) { if (index < inlineMemberSize) return reinterpret_cast<Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; }
@@ -87,7 +90,12 @@ struct Object : Base {
static const QV4::ObjectVTable static_vtbl; \
static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \
V4_MANAGED_SIZE_TEST \
- Data *d() const { return static_cast<Data *>(m()); }
+ Data *d_unchecked() const { return static_cast<Data *>(m()); } \
+ Data *d() const { \
+ Data *dptr = d_unchecked(); \
+ if (std::is_trivial<Data>::value) dptr->_checkIsInitialized(); \
+ return dptr; \
+ }
#define V4_OBJECT2(DataClass, superClass) \
private: \
@@ -100,7 +108,12 @@ struct Object : Base {
static const QV4::ObjectVTable static_vtbl; \
static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \
V4_MANAGED_SIZE_TEST \
- QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m()); }
+ QV4::Heap::DataClass *d_unchecked() const { return static_cast<QV4::Heap::DataClass *>(m()); } \
+ QV4::Heap::DataClass *d() const { \
+ QV4::Heap::DataClass *dptr = d_unchecked(); \
+ if (std::is_trivial<QV4::Heap::DataClass>::value) dptr->_checkIsInitialized(); \
+ return dptr; \
+ }
#define V4_INTERNALCLASS(c) \
static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \
@@ -112,8 +125,8 @@ struct Object : Base {
struct ObjectVTable
{
VTable vTable;
- ReturnedValue (*call)(const Managed *, CallData *data);
- ReturnedValue (*construct)(const Managed *, CallData *data);
+ void (*call)(const Managed *, Scope &scope, CallData *data);
+ void (*construct)(const Managed *, Scope &scope, CallData *data);
ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
void (*put)(Managed *, String *name, const Value &value);
@@ -131,7 +144,7 @@ struct ObjectVTable
#define DEFINE_OBJECT_VTABLE(classname) \
const QV4::ObjectVTable classname::static_vtbl = \
{ \
- DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.vTable), \
+ DEFINE_MANAGED_VTABLE_INT(classname, (QT_PREPEND_NAMESPACE(QtPrivate)::is_same<classname::SuperClass, Object>::value) ? Q_NULLPTR : &classname::SuperClass::static_vtbl.vTable), \
call, \
construct, \
get, \
@@ -324,14 +337,14 @@ public:
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
uint getLength() const { return vtable()->getLength(this); }
- inline ReturnedValue construct(CallData *d) const
- { return vtable()->construct(this, d); }
- inline ReturnedValue call(CallData *d) const
- { return vtable()->call(this, d); }
+ inline void construct(Scope &scope, CallData *d) const
+ { return vtable()->construct(this, scope, d); }
+ inline void call(Scope &scope, CallData *d) const
+ { vtable()->call(this, scope, d); }
protected:
static void markObjects(Heap::Base *that, ExecutionEngine *e);
- static ReturnedValue construct(const Managed *m, CallData *);
- static ReturnedValue call(const Managed *m, CallData *);
+ static void construct(const Managed *m, Scope &scope, CallData *);
+ static void call(const Managed *m, Scope &scope, CallData *);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
static void put(Managed *m, String *name, const Value &value);
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index b5e26b925f..4354e09248 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -74,11 +74,6 @@ void ObjectIterator::init(const Object *o)
object->setM(o ? o->m() : 0);
current->setM(o ? o->m() : 0);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
- object->setTag(QV4::Value::Managed_Type);
- current->setTag(QV4::Value::Managed_Type);
-#endif
-
if (object->as<ArgumentsObject>()) {
Scope scope(engine);
Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 015294e48a..cfd76166f2 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -59,28 +59,30 @@ Heap::ObjectCtor::ObjectCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue ObjectCtor::construct(const Managed *that, CallData *callData)
+void ObjectCtor::construct(const Managed *that, Scope &scope, CallData *callData)
{
const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that);
ExecutionEngine *v4 = ctor->engine();
- Scope scope(v4);
if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) {
ScopedObject obj(scope, v4->newObject());
ScopedObject proto(scope, ctor->get(v4->id_prototype()));
if (!!proto)
obj->setPrototype(proto);
- return obj.asReturnedValue();
+ scope.result = obj.asReturnedValue();
+ } else {
+ scope.result = RuntimeHelpers::toObject(scope.engine, callData->args[0]);
}
- return RuntimeHelpers::toObject(scope.engine, callData->args[0]);
}
-ReturnedValue ObjectCtor::call(const Managed *m, CallData *callData)
+void ObjectCtor::call(const Managed *m, Scope &scope, CallData *callData)
{
const ObjectCtor *ctor = static_cast<const ObjectCtor *>(m);
ExecutionEngine *v4 = ctor->engine();
- if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull())
- return v4->newObject()->asReturnedValue();
- return RuntimeHelpers::toObject(v4, callData->args[0]);
+ if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) {
+ scope.result = v4->newObject()->asReturnedValue();
+ } else {
+ scope.result = RuntimeHelpers::toObject(v4, callData->args[0]);
+ }
}
void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
@@ -413,7 +415,8 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx)
return ctx->engine()->throwTypeError();
ScopedCallData callData(scope);
callData->thisObject = o;
- return f->call(callData);
+ f->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx)
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index ac1964103e..47a37b196f 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -70,8 +70,8 @@ struct ObjectCtor: FunctionObject
{
V4_OBJECT2(ObjectCtor, FunctionObject)
- static ReturnedValue construct(const Managed *that, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *that, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
struct ObjectPrototype: Object
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index f6d4046ec4..7ca0692804 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -85,11 +85,9 @@ Page *allocatePage(PersistentValueStorage *storage)
if (p->header.next)
p->header.next->header.prev = &p->header.next;
for (int i = 0; i < kEntriesPerPage - 1; ++i) {
- p->values[i].setTag(QV4::Value::Empty_Type);
- p->values[i].setInt_32(i + 1);
+ p->values[i].setEmpty(i + 1);
}
- p->values[kEntriesPerPage - 1].setTag(QV4::Value::Empty_Type);
- p->values[kEntriesPerPage - 1].setInt_32(-1);
+ p->values[kEntriesPerPage - 1].setEmpty(-1);
storage->firstPage = p;
@@ -211,8 +209,7 @@ void PersistentValueStorage::free(Value *v)
Page *p = getPage(v);
- v->setTag(QV4::Value::Empty_Type);
- v->setInt_32(p->header.freeList);
+ v->setEmpty(p->header.freeList);
p->header.freeList = v - p->values;
if (!--p->header.refCount)
freePage(p);
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index 5b1926468a..a0ade2068f 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -118,7 +118,7 @@ public:
Managed *asManaged() const {
if (!val)
return 0;
- return val->as<Managed>();
+ return val->managed();
}
template<typename T>
T *as() const {
@@ -167,7 +167,7 @@ public:
Managed *asManaged() const {
if (!val)
return 0;
- return val->as<Managed>();
+ return val->managed();
}
template <typename T>
T *as() const {
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 349ec48e06..8862cbef8e 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -96,7 +96,7 @@ void Profiler::reportData(bool trackLocations)
FunctionLocationHash locations;
properties.reserve(m_data.size());
- foreach (const FunctionCall &call, m_data) {
+ for (const FunctionCall &call : qAsConst(m_data)) {
properties.append(call.properties());
Function *function = call.function();
SentMarker &marker = m_sentLocations[reinterpret_cast<quintptr>(function)];
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index 01fdf2951e..e06cb64a61 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -57,6 +57,40 @@
#include <QElapsedTimer>
+#ifdef QT_NO_QML_DEBUGGER
+
+#define Q_V4_PROFILE_ALLOC(engine, size, type) (!engine)
+#define Q_V4_PROFILE_DEALLOC(engine, size, type) (!engine)
+#define Q_V4_PROFILE(engine, function) (function->code(engine, function->codeData))
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace Profiling {
+struct Profiler {};
+}
+}
+
+QT_END_NAMESPACE
+
+#else
+
+#define Q_V4_PROFILE_ALLOC(engine, size, type)\
+ (engine->profiler() &&\
+ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
+ engine->profiler()->trackAlloc(size, type) : false)
+
+#define Q_V4_PROFILE_DEALLOC(engine, size, type) \
+ (engine->profiler() &&\
+ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
+ engine->profiler()->trackDealloc(size, type) : false)
+
+#define Q_V4_PROFILE(engine, function)\
+ (engine->profiler() &&\
+ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\
+ Profiling::FunctionCallProfiler::profileCall(engine->profiler(), engine, function) :\
+ function->code(engine, function->codeData))
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -150,25 +184,8 @@ private:
qint64 m_end;
};
-#define Q_V4_PROFILE_ALLOC(engine, size, type)\
- (engine->profiler &&\
- (engine->profiler->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
- engine->profiler->trackAlloc(size, type) : size)
-
-#define Q_V4_PROFILE_DEALLOC(engine, pointer, size, type) \
- (engine->profiler &&\
- (engine->profiler->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
- engine->profiler->trackDealloc(pointer, size, type) : pointer)
-
-#define Q_V4_PROFILE(engine, function)\
- (engine->profiler &&\
- (engine->profiler->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\
- Profiling::FunctionCallProfiler::profileCall(engine->profiler, engine, function) :\
- function->code(engine, function->codeData))
-
class Q_QML_EXPORT Profiler : public QObject {
Q_OBJECT
- Q_DISABLE_COPY(Profiler)
public:
struct SentMarker {
SentMarker() : m_function(nullptr) {}
@@ -212,23 +229,22 @@ public:
Profiler(QV4::ExecutionEngine *engine);
- size_t trackAlloc(size_t size, MemoryType type)
+ bool trackAlloc(size_t size, MemoryType type)
{
MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type};
m_memory_data.append(allocation);
- return size;
+ return true;
}
- void *trackDealloc(void *pointer, size_t size, MemoryType type)
+ bool trackDealloc(size_t size, MemoryType type)
{
MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type};
m_memory_data.append(allocation);
- return pointer;
+ return true;
}
quint64 featuresEnabled;
-public slots:
void stopProfiling();
void startProfiling(quint64 features);
void reportData(bool trackLocations);
@@ -290,4 +306,6 @@ Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash)
Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>)
Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>)
+#endif // QT_NO_QML_DEBUGGER
+
#endif // QV4PROFILING_H
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index c888f1e44c..b901d9be85 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -44,7 +44,6 @@
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qjsvalue_p.h>
-#include <private/qqmlaccessors_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmltypewrapper_p.h>
@@ -75,6 +74,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
@@ -114,130 +114,90 @@ static QPair<QObject *, int> extractQtSignal(const Value &value)
return qMakePair((QObject *)0, -1);
}
-
-struct ReadAccessor {
- static inline void Indirect(QObject *object, const QQmlPropertyData &property,
- void *output, QQmlNotifier **n)
- {
- Q_ASSERT(n == 0);
- Q_UNUSED(n);
-
- void *args[] = { output, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
- }
-
- static inline void Direct(QObject *object, const QQmlPropertyData &property,
- void *output, QQmlNotifier **n)
- {
- Q_ASSERT(n == 0);
- Q_UNUSED(n);
-
- void *args[] = { output, 0 };
- object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args);
- }
-
- static inline void Accessor(QObject *object, const QQmlPropertyData &property,
- void *output, QQmlNotifier **n)
- {
- Q_ASSERT(property.accessors);
-
- property.accessors->read(object, output);
- if (n) property.accessors->notifier(object, n);
- }
-};
-
-// Load value properties
-template<void (*ReadFunction)(QObject *, const QQmlPropertyData &,
- void *, QQmlNotifier **)>
-static QV4::ReturnedValue LoadProperty(QV4::ExecutionEngine *v4, QObject *object,
- const QQmlPropertyData &property,
- QQmlNotifier **notifier)
+static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object,
+ const QQmlPropertyData &property)
{
Q_ASSERT(!property.isFunction());
QV4::Scope scope(v4);
if (property.isQObject()) {
QObject *rv = 0;
- ReadFunction(object, property, &rv, notifier);
+ property.readProperty(object, &rv);
return QV4::QObjectWrapper::wrap(v4, rv);
} else if (property.isQList()) {
- return QmlListWrapper::create(v4, object, property.coreIndex, property.propType);
- } else if (property.propType == QMetaType::QReal) {
+ return QmlListWrapper::create(v4, object, property.coreIndex(), property.propType());
+ } else if (property.propType() == QMetaType::QReal) {
qreal v = 0;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
return QV4::Encode(v);
- } else if (property.propType == QMetaType::Int || property.isEnum()) {
+ } else if (property.propType() == QMetaType::Int || property.isEnum()) {
int v = 0;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
return QV4::Encode(v);
- } else if (property.propType == QMetaType::Bool) {
+ } else if (property.propType() == QMetaType::Bool) {
bool v = false;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
return QV4::Encode(v);
- } else if (property.propType == QMetaType::QString) {
+ } else if (property.propType() == QMetaType::QString) {
QString v;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
return v4->newString(v)->asReturnedValue();
- } else if (property.propType == QMetaType::UInt) {
+ } else if (property.propType() == QMetaType::UInt) {
uint v = 0;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
return QV4::Encode(v);
- } else if (property.propType == QMetaType::Float) {
+ } else if (property.propType() == QMetaType::Float) {
float v = 0;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
return QV4::Encode(v);
- } else if (property.propType == QMetaType::Double) {
+ } else if (property.propType() == QMetaType::Double) {
double v = 0;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
return QV4::Encode(v);
} else if (property.isV4Handle()) {
QQmlV4Handle handle;
- ReadFunction(object, property, &handle, notifier);
+ property.readProperty(object, &handle);
return handle;
- } else if (property.propType == qMetaTypeId<QJSValue>()) {
+ } else if (property.propType() == qMetaTypeId<QJSValue>()) {
QJSValue v;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
return QJSValuePrivate::convertedToValue(v4, v);
} else if (property.isQVariant()) {
QVariant v;
- ReadFunction(object, property, &v, notifier);
+ property.readProperty(object, &v);
if (QQmlValueTypeFactory::isValueType(v.userType())) {
if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(v.userType()))
- return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex, valueTypeMetaObject, v.userType()); // VariantReference value-type.
+ return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex(), valueTypeMetaObject, v.userType()); // VariantReference value-type.
}
return scope.engine->fromVariant(v);
- } else if (QQmlValueTypeFactory::isValueType(property.propType)) {
- Q_ASSERT(notifier == 0);
-
- if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property.propType))
- return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex, valueTypeMetaObject, property.propType);
+ } else if (QQmlValueTypeFactory::isValueType(property.propType())) {
+ if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property.propType()))
+ return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex(), valueTypeMetaObject, property.propType());
} else {
- Q_ASSERT(notifier == 0);
-
// see if it's a sequence type
bool succeeded = false;
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::newSequence(v4, property.propType, object, property.coreIndex, &succeeded));
+ QV4::ScopedValue retn(scope, QV4::SequencePrototype::newSequence(v4, property.propType(), object, property.coreIndex(), &succeeded));
if (succeeded)
return retn->asReturnedValue();
}
- if (property.propType == QMetaType::UnknownType) {
- QMetaProperty p = object->metaObject()->property(property.coreIndex);
+ if (property.propType() == QMetaType::UnknownType) {
+ QMetaProperty p = object->metaObject()->property(property.coreIndex());
qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property "
"'%s::%s'", p.typeName(), object->metaObject()->className(), p.name());
return QV4::Encode::undefined();
} else {
- QVariant v(property.propType, (void *)0);
- ReadFunction(object, property, v.data(), notifier);
+ QVariant v(property.propType(), (void *)0);
+ property.readProperty(object, v.data());
return scope.engine->fromVariant(v);
}
}
Heap::QObjectWrapper::QObjectWrapper(QObject *object)
- : object(object)
{
+ qObj.init(object);
}
void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
@@ -250,21 +210,21 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont
{
Q_UNUSED(revisionMode);
- QQmlData *ddata = QQmlData::get(d()->object, false);
+ QQmlData *ddata = QQmlData::get(d()->object(), false);
if (!ddata)
return 0;
QQmlPropertyData *result = 0;
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(name, d()->object, qmlContext);
+ result = ddata->propertyCache->property(name, d()->object(), qmlContext);
else
- result = QQmlPropertyCache::property(engine->jsEngine(), d()->object, name, qmlContext, *local);
+ result = QQmlPropertyCache::property(engine->jsEngine(), d()->object(), name, qmlContext, *local);
return result;
}
ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode,
bool *hasProperty, bool includeImports) const
{
- if (QQmlData::wasDeleted(d()->object)) {
+ if (QQmlData::wasDeleted(d()->object())) {
if (hasProperty)
*hasProperty = false;
return QV4::Encode::undefined();
@@ -277,7 +237,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
if (hasProperty)
*hasProperty = true;
ExecutionContext *global = v4->rootContext();
- return QV4::QObjectMethod::create(global, d()->object, index);
+ return QV4::QObjectMethod::create(global, d()->object(), index);
}
QQmlPropertyData local;
@@ -296,10 +256,10 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
if (r.scriptIndex != -1) {
return QV4::Encode::undefined();
} else if (r.type) {
- return QmlTypeWrapper::create(v4, d()->object,
+ return QmlTypeWrapper::create(v4, d()->object(),
r.type, Heap::QmlTypeWrapper::ExcludeEnums);
} else if (r.importNamespace) {
- return QmlTypeWrapper::create(v4, d()->object,
+ return QmlTypeWrapper::create(v4, d()->object(),
qmlContext->imports, r.importNamespace, Heap::QmlTypeWrapper::ExcludeEnums);
}
Q_ASSERT(!"Unreachable");
@@ -309,7 +269,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
return QV4::Object::get(this, name, hasProperty);
}
- QQmlData *ddata = QQmlData::get(d()->object, false);
+ QQmlData *ddata = QQmlData::get(d()->object(), false);
if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
@@ -322,69 +282,44 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
if (hasProperty)
*hasProperty = true;
- return getProperty(v4, d()->object, result);
+ return getProperty(v4, d()->object(), result);
}
ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
{
- QQmlData::flushPendingBinding(object, property->coreIndex);
+ QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
if (property->isFunction() && !property->isVarProperty()) {
if (property->isVMEFunction()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
- return vmemo->vmeMethod(property->coreIndex);
+ return vmemo->vmeMethod(property->coreIndex());
} else if (property->isV4Function()) {
Scope scope(engine);
ScopedContext global(scope, engine->qmlContext());
if (!global)
global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex);
+ return QV4::QObjectMethod::create(global, object, property->coreIndex());
} else if (property->isSignalHandler()) {
QmlSignalHandler::initProto(engine);
- return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex)->asReturnedValue();
+ return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
} else {
ExecutionContext *global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex);
+ return QV4::QObjectMethod::create(global, object, property->coreIndex());
}
}
QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
- if (property->hasAccessors()) {
- QQmlNotifier *n = 0;
- QQmlNotifier **nptr = 0;
-
- if (ep && ep->propertyCapture && property->accessors->notifier)
- nptr = &n;
-
- Scope scope(engine);
- QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(engine, object, *property, nptr));
-
- if (captureRequired) {
- if (property->accessors->notifier) {
- if (n && ep->propertyCapture)
- ep->propertyCapture->captureProperty(n);
- } else {
- if (ep->propertyCapture)
- ep->propertyCapture->captureProperty(object, property->coreIndex, property->notifyIndex);
- }
- }
-
- return rv->asReturnedValue();
- }
-
if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
- ep->propertyCapture->captureProperty(object, property->coreIndex, property->notifyIndex);
+ ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
- return vmemo->vmeProperty(property->coreIndex);
- } else if (property->isDirect()) {
- return LoadProperty<ReadAccessor::Direct>(engine, object, *property, 0);
+ return vmemo->vmeProperty(property->coreIndex());
} else {
- return LoadProperty<ReadAccessor::Indirect>(engine, object, *property, 0);
+ return loadProperty(engine, object, *property);
}
}
@@ -447,13 +382,13 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
QV4::ScopedFunctionObject f(scope, value);
if (f) {
if (!f->isBinding()) {
- if (!property->isVarProperty() && property->propType != qMetaTypeId<QJSValue>()) {
+ if (!property->isVarProperty() && property->propType() != qMetaTypeId<QJSValue>()) {
// assigning a JS function to a non var or QJSValue property or is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to ");
- if (!QMetaType::typeName(property->propType))
+ if (!QMetaType::typeName(property->propType()))
error += QLatin1String("[unknown property type]");
else
- error += QLatin1String(QMetaType::typeName(property->propType));
+ error += QLatin1String(QMetaType::typeName(property->propType()));
scope.engine->throwError(error);
return;
}
@@ -464,21 +399,21 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
bindingFunction->initBindingLocation();
- newBinding = new QQmlBinding(value, object, callingQmlContext);
- newBinding->setTarget(object, *property);
+ newBinding = QQmlBinding::create(property, value, object, callingQmlContext);
+ newBinding->setTarget(object, *property, nullptr);
}
}
if (newBinding)
QQmlPropertyPrivate::setBinding(newBinding);
else
- QQmlPropertyPrivate::removeBinding(object, property->encodedIndex());
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
if (!newBinding && property->isVarProperty()) {
// allow assignment of "special" values (null, undefined, function) to var properties
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
- vmemo->setVMEProperty(property->coreIndex, value);
+ vmemo->setVMEProperty(property->coreIndex(), value);
return;
}
@@ -487,44 +422,44 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
int status = -1; \
int flags = 0; \
void *argv[] = { &o, 0, &status, &flags }; \
- QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex, argv);
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex(), argv);
if (value.isNull() && property->isQObject()) {
PROPERTY_STORE(QObject*, 0);
} else if (value.isUndefined() && property->isResettable()) {
void *a[] = { 0 };
- QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a);
- } else if (value.isUndefined() && property->propType == qMetaTypeId<QVariant>()) {
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex(), a);
+ } else if (value.isUndefined() && property->propType() == qMetaTypeId<QVariant>()) {
PROPERTY_STORE(QVariant, QVariant());
- } else if (value.isUndefined() && property->propType == QMetaType::QJsonValue) {
+ } else if (value.isUndefined() && property->propType() == QMetaType::QJsonValue) {
PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
- } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) {
+ } else if (!newBinding && property->propType() == qMetaTypeId<QJSValue>()) {
PROPERTY_STORE(QJSValue, QJSValue(scope.engine, value.asReturnedValue()));
- } else if (value.isUndefined() && property->propType != qMetaTypeId<QQmlScriptString>()) {
+ } else if (value.isUndefined() && property->propType() != qMetaTypeId<QQmlScriptString>()) {
QString error = QLatin1String("Cannot assign [undefined] to ");
- if (!QMetaType::typeName(property->propType))
+ if (!QMetaType::typeName(property->propType()))
error += QLatin1String("[unknown property type]");
else
- error += QLatin1String(QMetaType::typeName(property->propType));
+ error += QLatin1String(QMetaType::typeName(property->propType()));
scope.engine->throwError(error);
return;
} else if (value.as<FunctionObject>()) {
// this is handled by the binding creation above
- } else if (property->propType == QMetaType::Int && value.isNumber()) {
+ } else if (property->propType() == QMetaType::Int && value.isNumber()) {
PROPERTY_STORE(int, value.asDouble());
- } else if (property->propType == QMetaType::QReal && value.isNumber()) {
+ } else if (property->propType() == QMetaType::QReal && value.isNumber()) {
PROPERTY_STORE(qreal, qreal(value.asDouble()));
- } else if (property->propType == QMetaType::Float && value.isNumber()) {
+ } else if (property->propType() == QMetaType::Float && value.isNumber()) {
PROPERTY_STORE(float, float(value.asDouble()));
- } else if (property->propType == QMetaType::Double && value.isNumber()) {
+ } else if (property->propType() == QMetaType::Double && value.isNumber()) {
PROPERTY_STORE(double, double(value.asDouble()));
- } else if (property->propType == QMetaType::QString && value.isString()) {
+ } else if (property->propType() == QMetaType::QString && value.isString()) {
PROPERTY_STORE(QString, value.toQStringNoThrow());
} else if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
- vmemo->setVMEProperty(property->coreIndex, value);
- } else if (property->propType == qMetaTypeId<QQmlScriptString>() && (value.isUndefined() || value.isPrimitive())) {
+ vmemo->setVMEProperty(property->coreIndex(), value);
+ } else if (property->propType() == qMetaTypeId<QQmlScriptString>() && (value.isUndefined() || value.isPrimitive())) {
QQmlScriptString ss(value.toQStringNoThrow(), 0 /* context */, object);
if (value.isNumber()) {
ss.d->numberValue = value.toNumber();
@@ -539,7 +474,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
if (property->isQList())
v = scope.engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
else
- v = scope.engine->toVariant(value, property->propType);
+ v = scope.engine->toVariant(value, property->propType());
QQmlContextData *callingQmlContext = scope.engine->callingQmlContext();
if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
@@ -547,7 +482,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
if (v.userType() == QVariant::Invalid) valueType = "null";
else valueType = QMetaType::typeName(v.userType());
- const char *targetTypeName = QMetaType::typeName(property->propType);
+ const char *targetTypeName = QMetaType::typeName(property->propType());
if (!targetTypeName)
targetTypeName = "an unregistered type";
@@ -642,11 +577,14 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value)
{
- setProperty(engine, d()->object, propertyIndex, value);
+ setProperty(engine, d()->object(), propertyIndex, value);
}
void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value)
{
+ Q_ASSERT(propertyIndex < 0xffff);
+ Q_ASSERT(propertyIndex >= 0);
+
if (QQmlData::wasDeleted(object))
return;
QQmlData *ddata = QQmlData::get(object, /*create*/false);
@@ -692,12 +630,12 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value)
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = that->engine();
- if (v4->hasException || QQmlData::wasDeleted(that->d()->object))
+ if (v4->hasException || QQmlData::wasDeleted(that->d()->object()))
return;
QQmlContextData *qmlContext = v4->callingQmlContext();
- if (!setQmlProperty(v4, qmlContext, that->d()->object, name, QV4::QObjectWrapper::IgnoreRevision, value)) {
- QQmlData *ddata = QQmlData::get(that->d()->object);
+ if (!setQmlProperty(v4, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) {
+ QQmlData *ddata = QQmlData::get(that->d()->object());
// Types created by QML are not extensible at run-time, but for other QObjects we can store them
// as regular JavaScript properties, like on JavaScript objects.
if (ddata && ddata->context) {
@@ -735,8 +673,8 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
- if (that->d()->object) {
- const QMetaObject *mo = that->d()->object->metaObject();
+ if (that->d()->object()) {
+ const QMetaObject *mo = that->d()->object()->metaObject();
// These indices don't apply to gadgets, so don't block them.
const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject;
const int propertyCount = mo->propertyCount();
@@ -796,8 +734,8 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
if (!v4)
break;
- QVarLengthArray<int, 9> dummy;
- int *argsTypes = QQmlMetaObject(r).methodParameterTypes(This->signalIndex, dummy, 0);
+ QQmlMetaObject::ArgTypeStorage storage;
+ int *argsTypes = QQmlMetaObject(r).methodParameterTypes(This->signalIndex, &storage, 0);
int argCount = argsTypes ? argsTypes[0]:0;
@@ -815,7 +753,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
}
}
- f->call(callData);
+ f->call(scope, callData);
if (scope.hasException()) {
QQmlError error = v4->catchExceptionAsQmlError();
if (error.description().isEmpty()) {
@@ -1006,7 +944,7 @@ void QObjectWrapper::markObjects(Heap::Base *that, QV4::ExecutionEngine *e)
{
QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that);
- if (QObject *o = This->object.data()) {
+ if (QObject *o = This->object()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
if (vme)
vme->mark(e);
@@ -1028,18 +966,18 @@ void QObjectWrapper::destroyObject(bool lastCall)
if (!h->internalClass)
return; // destroyObject already got called
- if (h->object) {
- QQmlData *ddata = QQmlData::get(h->object, false);
+ if (h->object()) {
+ QQmlData *ddata = QQmlData::get(h->object(), false);
if (ddata) {
- if (!h->object->parent() && !ddata->indestructible) {
+ if (!h->object()->parent() && !ddata->indestructible) {
if (ddata && ddata->ownContext && ddata->context)
ddata->context->emitDestruction();
// This object is notionally destroyed now
ddata->isQueuedForDeletion = true;
if (lastCall)
- delete h->object;
+ delete h->object();
else
- h->object->deleteLater();
+ h->object()->deleteLater();
}
}
}
@@ -1114,7 +1052,8 @@ private:
}
static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index, int returnType, int argCount,
- int *argTypes, QV4::ExecutionEngine *engine, QV4::CallData *callArgs)
+ int *argTypes, QV4::ExecutionEngine *engine, QV4::CallData *callArgs,
+ QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
{
if (argCount > 0) {
// Convert all arguments.
@@ -1126,7 +1065,7 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
for (int ii = 0; ii < args.count(); ++ii)
argData[ii] = args[ii].dataPtr();
- object.metacall(QMetaObject::InvokeMetaMethod, index, argData.data());
+ object.metacall(callType, index, argData.data());
return args[0].toValue(engine);
@@ -1137,14 +1076,14 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
void *args[] = { arg.dataPtr() };
- object.metacall(QMetaObject::InvokeMetaMethod, index, args);
+ object.metacall(callType, index, args);
return arg.toValue(engine);
} else {
void *args[] = { 0 };
- object.metacall(QMetaObject::InvokeMetaMethod, index, args);
+ object.metacall(callType, index, args);
return Encode::undefined();
}
@@ -1245,6 +1184,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
}
} else if (actual.isNull()) {
switch (conversionType) {
+ case QMetaType::Nullptr:
case QMetaType::VoidStar:
case QMetaType::QObjectStar:
case QMetaType::QJsonValue:
@@ -1317,34 +1257,34 @@ static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object,
if (!current->isOverload())
return 0;
- Q_ASSERT(!current->overrideIndexIsProperty);
+ Q_ASSERT(!current->overrideIndexIsProperty());
if (propertyCache) {
- return propertyCache->method(current->overrideIndex);
+ return propertyCache->method(current->overrideIndex());
} else {
const QMetaObject *mo = object.metaObject();
int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
- while (methodOffset > current->overrideIndex) {
+ while (methodOffset > current->overrideIndex()) {
mo = mo->superClass();
methodOffset -= QMetaObject_methods(mo);
}
// If we've been called before with the same override index, then
// we can't go any further...
- if (&dummy == current && dummy.coreIndex == current->overrideIndex)
+ if (&dummy == current && dummy.coreIndex() == current->overrideIndex())
return 0;
- QMetaMethod method = mo->method(current->overrideIndex);
+ QMetaMethod method = mo->method(current->overrideIndex());
dummy.load(method);
// Look for overloaded methods
QByteArray methodName = method.name();
- for (int ii = current->overrideIndex - 1; ii >= methodOffset; --ii) {
+ for (int ii = current->overrideIndex() - 1; ii >= methodOffset; --ii) {
if (methodName == mo->method(ii).name()) {
- dummy.setFlags(dummy.getFlags() | QQmlPropertyData::IsOverload);
- dummy.overrideIndexIsProperty = 0;
- dummy.overrideIndex = ii;
+ dummy.setOverload(true);
+ dummy.setOverrideIndexIsProperty(0);
+ dummy.setOverrideIndex(ii);
return &dummy;
}
}
@@ -1354,29 +1294,32 @@ static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object,
}
static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
- QV4::ExecutionEngine *engine, QV4::CallData *callArgs)
+ QV4::ExecutionEngine *engine, QV4::CallData *callArgs,
+ QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
{
QByteArray unknownTypeError;
int returnType = object.methodReturnType(data, &unknownTypeError);
if (returnType == QMetaType::UnknownType) {
- QString typeName = QString::fromLatin1(unknownTypeError);
- QString error = QStringLiteral("Unknown method return type: %1").arg(typeName);
- return engine->throwError(error);
+ return engine->throwError(QLatin1String("Unknown method return type: ")
+ + QLatin1String(unknownTypeError));
}
if (data.hasArguments()) {
int *args = 0;
- QVarLengthArray<int, 9> dummy;
+ QQmlMetaObject::ArgTypeStorage storage;
- args = object.methodParameterTypes(data.coreIndex, dummy, &unknownTypeError);
+ if (data.isConstructor())
+ args = static_cast<const QQmlStaticMetaObject&>(object).constructorParameterTypes(
+ data.coreIndex(), &storage, &unknownTypeError);
+ else
+ args = object.methodParameterTypes(data.coreIndex(), &storage, &unknownTypeError);
if (!args) {
- QString typeName = QString::fromLatin1(unknownTypeError);
- QString error = QStringLiteral("Unknown method parameter type: %1").arg(typeName);
- return engine->throwError(error);
+ return engine->throwError(QLatin1String("Unknown method parameter type: ")
+ + QLatin1String(unknownTypeError));
}
if (args[0] > callArgs->argc) {
@@ -1384,11 +1327,11 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ
return engine->throwError(error);
}
- return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs);
+ return CallMethod(object, data.coreIndex(), returnType, args[0], args + 1, engine, callArgs, callType);
} else {
- return CallMethod(object, data.coreIndex, returnType, 0, 0, engine, callArgs);
+ return CallMethod(object, data.coreIndex(), returnType, 0, 0, engine, callArgs, callType);
}
}
@@ -1407,7 +1350,8 @@ Resolve the overloaded method to call. The algorithm works conceptually like th
score is constructed by adding the matchScore() result for each of the parameters.
*/
static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
- QV4::ExecutionEngine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache)
+ QV4::ExecutionEngine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache,
+ QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
{
int argumentCount = callArgs->argc;
@@ -1422,11 +1366,11 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const
QV4::ScopedValue v(scope);
do {
- QVarLengthArray<int, 9> dummy;
+ QQmlMetaObject::ArgTypeStorage storage;
int methodArgumentCount = 0;
int *methodArgTypes = 0;
if (attempt->hasArguments()) {
- int *args = object.methodParameterTypes(attempt->coreIndex, dummy, 0);
+ int *args = object.methodParameterTypes(attempt->coreIndex(), &storage, 0);
if (!args) // Must be an unknown argument
continue;
@@ -1457,13 +1401,13 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const
} while ((attempt = RelatedMethod(object, attempt, dummy, propertyCache)) != 0);
if (best.isValid()) {
- return CallPrecise(object, best, engine, callArgs);
+ return CallPrecise(object, best, engine, callArgs, callType);
} else {
QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
const QQmlPropertyData *candidate = &data;
while (candidate) {
error += QLatin1String("\n ") +
- QString::fromUtf8(object.metaObject()->method(candidate->coreIndex)
+ QString::fromUtf8(object.metaObject()->method(candidate->coreIndex())
.methodSignature());
candidate = RelatedMethod(object, candidate, dummy, propertyCache);
}
@@ -1731,7 +1675,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in
{
Scope valueScope(scope);
Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope));
- method->d()->object = object;
+ method->d()->setObject(object);
if (QQmlData *ddata = QQmlData::get(object))
method->d()->propertyCache = ddata->propertyCache;
@@ -1743,7 +1687,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in
ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index)
{
Scope valueScope(scope);
- Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope));
+ Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope));
method->d()->propertyCache = valueType->d()->propertyCache;
method->d()->index = index;
method->d()->valueTypeWrapper = valueType->d();
@@ -1759,7 +1703,7 @@ const QMetaObject *Heap::QObjectMethod::metaObject()
{
if (propertyCache)
return propertyCache->createMetaObject();
- return object->metaObject();
+ return object()->metaObject();
}
QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) const
@@ -1768,10 +1712,10 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co
if (const QMetaObject *metaObject = d()->metaObject()) {
result += QString::fromUtf8(metaObject->className()) +
- QLatin1String("(0x") + QString::number((quintptr)d()->object.data(),16);
+ QLatin1String("(0x") + QString::number((quintptr)d()->object(),16);
- if (d()->object) {
- QString objectName = d()->object->objectName();
+ if (d()->object()) {
+ QString objectName = d()->object()->objectName();
if (!objectName.isEmpty())
result += QLatin1String(", \"") + objectName + QLatin1Char('\"');
}
@@ -1786,9 +1730,9 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co
QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const
{
- if (!d()->object)
+ if (!d()->object())
return Encode::undefined();
- if (QQmlData::keepAliveDuringGarbageCollection(d()->object))
+ if (QQmlData::keepAliveDuringGarbageCollection(d()->object()))
return ctx->engine()->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
int delay = 0;
@@ -1796,32 +1740,39 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con
delay = args[0].toUInt32();
if (delay > 0)
- QTimer::singleShot(delay, d()->object, SLOT(deleteLater()));
+ QTimer::singleShot(delay, d()->object(), SLOT(deleteLater()));
else
- d()->object->deleteLater();
+ d()->object()->deleteLater();
return Encode::undefined();
}
-ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData)
+void QObjectMethod::call(const Managed *m, Scope &scope, CallData *callData)
{
const QObjectMethod *This = static_cast<const QObjectMethod*>(m);
- return This->callInternal(callData);
+ This->callInternal(callData, scope);
}
-ReturnedValue QObjectMethod::callInternal(CallData *callData) const
+void QObjectMethod::callInternal(CallData *callData, Scope &scope) const
{
ExecutionEngine *v4 = engine();
ExecutionContext *context = v4->currentContext;
- if (d()->index == DestroyMethod)
- return method_destroy(context, callData->args, callData->argc);
- else if (d()->index == ToStringMethod)
- return method_toString(context);
+ if (d()->index == DestroyMethod) {
+ scope.result = method_destroy(context, callData->args, callData->argc);
+ return;
+ }
+
+ else if (d()->index == ToStringMethod) {
+ scope.result = method_toString(context);
+ return;
+ }
- QQmlObjectOrGadget object(d()->object.data());
- if (!d()->object) {
- if (!d()->valueTypeWrapper)
- return Encode::undefined();
+ QQmlObjectOrGadget object(d()->object());
+ if (!d()->object()) {
+ if (!d()->valueTypeWrapper) {
+ scope.result = Encode::undefined();
+ return;
+ }
object = QQmlObjectOrGadget(d()->propertyCache.data(), d()->valueTypeWrapper->gadgetPtr);
}
@@ -1830,46 +1781,49 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const
if (d()->propertyCache) {
QQmlPropertyData *data = d()->propertyCache->method(d()->index);
- if (!data)
- return QV4::Encode::undefined();
+ if (!data) {
+ scope.result = QV4::Encode::undefined();
+ return;
+ }
method = *data;
} else {
- const QMetaObject *mo = d()->object->metaObject();
+ const QMetaObject *mo = d()->object()->metaObject();
const QMetaMethod moMethod = mo->method(d()->index);
method.load(moMethod);
- if (method.coreIndex == -1)
- return QV4::Encode::undefined();
+ if (method.coreIndex() == -1) {
+ scope.result = QV4::Encode::undefined();
+ return;
+ }
// Look for overloaded methods
QByteArray methodName = moMethod.name();
const int methodOffset = mo->methodOffset();
for (int ii = d()->index - 1; ii >= methodOffset; --ii) {
if (methodName == mo->method(ii).name()) {
- method.setFlags(method.getFlags() | QQmlPropertyData::IsOverload);
- method.overrideIndexIsProperty = 0;
- method.overrideIndex = ii;
+ method.setOverload(true);
+ method.setOverrideIndexIsProperty(0);
+ method.setOverrideIndex(ii);
break;
}
}
}
if (method.isV4Function()) {
- Scope scope(v4);
- QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue());
- QQmlV4Function func(callData, rv, v4);
+ scope.result = QV4::Encode::undefined();
+ QQmlV4Function func(callData, &scope.result, v4);
QQmlV4Function *funcptr = &func;
void *args[] = { 0, &funcptr };
- object.metacall(QMetaObject::InvokeMetaMethod, method.coreIndex, args);
+ object.metacall(QMetaObject::InvokeMetaMethod, method.coreIndex(), args);
- return rv->asReturnedValue();
+ return;
}
if (!method.isOverload()) {
- return CallPrecise(object, method, v4, callData);
+ scope.result = CallPrecise(object, method, v4, callData);
} else {
- return CallOverloaded(object, method, v4, callData, d()->propertyCache);
+ scope.result = CallOverloaded(object, method, v4, callData, d()->propertyCache);
}
}
@@ -1884,10 +1838,183 @@ void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e)
DEFINE_OBJECT_VTABLE(QObjectMethod);
+
+Heap::QMetaObjectWrapper::QMetaObjectWrapper(const QMetaObject *metaObject)
+ : metaObject(metaObject)
+ , constructors(nullptr)
+ , constructorCount(0)
+{}
+
+Heap::QMetaObjectWrapper::~QMetaObjectWrapper()
+{
+ delete[] constructors;
+}
+
+void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
+
+ const int count = metaObject->constructorCount();
+ if (constructorCount != count) {
+ delete[] constructors;
+ constructorCount = count;
+ if (count == 0) {
+ constructors = nullptr;
+ return;
+ }
+ constructors = new QQmlPropertyData[count];
+
+ for (int i = 0; i < count; ++i) {
+ QMetaMethod method = metaObject->constructor(i);
+ QQmlPropertyData &d = constructors[i];
+ d.load(method);
+ d.setCoreIndex(i);
+ }
+ }
+}
+
+
+ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
+
+ QV4::Scope scope(engine);
+ Scoped<QMetaObjectWrapper> mo(scope, engine->memoryManager->allocObject<QV4::QMetaObjectWrapper>(metaObject)->asReturnedValue());
+ mo->init(engine);
+ return mo->asReturnedValue();
+}
+
+void QMetaObjectWrapper::init(ExecutionEngine *) {
+ const QMetaObject & mo = *d()->metaObject;
+
+ for (int i = 0; i < mo.enumeratorCount(); i++) {
+ QMetaEnum Enum = mo.enumerator(i);
+ for (int k = 0; k < Enum.keyCount(); k++) {
+ const char* key = Enum.key(k);
+ const int value = Enum.value(k);
+ defineReadonlyProperty(QLatin1String(key), Primitive::fromInt32(value));
+ }
+ }
+}
+
+void QMetaObjectWrapper::construct(const Managed *m, Scope &scope, CallData *callData)
+{
+ const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(m);
+ scope.result = This->constructInternal(callData);
+}
+
+ReturnedValue QMetaObjectWrapper::constructInternal(CallData * callData) const {
+
+ d()->ensureConstructorsCache();
+
+ ExecutionEngine *v4 = engine();
+ const QMetaObject* mo = d()->metaObject;
+ if (d()->constructorCount == 0) {
+ return v4->throwTypeError(QLatin1String(mo->className())
+ + QLatin1String(" has no invokable constructor"));
+ }
+
+ Scope scope(v4);
+ Scoped<QObjectWrapper> object(scope);
+
+ if (d()->constructorCount == 1) {
+ object = callConstructor(d()->constructors[0], v4, callData);
+ }
+ else {
+ object = callOverloadedConstructor(v4, callData);
+ }
+ Scoped<QMetaObjectWrapper> metaObject(scope, this);
+ object->defineDefaultProperty(v4->id_constructor(), metaObject);
+ object->setPrototype(const_cast<QMetaObjectWrapper*>(this));
+ return object.asReturnedValue();
+
+}
+
+ReturnedValue QMetaObjectWrapper::callConstructor(const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const {
+
+ const QMetaObject* mo = d()->metaObject;
+ const QQmlStaticMetaObject object(mo);
+ return CallPrecise(object, data, engine, callArgs, QMetaObject::CreateInstance);
+}
+
+
+ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const {
+ const int numberOfConstructors = d()->constructorCount;
+ const int argumentCount = callArgs->argc;
+ const QQmlStaticMetaObject object(d()->metaObject);
+
+ QQmlPropertyData best;
+ int bestParameterScore = INT_MAX;
+ int bestMatchScore = INT_MAX;
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue v(scope);
+
+ for (int i = 0; i < numberOfConstructors; i++) {
+ const QQmlPropertyData & attempt = d()->constructors[i];
+ int methodArgumentCount = 0;
+ int *methodArgTypes = 0;
+ if (attempt.hasArguments()) {
+ QQmlMetaObject::ArgTypeStorage storage;
+ int *args = object.constructorParameterTypes(attempt.coreIndex(), &storage, 0);
+ if (!args) // Must be an unknown argument
+ continue;
+
+ methodArgumentCount = args[0];
+ methodArgTypes = args + 1;
+ }
+
+ if (methodArgumentCount > argumentCount)
+ continue; // We don't have sufficient arguments to call this method
+
+ int methodParameterScore = argumentCount - methodArgumentCount;
+ if (methodParameterScore > bestParameterScore)
+ continue; // We already have a better option
+
+ int methodMatchScore = 0;
+ for (int ii = 0; ii < methodArgumentCount; ++ii)
+ methodMatchScore += MatchScore((v = callArgs->args[ii]), methodArgTypes[ii]);
+
+ if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
+ best = attempt;
+ bestParameterScore = methodParameterScore;
+ bestMatchScore = methodMatchScore;
+ }
+
+ if (bestParameterScore == 0 && bestMatchScore == 0)
+ break; // We can't get better than that
+ };
+
+ if (best.isValid()) {
+ return CallPrecise(object, best, engine, callArgs, QMetaObject::CreateInstance);
+ } else {
+ QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
+ for (int i = 0; i < numberOfConstructors; i++) {
+ const QQmlPropertyData & candidate = d()->constructors[i];
+ error += QLatin1String("\n ") +
+ QString::fromUtf8(d()->metaObject->constructor(candidate.coreIndex())
+ .methodSignature());
+ }
+
+ return engine->throwError(error);
+ }
+}
+
+bool QMetaObjectWrapper::isEqualTo(Managed *a, Managed *b)
+{
+ Q_ASSERT(a->as<QMetaObjectWrapper>());
+ QMetaObjectWrapper *aMetaObject = a->as<QMetaObjectWrapper>();
+ QMetaObjectWrapper *bMetaObject = b->as<QMetaObjectWrapper>();
+ if (!bMetaObject)
+ return true;
+ return aMetaObject->metaObject() == bMetaObject->metaObject();
+}
+
+DEFINE_OBJECT_VTABLE(QMetaObjectWrapper);
+
+
+
+
Heap::QmlSignalHandler::QmlSignalHandler(QObject *object, int signalIndex)
- : object(object)
- , signalIndex(signalIndex)
+ : signalIndex(signalIndex)
{
+ setObject(object);
}
DEFINE_OBJECT_VTABLE(QmlSignalHandler);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index d53bb88d20..076f304fea 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -59,7 +59,6 @@
#include <private/qqmldata_p.h>
#include <private/qqmlpropertycache_p.h>
#include <private/qintrusivelist_p.h>
-#include <private/qqmlaccessors_p.h>
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
@@ -80,24 +79,50 @@ struct QQmlValueTypeWrapper;
struct QObjectWrapper : Object {
QObjectWrapper(QObject *object);
- QPointer<QObject> object;
+ ~QObjectWrapper() { qObj.destroy(); }
+
+ QObject *object() const { return qObj.data(); }
+
+private:
+ QQmlQPointer<QObject> qObj;
};
struct QObjectMethod : FunctionObject {
QObjectMethod(QV4::ExecutionContext *scope);
- QPointer<QObject> object;
+ ~QObjectMethod() { qObj.destroy(); }
QQmlRefPointer<QQmlPropertyCache> propertyCache;
int index;
Pointer<QQmlValueTypeWrapper> valueTypeWrapper;
const QMetaObject *metaObject();
+ QObject *object() const { return qObj.data(); }
+ void setObject(QObject *o) { qObj = o; }
+
+private:
+ QQmlQPointer<QObject> qObj;
+};
+
+struct QMetaObjectWrapper : FunctionObject {
+ const QMetaObject* metaObject;
+ QQmlPropertyData *constructors;
+ int constructorCount;
+
+ QMetaObjectWrapper(const QMetaObject* metaObject);
+ ~QMetaObjectWrapper();
+ void ensureConstructorsCache();
};
struct QmlSignalHandler : Object {
QmlSignalHandler(QObject *object, int signalIndex);
- QPointer<QObject> object;
+ ~QmlSignalHandler() { qObj.destroy(); }
int signalIndex;
+
+ QObject *object() const { return qObj.data(); }
+ void setObject(QObject *o) { qObj = o; }
+
+private:
+ QQmlQPointer<QObject> qObj;
};
}
@@ -110,7 +135,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
static void initializeBindings(ExecutionEngine *engine);
- QObject *object() const { return d()->object.data(); }
+ QObject *object() const { return d()->object(); }
ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false) const;
static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0);
@@ -180,28 +205,48 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
static ReturnedValue create(QV4::ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index);
int methodIndex() const { return d()->index; }
- QObject *object() const { return d()->object.data(); }
+ QObject *object() const { return d()->object(); }
QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx) const;
QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const;
- static ReturnedValue call(const Managed *, CallData *callData);
+ static void call(const Managed *, Scope &scope, CallData *callData);
- ReturnedValue callInternal(CallData *callData) const;
+ void callInternal(CallData *callData, Scope &scope) const;
static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
};
-struct QmlSignalHandler : public QV4::Object
+
+struct Q_QML_EXPORT QMetaObjectWrapper : public QV4::FunctionObject
+{
+ V4_OBJECT2(QMetaObjectWrapper, QV4::FunctionObject)
+ V4_NEEDS_DESTROY
+
+ static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
+ static void construct(const Managed *, Scope &scope, CallData *callData);
+ static bool isEqualTo(Managed *a, Managed *b);
+
+ const QMetaObject *metaObject() const { return d()->metaObject; }
+
+private:
+ void init(ExecutionEngine *engine);
+ ReturnedValue constructInternal(CallData *callData) const;
+ ReturnedValue callConstructor(const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
+ ReturnedValue callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
+
+};
+
+struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
{
V4_OBJECT2(QmlSignalHandler, QV4::Object)
V4_PROTOTYPE(signalHandlerPrototype)
V4_NEEDS_DESTROY
int signalIndex() const { return d()->signalIndex; }
- QObject *object() const { return d()->object.data(); }
+ QObject *object() const { return d()->object(); }
static void initProto(ExecutionEngine *v4);
};
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index af5355c964..6d6d446ca2 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -95,6 +95,8 @@ Heap::RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignor
, ignoreCase(ignoreCase)
, multiLine(multiline)
{
+ Base::init();
+
const char* error = 0;
JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiline, &error);
if (error)
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 05752dc6dc..203def0bcf 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -79,9 +79,9 @@ Heap::RegExpObject::RegExpObject()
}
Heap::RegExpObject::RegExpObject(QV4::RegExp *value, bool global)
- : value(value->d())
- , global(global)
+ : global(global)
{
+ this->value = value->d();
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
o->initProperties();
@@ -231,34 +231,39 @@ void Heap::RegExpCtor::clearLastMatch()
lastMatchEnd = 0;
}
-ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData)
+void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const Object *>(m)->engine());
-
ScopedValue r(scope, callData->argument(0));
ScopedValue f(scope, callData->argument(1));
Scoped<RegExpObject> re(scope, r);
if (re) {
- if (!f->isUndefined())
- return scope.engine->throwTypeError();
+ if (!f->isUndefined()) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
Scoped<RegExp> regexp(scope, re->value());
- return Encode(scope.engine->newRegExpObject(regexp, re->global()));
+ scope.result = Encode(scope.engine->newRegExpObject(regexp, re->global()));
+ return;
}
QString pattern;
if (!r->isUndefined())
pattern = r->toQString();
- if (scope.hasException())
- return Encode::undefined();
+ if (scope.hasException()) {
+ scope.result = Encode::undefined();
+ return;
+ }
bool global = false;
bool ignoreCase = false;
bool multiLine = false;
if (!f->isUndefined()) {
f = RuntimeHelpers::toString(scope.engine, f);
- if (scope.hasException())
- return Encode::undefined();
+ if (scope.hasException()) {
+ scope.result = Encode::undefined();
+ return;
+ }
QString str = f->stringValue()->toQString();
for (int i = 0; i < str.length(); ++i) {
if (str.at(i) == QLatin1Char('g') && !global) {
@@ -268,26 +273,31 @@ ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData)
} else if (str.at(i) == QLatin1Char('m') && !multiLine) {
multiLine = true;
} else {
- return scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor"));
+ scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor"));
+ return;
}
}
}
Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine));
- if (!regexp->isValid())
- return scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression"));
+ if (!regexp->isValid()) {
+ scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression"));
+ return;
+ }
- return Encode(scope.engine->newRegExpObject(regexp, global));
+ scope.result = Encode(scope.engine->newRegExpObject(regexp, global));
}
-ReturnedValue RegExpCtor::call(const Managed *that, CallData *callData)
+void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
if (callData->argc > 0 && callData->args[0].as<RegExpObject>()) {
- if (callData->argc == 1 || callData->args[1].isUndefined())
- return callData->args[0].asReturnedValue();
+ if (callData->argc == 1 || callData->args[1].isUndefined()) {
+ scope.result = callData->args[0];
+ return;
+ }
}
- return construct(that, callData);
+ construct(that, scope, callData);
}
void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e)
@@ -419,7 +429,8 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx)
ScopedCallData callData(scope, ctx->argc());
memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value));
- Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(callData));
+ ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(scope, callData);
+ Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
r->d()->value = re->value();
r->d()->global = re->global();
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 4bd91bbedd..655e120c16 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -140,8 +140,8 @@ struct RegExpCtor: FunctionObject
int lastMatchStart() { return d()->lastMatchStart; }
int lastMatchEnd() { return d()->lastMatchEnd; }
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 8f377dd664..5460304e7b 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -176,7 +176,7 @@ struct RuntimeCounters::Data {
}
std::sort(lines.begin(), lines.end(), Line::less);
outs << lines.size() << " counters:" << endl;
- foreach (const Line &line, lines)
+ for (const Line &line : qAsConst(lines))
outs << qSetFieldWidth(10) << line.count << qSetFieldWidth(0)
<< " | " << line.func
<< " | " << pretty(line.tag1)
@@ -252,14 +252,14 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
result->append(QLatin1Char('+'));
result->append(QString::number(decpt - 1));
} else if (decpt <= 0) {
- result->prepend(QString::fromLatin1("0.%1").arg(QString().fill(zero, -decpt)));
+ result->prepend(QLatin1String("0.") + QString(-decpt, zero));
} else if (decpt < result->length()) {
result->insert(decpt, dot);
} else {
- result->append(QString().fill(zero, decpt - result->length()));
+ result->append(QString(decpt - result->length(), zero));
}
- if (sign)
+ if (sign && num)
result->prepend(QLatin1Char('-'));
return;
@@ -387,7 +387,7 @@ QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left
double RuntimeHelpers::stringToNumber(const QString &string)
{
- QString s = string.trimmed();
+ const QStringRef s = QStringRef(&string).trimmed();
if (s.startsWith(QLatin1String("0x")) || s.startsWith(QLatin1String("0X")))
return s.toLong(0, 16);
bool ok;
@@ -438,9 +438,9 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH
ScopedValue conv(scope, object->get(meth1));
if (FunctionObject *o = conv->as<FunctionObject>()) {
- ScopedValue r(scope, o->call(callData));
- if (r->isPrimitive())
- return r->asReturnedValue();
+ o->call(scope, callData);
+ if (scope.result.isPrimitive())
+ return scope.result.asReturnedValue();
}
if (engine->hasException)
@@ -448,9 +448,9 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH
conv = object->get(meth2);
if (FunctionObject *o = conv->as<FunctionObject>()) {
- ScopedValue r(scope, o->call(callData));
- if (r->isPrimitive())
- return r->asReturnedValue();
+ o->call(scope, callData);
+ if (scope.result.isPrimitive())
+ return scope.result.asReturnedValue();
}
return engine->throwTypeError();
@@ -555,7 +555,7 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu
if (!pright->stringValue()->d()->length())
return pleft->asReturnedValue();
MemoryManager *mm = engine->memoryManager;
- return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue();
+ return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d(), true))->asReturnedValue();
}
double x = RuntimeHelpers::toNumber(pleft);
double y = RuntimeHelpers::toNumber(pright);
@@ -572,7 +572,7 @@ QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Valu
if (!right.stringValue()->d()->length())
return left.asReturnedValue();
MemoryManager *mm = engine->memoryManager;
- return (mm->alloc<String>(mm, left.stringValue()->d(), right.stringValue()->d()))->asReturnedValue();
+ return (mm->alloc<String>(mm, left.stringValue()->d(), right.stringValue()->d(), true))->asReturnedValue();
}
Scope scope(engine);
@@ -590,7 +590,7 @@ QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Valu
if (!pright->stringValue()->d()->length())
return pleft->asReturnedValue();
MemoryManager *mm = engine->memoryManager;
- return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue();
+ return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d(), true))->asReturnedValue();
}
void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
@@ -943,10 +943,13 @@ ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint ind
return engine->throwTypeError();
ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
- if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval()))
- return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true);
+ if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) {
+ static_cast<EvalFunction *>(o.getPointer())->evalCall(scope, callData, true);
+ } else {
+ o->call(scope, callData);
+ }
- return o->call(callData);
+ return scope.result.asReturnedValue();
}
@@ -974,33 +977,38 @@ ReturnedValue Runtime::method_callActivationProperty(ExecutionEngine *engine, in
}
if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) {
- return static_cast<EvalFunction *>(o)->evalCall(callData, true);
+ static_cast<EvalFunction *>(o)->evalCall(scope, callData, true);
+ } else {
+ o->call(scope, callData);
}
- return o->call(callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData)
{
Scope scope(engine);
- ScopedFunctionObject o(scope, method_getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex));
+ ScopedFunctionObject o(scope, method_getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex, /*captureRequired*/true));
if (!o) {
QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex);
return engine->throwTypeError(error);
}
- return o->call(callData);
+
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData)
{
Scope scope(engine);
- ScopedFunctionObject o(scope, method_getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex));
+ ScopedFunctionObject o(scope, method_getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex, /*captureRequired*/true));
if (!o) {
QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex);
return engine->throwTypeError(error);
}
- return o->call(callData);
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
@@ -1022,12 +1030,14 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, int nameInde
}
ScopedFunctionObject o(scope, baseObject->get(name));
- if (!o) {
+ if (o) {
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString(), callData->thisObject.toQStringNoThrow());
return engine->throwTypeError(error);
}
- return o->call(callData);
}
ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData)
@@ -1035,10 +1045,13 @@ ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, uint i
Lookup *l = engine->current->lookups + index;
Value v;
v = l->getter(l, engine, callData->thisObject);
- if (!v.isObject())
+ if (v.isObject()) {
+ Scope scope(engine);
+ v.objectValue()->call(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
return engine->throwTypeError();
-
- return v.objectValue()->call(callData);
+ }
}
ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value &index, CallData *callData)
@@ -1055,7 +1068,8 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value &
if (!o)
return engine->throwTypeError();
- return o->call(callData);
+ o->call(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, CallData *callData)
@@ -1063,7 +1077,9 @@ ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &fu
if (!func.isObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
- return func.objectValue()->call(callData);
+ Scope scope(engine);
+ func.objectValue()->call(scope, callData);
+ return scope.result.asReturnedValue();
}
@@ -1074,10 +1090,12 @@ ReturnedValue Runtime::method_constructGlobalLookup(ExecutionEngine *engine, uin
Lookup *l = engine->current->lookups + index;
ScopedObject f(scope, l->globalGetter(l, engine));
- if (!f)
+ if (f) {
+ f->construct(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
return engine->throwTypeError();
-
- return f->construct(callData);
+ }
}
@@ -1093,7 +1111,8 @@ ReturnedValue Runtime::method_constructActivationProperty(ExecutionEngine *engin
if (!f)
return engine->throwTypeError();
- return f->construct(callData);
+ f->construct(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue Runtime::method_constructValue(ExecutionEngine *engine, const Value &func, CallData *callData)
@@ -1102,7 +1121,9 @@ ReturnedValue Runtime::method_constructValue(ExecutionEngine *engine, const Valu
if (!f)
return engine->throwTypeError();
- return f->construct(callData);
+ Scope scope(engine);
+ f->construct(scope, callData);
+ return scope.result.asReturnedValue();
}
ReturnedValue Runtime::method_constructProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
@@ -1114,10 +1135,13 @@ ReturnedValue Runtime::method_constructProperty(ExecutionEngine *engine, int nam
return Encode::undefined();
ScopedObject f(scope, thisObject->get(name));
- if (!f)
+ if (f) {
+ Scope scope(engine);
+ f->construct(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
return engine->throwTypeError();
-
- return f->construct(callData);
+ }
}
ReturnedValue Runtime::method_constructPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData)
@@ -1125,10 +1149,14 @@ ReturnedValue Runtime::method_constructPropertyLookup(ExecutionEngine *engine, u
Lookup *l = engine->current->lookups + index;
Value v;
v = l->getter(l, engine, callData->thisObject);
- if (!v.isObject())
+ if (v.isObject()) {
+ Scope scope(engine);
+ ScopedValue result(scope);
+ v.objectValue()->construct(scope, callData);
+ return scope.result.asReturnedValue();
+ } else {
return engine->throwTypeError();
-
- return v.objectValue()->construct(callData);
+ }
}
@@ -1181,7 +1209,7 @@ QV4::ReturnedValue Runtime::method_typeofName(ExecutionEngine *engine, int nameI
ReturnedValue Runtime::method_typeofScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
{
Scope scope(engine);
- ScopedValue prop(scope, method_getQmlScopeObjectProperty(engine, context, propertyIndex));
+ ScopedValue prop(scope, method_getQmlScopeObjectProperty(engine, context, propertyIndex, /*captureRequired*/true));
if (scope.engine->hasException)
return Encode::undefined();
return method_typeofValue(engine, prop);
@@ -1190,7 +1218,7 @@ ReturnedValue Runtime::method_typeofScopeObjectProperty(ExecutionEngine *engine,
ReturnedValue Runtime::method_typeofContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
{
Scope scope(engine);
- ScopedValue prop(scope, method_getQmlContextObjectProperty(engine, context, propertyIndex));
+ ScopedValue prop(scope, method_getQmlContextObjectProperty(engine, context, propertyIndex, /*captureRequired*/true));
if (scope.engine->hasException)
return Encode::undefined();
return method_typeofValue(engine, prop);
@@ -1234,19 +1262,19 @@ ReturnedValue Runtime::method_unwindException(ExecutionEngine *engine)
void Runtime::method_pushWithScope(const Value &o, ExecutionEngine *engine)
{
engine->pushContext(engine->currentContext->newWithContext(o.toObject(engine)));
- Q_ASSERT(engine->jsStackTop = engine->currentContext + 2);
+ Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
}
void Runtime::method_pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex)
{
ExecutionContext *c = engine->currentContext;
engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0)));
- Q_ASSERT(engine->jsStackTop = engine->currentContext + 2);
+ Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
}
void Runtime::method_popScope(ExecutionEngine *engine)
{
- Q_ASSERT(engine->jsStackTop = engine->currentContext + 2);
+ Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
engine->popContext();
engine->jsStackTop -= 2;
}
@@ -1415,116 +1443,6 @@ ReturnedValue Runtime::method_getQmlQObjectProperty(ExecutionEngine *engine, con
return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->object(), propertyIndex, captureRequired);
}
-template <typename PropertyType>
-static inline PropertyType getQObjectProperty(QObject *object, ExecutionEngine *engine, QQmlAccessors *accessors, int coreIndex, int notifyIndex)
-{
- PropertyType t;
- accessors->read(object, &t);
- if (notifyIndex != -1) {
- QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
- if (ep && ep->propertyCapture) {
- if (accessors->notifier) {
- QQmlNotifier *n = nullptr;
- accessors->notifier(object, &n);
- if (n) {
- ep->propertyCapture->captureProperty(n);
- }
- } else {
- ep->propertyCapture->captureProperty(object, coreIndex, notifyIndex);
- }
- }
- }
-
- return t;
-}
-
-ReturnedValue Runtime::method_accessQObjectQRealProperty(ExecutionEngine *engine,
- const Value &object,
- QQmlAccessors *accessors, int coreIndex,
- int notifyIndex)
-{
- auto casted = object.as<QObjectWrapper>();
- QObject *o = casted ? casted->object() : nullptr;
- if (Q_LIKELY(o)) {
- return QV4::Encode(getQObjectProperty<qreal>(o, engine, accessors, coreIndex, notifyIndex));
- }
- engine->throwTypeError(QStringLiteral("Cannot read property of null"));
- return Encode::undefined();
-}
-
-ReturnedValue Runtime::method_accessQObjectQObjectProperty(ExecutionEngine *engine,
- const Value &object,
- QQmlAccessors *accessors, int coreIndex,
- int notifyIndex)
-{
- auto casted = object.as<QObjectWrapper>();
- QObject *o = casted ? casted->object() : nullptr;
- if (Q_LIKELY(o)) {
- return QV4::QObjectWrapper::wrap(engine, getQObjectProperty<QObject *>(o, engine, accessors,
- coreIndex,
- notifyIndex));
- }
-
- engine->throwTypeError(QStringLiteral("Cannot read property of null"));
- return Encode::undefined();
-}
-
-ReturnedValue Runtime::method_accessQObjectIntProperty(ExecutionEngine *engine, const Value &object,
- QQmlAccessors *accessors, int coreIndex,
- int notifyIndex)
-{
- auto casted = object.as<QObjectWrapper>();
- QObject *o = casted ? casted->object() : nullptr;
- if (Q_LIKELY(o)) {
- return QV4::Encode(getQObjectProperty<int>(o, engine, accessors, coreIndex, notifyIndex));
- }
- engine->throwTypeError(QStringLiteral("Cannot read property of null"));
- return Encode::undefined();
-}
-
-ReturnedValue Runtime::method_accessQObjectBoolProperty(ExecutionEngine *engine, const Value &object,
- QQmlAccessors *accessors, int coreIndex,
- int notifyIndex)
-{
- auto casted = object.as<QObjectWrapper>();
- QObject *o = casted ? casted->object() : nullptr;
- if (Q_LIKELY(o)) {
- return QV4::Encode(getQObjectProperty<bool>(o, engine, accessors, coreIndex, notifyIndex));
- }
- engine->throwTypeError(QStringLiteral("Cannot read property of null"));
- return Encode::undefined();
-}
-
-ReturnedValue Runtime::method_accessQObjectQStringProperty(ExecutionEngine *engine,
- const Value &object,
- QQmlAccessors *accessors, int coreIndex,
- int notifyIndex)
-{
- auto casted = object.as<QObjectWrapper>();
- QObject *o = casted ? casted->object() : nullptr;
- if (Q_LIKELY(o)) {
- return QV4::Encode(engine->newString(getQObjectProperty<QString>(o, engine, accessors,
- coreIndex, notifyIndex)));
- }
- engine->throwTypeError(QStringLiteral("Cannot read property of null"));
- return Encode::undefined();
-}
-
-ReturnedValue Runtime::method_accessQmlScopeObjectQObjectProperty(const Value &context,
- QQmlAccessors *accessors)
-{
-#ifndef V4_BOOTSTRAP
- const QmlContext &c = static_cast<const QmlContext &>(context);
- QObject *rv = 0;
- accessors->read(c.d()->qml->scopeObject, &rv);
- return QV4::QObjectWrapper::wrap(c.engine(), rv);
-#else
- Q_UNUSED(context);
- Q_UNUSED(accessors);
- return QV4::Encode::undefined();
-#endif
-}
-
QV4::ReturnedValue Runtime::method_getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)
{
QObject *scopeObject = engine->qmlScopeObject();
@@ -1535,16 +1453,16 @@ QV4::ReturnedValue Runtime::method_getQmlAttachedProperty(ExecutionEngine *engin
return QV4::QObjectWrapper::getProperty(engine, attachedObject, propertyIndex, /*captureRequired*/true);
}
-ReturnedValue Runtime::method_getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
+ReturnedValue Runtime::method_getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->scopeObject, propertyIndex, false);
+ return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->scopeObject, propertyIndex, captureRequired);
}
-ReturnedValue Runtime::method_getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
+ReturnedValue Runtime::method_getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->context->contextObject, propertyIndex, false);
+ return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->context->contextObject, propertyIndex, captureRequired);
}
ReturnedValue Runtime::method_getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
@@ -1798,6 +1716,8 @@ ReturnedValue Runtime::method_ushr(const Value &left, const Value &right)
return Encode(res);
}
+#endif // V4_BOOTSTRAP
+
ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -1906,70 +1826,6 @@ Bool Runtime::method_toBoolean(const Value &value)
return value.toBoolean();
}
-ReturnedValue Runtime::method_accessQmlScopeObjectQRealProperty(const Value &context,
- QQmlAccessors *accessors)
-{
-#ifndef V4_BOOTSTRAP
- const QmlContext &c = static_cast<const QmlContext &>(context);
- qreal rv = 0;
- accessors->read(c.d()->qml->scopeObject, &rv);
- return QV4::Encode(rv);
-#else
- Q_UNUSED(context);
- Q_UNUSED(accessors);
- return QV4::Encode::undefined();
-#endif
-}
-
-ReturnedValue Runtime::method_accessQmlScopeObjectIntProperty(const Value &context,
- QQmlAccessors *accessors)
-{
-#ifndef V4_BOOTSTRAP
- const QmlContext &c = static_cast<const QmlContext &>(context);
- int rv = 0;
- accessors->read(c.d()->qml->scopeObject, &rv);
- return QV4::Encode(rv);
-#else
- Q_UNUSED(context);
- Q_UNUSED(accessors);
- return QV4::Encode::undefined();
-#endif
-}
-
-ReturnedValue Runtime::method_accessQmlScopeObjectBoolProperty(const Value &context,
- QQmlAccessors *accessors)
-{
-#ifndef V4_BOOTSTRAP
- const QmlContext &c = static_cast<const QmlContext &>(context);
- bool rv = false;
- accessors->read(c.d()->qml->scopeObject, &rv);
- return QV4::Encode(rv);
-#else
- Q_UNUSED(context);
- Q_UNUSED(accessors);
- return QV4::Encode::undefined();
-#endif
-}
-
-ReturnedValue Runtime::method_accessQmlScopeObjectQStringProperty(ExecutionEngine *engine,
- const Value &context,
- QQmlAccessors *accessors)
-{
-#ifndef V4_BOOTSTRAP
- const QmlContext &c = static_cast<const QmlContext &>(context);
- QString rv;
- accessors->read(c.d()->qml->scopeObject, &rv);
- return QV4::Encode(engine->newString(rv));
-#else
- Q_UNUSED(engine);
- Q_UNUSED(context);
- Q_UNUSED(accessors);
- return QV4::Encode::undefined();
-#endif
-}
-
-#endif // V4_BOOTSTRAP
-
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 975d100ef4..a32b3f1663 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -56,17 +56,10 @@
#include "qv4engine_p.h"
#include "qv4math_p.h"
#include "qv4runtimeapi_p.h"
-#ifndef V4_BOOTSTRAP
-#include <private/qqmlaccessors_p.h>
-#include <private/qqmlcontextwrapper_p.h>
-#endif
-
#include <QtCore/qnumeric.h>
QT_BEGIN_NAMESPACE
-class QQmlAccessors;
-
#undef QV4_COUNT_RUNTIME_FUNCTIONS
namespace QV4 {
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index ded2b541dc..040a545b83 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -58,8 +58,41 @@ namespace QV4 {
struct NoThrowEngine;
+namespace {
+template <typename T>
+struct ExceptionCheck {
+ enum { NeedsCheck = 1 };
+};
+// push_catch and pop context methods shouldn't check for exceptions
+template <>
+struct ExceptionCheck<void (*)(QV4::ExecutionEngine *)> {
+ enum { NeedsCheck = 0 };
+};
+template <typename A>
+struct ExceptionCheck<void (*)(A, QV4::NoThrowEngine)> {
+ enum { NeedsCheck = 0 };
+};
+template <>
+struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *)> {
+ enum { NeedsCheck = 0 };
+};
+template <typename A>
+struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A)> {
+ enum { NeedsCheck = 0 };
+};
+template <typename A, typename B>
+struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A, B)> {
+ enum { NeedsCheck = 0 };
+};
+template <typename A, typename B, typename C>
+struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
+ enum { NeedsCheck = 0 };
+};
+} // anonymous namespace
+
#define RUNTIME_METHOD(returnvalue, name, args) \
typedef returnvalue (*Method_##name)args; \
+ enum { Method_##name##_NeedsExceptionCheck = ExceptionCheck<Method_##name>::NeedsCheck }; \
static returnvalue method_##name args; \
const Method_##name name
@@ -167,16 +200,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
, INIT_RUNTIME_METHOD(setQmlScopeObjectProperty)
, INIT_RUNTIME_METHOD(setQmlContextObjectProperty)
, INIT_RUNTIME_METHOD(setQmlQObjectProperty)
- , INIT_RUNTIME_METHOD(accessQObjectQRealProperty)
- , INIT_RUNTIME_METHOD(accessQObjectQObjectProperty)
- , INIT_RUNTIME_METHOD(accessQObjectIntProperty)
- , INIT_RUNTIME_METHOD(accessQObjectBoolProperty)
- , INIT_RUNTIME_METHOD(accessQObjectQStringProperty)
- , INIT_RUNTIME_METHOD(accessQmlScopeObjectQRealProperty)
- , INIT_RUNTIME_METHOD(accessQmlScopeObjectQObjectProperty)
- , INIT_RUNTIME_METHOD(accessQmlScopeObjectIntProperty)
- , INIT_RUNTIME_METHOD(accessQmlScopeObjectBoolProperty)
- , INIT_RUNTIME_METHOD(accessQmlScopeObjectQStringProperty)
{ }
// call
@@ -304,8 +327,8 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
RUNTIME_METHOD(ReturnedValue, getQmlImportedScripts, (NoThrowEngine *engine));
RUNTIME_METHOD(ReturnedValue, getQmlSingleton, (NoThrowEngine *engine, int nameIndex));
RUNTIME_METHOD(ReturnedValue, getQmlAttachedProperty, (ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex));
- RUNTIME_METHOD(ReturnedValue, getQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex));
- RUNTIME_METHOD(ReturnedValue, getQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex));
+ RUNTIME_METHOD(ReturnedValue, getQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired));
+ RUNTIME_METHOD(ReturnedValue, getQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired));
RUNTIME_METHOD(ReturnedValue, getQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired));
RUNTIME_METHOD(ReturnedValue, getQmlSingletonQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired));
RUNTIME_METHOD(ReturnedValue, getQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index));
@@ -313,17 +336,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
RUNTIME_METHOD(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value));
RUNTIME_METHOD(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value));
RUNTIME_METHOD(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value));
-
- RUNTIME_METHOD(ReturnedValue, accessQObjectQRealProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
- RUNTIME_METHOD(ReturnedValue, accessQObjectQObjectProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
- RUNTIME_METHOD(ReturnedValue, accessQObjectIntProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
- RUNTIME_METHOD(ReturnedValue, accessQObjectBoolProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
- RUNTIME_METHOD(ReturnedValue, accessQObjectQStringProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
- RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQRealProperty, (const Value &context, QQmlAccessors *accessors));
- RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQObjectProperty, (const Value &context, QQmlAccessors *accessors));
- RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectIntProperty, (const Value &context, QQmlAccessors *accessors));
- RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectBoolProperty, (const Value &context, QQmlAccessors *accessors));
- RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQStringProperty, (ExecutionEngine *engine, const Value &context, QQmlAccessors *accessors));
};
#undef RUNTIME_METHOD
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index e01571c3d6..44d171e087 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -71,14 +71,18 @@ struct ScopedValue;
struct Scope {
inline Scope(ExecutionContext *ctx)
: engine(ctx->d()->engine)
+ , mark(engine->jsStackTop)
+ , result(*engine->jsAlloca(1))
{
- mark = engine->jsStackTop;
+ result = Encode::undefined();
}
explicit Scope(ExecutionEngine *e)
: engine(e)
+ , mark(engine->jsStackTop)
+ , result(*engine->jsAlloca(1))
{
- mark = engine->jsStackTop;
+ result = Encode::undefined();
}
~Scope() {
@@ -88,12 +92,12 @@ struct Scope {
memset(mark, 0, (engine->jsStackTop - mark)*sizeof(Value));
#endif
#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_UNDEFINED(mark, engine->jsStackLimit - mark);
+ VALGRIND_MAKE_MEM_UNDEFINED(mark, (engine->jsStackLimit - mark) * sizeof(Value));
#endif
engine->jsStackTop = mark;
}
- Value *alloc(int nValues) {
+ Value *alloc(int nValues) const {
return engine->jsAlloca(nValues);
}
@@ -103,6 +107,7 @@ struct Scope {
ExecutionEngine *engine;
Value *mark;
+ Value &result;
private:
Q_DISABLE_COPY(Scope)
@@ -126,9 +131,6 @@ struct ScopedValue
{
ptr = scope.engine->jsStackTop++;
ptr->setM(o);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
- ptr->setTag(QV4::Value::Managed_Type);
-#endif
}
ScopedValue(const Scope &scope, Managed *m)
@@ -150,9 +152,6 @@ struct ScopedValue
ScopedValue &operator=(Heap::Base *o) {
ptr->setM(o);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
- ptr->setTag(QV4::Value::Managed_Type);
-#endif
return *this;
}
@@ -192,69 +191,63 @@ struct Scoped
inline void setPointer(const Managed *p) {
ptr->setM(p ? p->m() : 0);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
- ptr->setTag(QV4::Value::Managed_Type);
-#endif
}
Scoped(const Scope &scope)
{
- ptr = scope.engine->jsStackTop++;
- ptr->setM(0);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
- ptr->setTag(QV4::Value::Managed_Type);
-#endif
+ ptr = scope.engine->jsAlloca(1);
}
Scoped(const Scope &scope, const Value &v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(v.as<T>());
}
Scoped(const Scope &scope, Heap::Base *o)
{
Value v;
v = o;
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(v.as<T>());
}
Scoped(const Scope &scope, const ScopedValue &v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(v.ptr->as<T>());
}
Scoped(const Scope &scope, const Value &v, ConvertType)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
ptr->setRawValue(value_convert<T>(scope.engine, v));
}
Scoped(const Scope &scope, const Value *v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(v ? v->as<T>() : 0);
}
Scoped(const Scope &scope, T *t)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(t);
}
Scoped(const Scope &scope, typename T::Data *t)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
*ptr = t;
}
Scoped(const Scope &scope, const ReturnedValue &v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
setPointer(QV4::Value::fromReturnedValue(v).as<T>());
}
+
Scoped(const Scope &scope, const ReturnedValue &v, ConvertType)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.engine->jsAlloca(1);
ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v)));
}
@@ -301,6 +294,10 @@ struct Scoped
return ptr->cast<T>();
}
+ const T *operator->() const {
+ return ptr->cast<T>();
+ }
+
bool operator!() const {
return !ptr->m();
}
@@ -323,7 +320,7 @@ struct Scoped
};
struct ScopedCallData {
- ScopedCallData(Scope &scope, int argc = 0)
+ ScopedCallData(const Scope &scope, int argc = 0)
{
int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value);
ptr = reinterpret_cast<CallData *>(scope.alloc(size));
@@ -345,14 +342,14 @@ struct ScopedCallData {
inline Value &Value::operator =(const ScopedValue &v)
{
- _val = v.ptr->val();
+ _val = v.ptr->rawValue();
return *this;
}
template<typename T>
inline Value &Value::operator=(const Scoped<T> &t)
{
- _val = t.ptr->val();
+ _val = t.ptr->rawValue();
return *this;
}
@@ -374,19 +371,19 @@ struct ScopedProperty
struct ExecutionContextSaver
{
- ExecutionEngine *engine;
+ Scope scope; // this makes sure that a reference to context on the JS stack goes out of scope as soon as the context is not used anymore.
ExecutionContext *savedContext;
- ExecutionContextSaver(Scope &scope)
- : engine(scope.engine)
+ ExecutionContextSaver(const Scope &scope)
+ : scope(scope.engine)
{
- savedContext = engine->currentContext;
+ savedContext = scope.engine->currentContext;
}
~ExecutionContextSaver()
{
- Q_ASSERT(engine->jsStackTop > engine->currentContext);
- engine->currentContext = savedContext;
- engine->current = savedContext->d();
+ Q_ASSERT(scope.engine->jsStackTop > scope.engine->currentContext);
+ scope.engine->currentContext = savedContext;
+ scope.engine->current = savedContext->d();
}
};
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 4b847600b4..b40307d2f0 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -64,34 +64,16 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Heap {
-struct CompilationUnitHolder : Object {
- inline CompilationUnitHolder(CompiledData::CompilationUnit *unit);
-
- QQmlRefPointer<CompiledData::CompilationUnit> unit;
-};
-
struct QmlBindingWrapper : FunctionObject {
QmlBindingWrapper(QV4::QmlContext *scope, Function *f);
};
}
-struct CompilationUnitHolder : public Object
-{
- V4_OBJECT2(CompilationUnitHolder, Object)
- V4_NEEDS_DESTROY
-};
-
-inline
-Heap::CompilationUnitHolder::CompilationUnitHolder(CompiledData::CompilationUnit *unit)
- : unit(unit)
-{
-}
-
struct QmlBindingWrapper : FunctionObject {
V4_OBJECT2(QmlBindingWrapper, FunctionObject)
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
}
@@ -101,7 +83,6 @@ QT_END_NAMESPACE
using namespace QV4;
DEFINE_OBJECT_VTABLE(QmlBindingWrapper);
-DEFINE_OBJECT_VTABLE(CompilationUnitHolder);
Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f)
: Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false)
@@ -113,32 +94,33 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f)
function->compilationUnit->addref();
}
-ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData)
+void QmlBindingWrapper::call(const Managed *that, Scope &scope, CallData *callData)
{
const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that);
ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException)
- return Encode::undefined();
- CHECK_STACK_LIMITS(v4);
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ CHECK_STACK_LIMITS(v4, scope);
- Scope scope(v4);
ExecutionContextSaver ctxSaver(scope);
QV4::Function *f = This->function();
- if (!f)
- return QV4::Encode::undefined();
+ if (!f) {
+ scope.result = QV4::Encode::undefined();
+ return;
+ }
Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData));
v4->pushContext(ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, f));
-
- return result->asReturnedValue();
+ scope.result = Q_V4_PROFILE(v4, f);
}
Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit)
: line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
- , vmFunction(0), parseAsBinding(true)
+ , compilationUnit(compilationUnit), vmFunction(0), parseAsBinding(true)
{
if (qml)
qmlContext.set(v4, *qml);
@@ -146,11 +128,6 @@ Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUn
parsed = true;
vmFunction = compilationUnit ? compilationUnit->linkToEngine(v4) : 0;
- if (vmFunction) {
- Scope valueScope(v4);
- ScopedObject holder(valueScope, v4->memoryManager->allocObject<CompilationUnitHolder>(compilationUnit));
- compilationUnitHolder.set(v4, holder);
- }
}
Script::~Script()
@@ -171,7 +148,7 @@ void Script::parse()
MemoryManager::GCBlocker gcBlocker(v4->memoryManager);
- IR::Module module(v4->debugger != 0);
+ IR::Module module(v4->debugger() != 0);
QQmlJS::Engine ee, *engine = &ee;
Lexer lexer(engine);
@@ -180,7 +157,8 @@ void Script::parse()
const bool parsed = parser.parseProgram();
- foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
+ const auto diagnosticMessages = parser.diagnosticMessages();
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
if (m.isError()) {
valueScope.engine->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
return;
@@ -217,10 +195,8 @@ void Script::parse()
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
if (inheritContext)
isel->setUseFastLookups(false);
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile();
+ compilationUnit = isel->compile();
vmFunction = compilationUnit->linkToEngine(v4);
- ScopedObject holder(valueScope, v4->memoryManager->allocObject<CompilationUnitHolder>(compilationUnit));
- compilationUnitHolder.set(v4, holder);
}
if (!vmFunction) {
@@ -247,6 +223,7 @@ ReturnedValue Script::run()
ContextStateSaver stateSaver(valueScope, scope);
scope->d()->strictMode = vmFunction->isStrict();
scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups;
+ scope->d()->constantTable = vmFunction->compilationUnit->constants;
scope->d()->compilationUnit = vmFunction->compilationUnit;
return Q_V4_PROFILE(engine, vmFunction);
@@ -255,7 +232,8 @@ ReturnedValue Script::run()
ScopedFunctionObject f(valueScope, engine->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction));
ScopedCallData callData(valueScope);
callData->thisObject = Primitive::undefinedValue();
- return f->call(callData);
+ f->call(valueScope, callData);
+ return valueScope.result.asReturnedValue();
}
}
@@ -282,7 +260,8 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module
QList<QQmlError> errors;
- foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
+ const auto diagnosticMessages = parser.diagnosticMessages();
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message));
continue;
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index d7b82218e7..2e87a7692b 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -71,22 +71,25 @@ struct ContextStateSaver {
Value *savedContext;
bool strictMode;
Lookup *lookups;
+ const QV4::Value *constantTable;
CompiledData::CompilationUnit *compilationUnit;
int lineNumber;
- ContextStateSaver(Scope &scope, ExecutionContext *context)
+ ContextStateSaver(const Scope &scope, ExecutionContext *context)
: savedContext(scope.alloc(1))
, strictMode(context->d()->strictMode)
, lookups(context->d()->lookups)
+ , constantTable(context->d()->constantTable)
, compilationUnit(context->d()->compilationUnit)
, lineNumber(context->d()->lineNumber)
{
savedContext->setM(context->d());
}
- ContextStateSaver(Scope &scope, Heap::ExecutionContext *context)
+ ContextStateSaver(const Scope &scope, Heap::ExecutionContext *context)
: savedContext(scope.alloc(1))
, strictMode(context->strictMode)
, lookups(context->lookups)
+ , constantTable(context->constantTable)
, compilationUnit(context->compilationUnit)
, lineNumber(context->lineNumber)
{
@@ -98,6 +101,7 @@ struct ContextStateSaver {
Heap::ExecutionContext *ctx = static_cast<Heap::ExecutionContext *>(savedContext->m());
ctx->strictMode = strictMode;
ctx->lookups = lookups;
+ ctx->constantTable = constantTable;
ctx->compilationUnit = compilationUnit;
ctx->lineNumber = lineNumber;
}
@@ -126,7 +130,7 @@ struct Q_QML_EXPORT Script {
bool inheritContext;
bool parsed;
QV4::PersistentValue qmlContext;
- QV4::PersistentValue compilationUnitHolder;
+ QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit;
Function *vmFunction;
bool parseAsBinding;
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index fa2409a85c..59086c245c 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -218,9 +218,10 @@ template <typename Container>
struct QQmlSequence : Object {
QQmlSequence(const Container &container);
QQmlSequence(QObject *object, int propertyIndex);
+ ~QQmlSequence() { object.destroy(); }
mutable Container container;
- QPointer<QObject> object;
+ QQmlQPointer<QObject> object;
int propertyIndex;
bool isReference;
};
@@ -411,8 +412,8 @@ public:
callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs);
callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs);
callData->thisObject = this->m_ctx->d()->engine->globalObject;
- QV4::ScopedValue result(scope, compare->call(callData));
- return result->toNumber() < 0;
+ compare->call(scope, callData);
+ return scope.result.toNumber() < 0;
}
private:
@@ -531,7 +532,7 @@ public:
Q_ASSERT(d()->object);
Q_ASSERT(d()->isReference);
int status = -1;
- QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding;
+ QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding;
void *a[] = { &d()->container, 0, &status, &flags };
QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a);
}
@@ -558,6 +559,8 @@ Heap::QQmlSequence<Container>::QQmlSequence(const Container &container)
, propertyIndex(-1)
, isReference(false)
{
+ object.init();
+
QV4::Scope scope(internalClass->engine);
QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this);
o->setArrayType(Heap::ArrayData::Custom);
@@ -566,10 +569,10 @@ Heap::QQmlSequence<Container>::QQmlSequence(const Container &container)
template <typename Container>
Heap::QQmlSequence<Container>::QQmlSequence(QObject *object, int propertyIndex)
- : object(object)
- , propertyIndex(propertyIndex)
+ : propertyIndex(propertyIndex)
, isReference(true)
{
+ this->object.init(object);
QV4::Scope scope(internalClass->engine);
QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this);
o->setArrayType(Heap::ArrayData::Custom);
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 7c965ce441..8bc867e2cd 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -46,59 +46,10 @@
#include "qv4stringobject_p.h"
#endif
#include <QtCore/QHash>
-#include <QtCore/private/qnumeric_p.h>
using namespace QV4;
-static inline uint toUInt(const QChar *ch) { return ch->unicode(); }
#ifndef V4_BOOTSTRAP
-static inline uint toUInt(const char *ch) { return *ch; }
-#endif
-
-template <typename T>
-static inline uint toArrayIndex(const T *ch, const T *end)
-{
- uint i = toUInt(ch) - '0';
- if (i > 9)
- return UINT_MAX;
- ++ch;
- // reject "01", "001", ...
- if (i == 0 && ch != end)
- return UINT_MAX;
-
- while (ch < end) {
- uint x = toUInt(ch) - '0';
- if (x > 9)
- return UINT_MAX;
- if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i))
- return UINT_MAX;
- ++ch;
- }
- return i;
-}
-
-#ifndef V4_BOOTSTRAP
-
-template <typename T>
-static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
-{
- // array indices get their number as hash value
- uint h = ::toArrayIndex(ch, end);
- if (h != UINT_MAX) {
- if (subtype)
- *subtype = Heap::String::StringType_ArrayIndex;
- return h;
- }
-
- while (ch < end) {
- h = 31 * h + toUInt(ch);
- ++ch;
- }
-
- if (subtype)
- *subtype = Heap::String::StringType_Regular;
- return h;
-}
DEFINE_MANAGED_VTABLE(String);
@@ -126,6 +77,8 @@ bool String::isEqualTo(Managed *t, Managed *o)
Heap::String::String(MemoryManager *mm, const QString &t)
: mm(mm)
{
+ Base::init();
+
subtype = String::StringType_Unknown;
text = const_cast<QString &>(t).data_ptr();
@@ -136,9 +89,11 @@ Heap::String::String(MemoryManager *mm, const QString &t)
len = text->size;
}
-Heap::String::String(MemoryManager *mm, String *l, String *r)
+Heap::String::String(MemoryManager *mm, String *l, String *r, bool) // TODO: remove the dummy bool when String is trivial
: mm(mm)
{
+ Base::init();
+
subtype = String::StringType_Unknown;
left = l;
@@ -225,19 +180,7 @@ void Heap::String::createHashValue() const
Q_ASSERT(!largestSubLength);
const QChar *ch = reinterpret_cast<const QChar *>(text->data());
const QChar *end = ch + text->size;
- stringHash = calculateHashValue(ch, end, &subtype);
-}
-
-uint String::createHashValue(const QChar *ch, int length, uint *subtype)
-{
- const QChar *end = ch + length;
- return calculateHashValue(ch, end, subtype);
-}
-
-uint String::createHashValue(const char *ch, int length, uint *subtype)
-{
- const char *end = ch + length;
- return calculateHashValue(ch, end, subtype);
+ stringHash = QV4::String::calculateHashValue(ch, end, &subtype);
}
uint String::getLength(const Managed *m)
@@ -249,6 +192,6 @@ uint String::getLength(const Managed *m)
uint String::toArrayIndex(const QString &str)
{
- return ::toArrayIndex(str.constData(), str.constData() + str.length());
+ return QV4::String::toArrayIndex(str.constData(), str.constData() + str.length());
}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 60e2655536..f347ea8897 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -52,6 +52,7 @@
#include <QtCore/qstring.h>
#include "qv4managed_p.h"
+#include <QtCore/private/qnumeric_p.h>
QT_BEGIN_NAMESPACE
@@ -62,7 +63,6 @@ struct Identifier;
namespace Heap {
-#ifndef V4_BOOTSTRAP
struct Q_QML_PRIVATE_EXPORT String : Base {
enum StringType {
StringType_Unknown,
@@ -70,8 +70,9 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
StringType_ArrayIndex
};
+#ifndef V4_BOOTSTRAP
String(MemoryManager *mm, const QString &text);
- String(MemoryManager *mm, String *l, String *n);
+ String(MemoryManager *mm, String *l, String *n, bool dummy);
~String() {
if (!largestSubLength && !text->ref.deref())
QStringData::deallocate(text);
@@ -130,8 +131,8 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
MemoryManager *mm;
private:
static void append(const String *data, QChar *ch);
-};
#endif
+};
}
@@ -183,8 +184,17 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
void makeIdentifierImpl(ExecutionEngine *e) const;
- static uint createHashValue(const QChar *ch, int length, uint *subtype);
- static uint createHashValue(const char *ch, int length, uint *subtype);
+ static uint createHashValue(const QChar *ch, int length, uint *subtype)
+ {
+ const QChar *end = ch + length;
+ return calculateHashValue(ch, end, subtype);
+ }
+
+ static uint createHashValue(const char *ch, int length, uint *subtype)
+ {
+ const char *end = ch + length;
+ return calculateHashValue(ch, end, subtype);
+ }
bool startsWithUpper() const {
const String::Data *l = d();
@@ -203,6 +213,54 @@ protected:
public:
static uint toArrayIndex(const QString &str);
+
+private:
+ static inline uint toUInt(const QChar *ch) { return ch->unicode(); }
+ static inline uint toUInt(const char *ch) { return *ch; }
+
+ template <typename T>
+ static inline uint toArrayIndex(const T *ch, const T *end)
+ {
+ uint i = toUInt(ch) - '0';
+ if (i > 9)
+ return UINT_MAX;
+ ++ch;
+ // reject "01", "001", ...
+ if (i == 0 && ch != end)
+ return UINT_MAX;
+
+ while (ch < end) {
+ uint x = toUInt(ch) - '0';
+ if (x > 9)
+ return UINT_MAX;
+ if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x
+ return UINT_MAX;
+ ++ch;
+ }
+ return i;
+ }
+
+public:
+ template <typename T>
+ static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
+ {
+ // array indices get their number as hash value
+ uint h = toArrayIndex(ch, end);
+ if (h != UINT_MAX) {
+ if (subtype)
+ *subtype = Heap::String::StringType_ArrayIndex;
+ return h;
+ }
+
+ while (ch < end) {
+ h = 31 * h + toUInt(ch);
+ ++ch;
+ }
+
+ if (subtype)
+ *subtype = Heap::String::StringType_Regular;
+ return h;
+ }
};
template<>
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index b4f04bbc76..1989f747e9 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -157,28 +157,24 @@ Heap::StringCtor::StringCtor(QV4::ExecutionContext *scope)
{
}
-ReturnedValue StringCtor::construct(const Managed *m, CallData *callData)
+void StringCtor::construct(const Managed *m, Scope &scope, CallData *callData)
{
ExecutionEngine *v4 = static_cast<const Object *>(m)->engine();
- Scope scope(v4);
ScopedString value(scope);
if (callData->argc)
value = callData->args[0].toString(v4);
else
value = v4->newString();
- return Encode(v4->newStringObject(value));
+ scope.result = Encode(v4->newStringObject(value));
}
-ReturnedValue StringCtor::call(const Managed *m, CallData *callData)
+void StringCtor::call(const Managed *, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = static_cast<const Object *>(m)->engine();
- Scope scope(v4);
- ScopedValue value(scope);
+ ExecutionEngine *v4 = scope.engine;
if (callData->argc)
- value = callData->args[0].toString(v4);
+ scope.result = callData->args[0].toString(v4);
else
- value = v4->newString();
- return value->asReturnedValue();
+ scope.result = v4->newString();
}
void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -423,7 +419,8 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
if (!rx) {
ScopedCallData callData(scope, 1);
callData->args[0] = regexp;
- rx = context->d()->engine->regExpCtor()->construct(callData);
+ context->d()->engine->regExpCtor()->construct(scope, callData);
+ rx = scope.result.asReturnedValue();
}
if (!rx)
@@ -439,8 +436,10 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
ScopedCallData callData(scope, 1);
callData->thisObject = rx;
callData->args[0] = s;
- if (!global)
- return exec->call(callData);
+ if (!global) {
+ exec->call(scope, callData);
+ return scope.result.asReturnedValue();
+ }
ScopedString lastIndex(scope, context->d()->engine->newString(QStringLiteral("lastIndex")));
rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0)));
@@ -448,14 +447,13 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
double previousLastIndex = 0;
uint n = 0;
- ScopedValue result(scope);
ScopedValue matchStr(scope);
ScopedValue index(scope);
while (1) {
- result = exec->call(callData);
- if (result->isNull())
+ exec->call(scope, callData);
+ if (scope.result.isNull())
break;
- assert(result->isObject());
+ assert(scope.result.isObject());
index = rx->get(lastIndex, 0);
double thisIndex = index->toInteger();
if (previousLastIndex == thisIndex) {
@@ -464,7 +462,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
} else {
previousLastIndex = thisIndex;
}
- matchStr = result->objectValue()->getIndexed(0);
+ matchStr = scope.result.objectValue()->getIndexed(0);
a->arraySet(n, matchStr);
++n;
}
@@ -580,7 +578,6 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
}
QString result;
- ScopedValue replacement(scope);
ScopedValue replaceValue(scope, ctx->argument(1));
ScopedFunctionObject searchCallback(scope, replaceValue);
if (!!searchCallback) {
@@ -605,9 +602,9 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
callData->args[numCaptures] = Primitive::fromUInt32(matchStart);
callData->args[numCaptures + 1] = ctx->d()->engine->newString(string);
- replacement = searchCallback->call(callData);
+ searchCallback->call(scope, callData);
result += string.midRef(lastEnd, matchStart - lastEnd);
- result += replacement->toQString();
+ result += scope.result.toQString();
lastEnd = matchEnd;
}
result += string.midRef(lastEnd);
@@ -640,17 +637,17 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx)
{
Scope scope(ctx);
QString string = getThisString(ctx);
- ScopedValue regExpValue(scope, ctx->argument(0));
+ scope.result = ctx->argument(0);
if (scope.engine->hasException)
return Encode::undefined();
- Scoped<RegExpObject> regExp(scope, regExpValue->as<RegExpObject>());
+ Scoped<RegExpObject> regExp(scope, scope.result.as<RegExpObject>());
if (!regExp) {
ScopedCallData callData(scope, 1);
- callData->args[0] = regExpValue;
- regExpValue = ctx->d()->engine->regExpCtor()->construct(callData);
+ callData->args[0] = scope.result;
+ ctx->d()->engine->regExpCtor()->construct(scope, callData);
if (scope.engine->hasException)
return Encode::undefined();
- regExp = regExpValue->as<RegExpObject>();
+ regExp = scope.result.as<RegExpObject>();
Q_ASSERT(regExp);
}
Scoped<RegExp> re(scope, regExp->value());
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index fb229d4aff..54425b0909 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -103,8 +103,8 @@ struct StringCtor: FunctionObject
{
V4_OBJECT2(StringCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *, Scope &scope, CallData *callData);
};
struct StringPrototype: StringObject
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index c86f252353..ae5ebcad1b 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -208,30 +208,34 @@ Heap::TypedArrayCtor::TypedArrayCtor(QV4::ExecutionContext *scope, TypedArray::T
{
}
-ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
+void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const Object *>(m)->engine());
Scoped<TypedArrayCtor> that(scope, static_cast<const TypedArrayCtor *>(m));
if (!callData->argc || !callData->args[0].isObject()) {
// ECMA 6 22.2.1.1
double l = callData->argc ? callData->args[0].toNumber() : 0;
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
uint len = (uint)l;
if (l != len)
scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array."));
uint byteLength = len * operations[that->d()->type].bytesPerElement;
Scoped<ArrayBuffer> buffer(scope, scope.engine->newArrayBuffer(byteLength));
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer = buffer->d();
array->d()->byteLength = byteLength;
array->d()->byteOffset = 0;
- return array.asReturnedValue();
+ scope.result = array.asReturnedValue();
+ return;
}
Scoped<TypedArray> typedArray(scope, callData->argument(0));
if (!!typedArray) {
@@ -243,8 +247,10 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
uint destByteLength = byteLength*destElementSize/srcElementSize;
Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(destByteLength));
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer = newBuffer->d();
@@ -269,7 +275,8 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
}
}
- return array.asReturnedValue();
+ scope.result = array.asReturnedValue();
+ return;
}
Scoped<ArrayBuffer> buffer(scope, callData->argument(0));
if (!!buffer) {
@@ -278,21 +285,29 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
double dbyteOffset = callData->argc > 1 ? callData->args[1].toInteger() : 0;
uint byteOffset = (uint)dbyteOffset;
uint elementSize = operations[that->d()->type].bytesPerElement;
- if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength())
- return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset"));
+ if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength()) {
+ scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset"));
+ return;
+ }
uint byteLength;
if (callData->argc < 3 || callData->args[2].isUndefined()) {
byteLength = buffer->byteLength() - byteOffset;
- if (buffer->byteLength() < byteOffset || byteLength % elementSize)
- return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
+ if (buffer->byteLength() < byteOffset || byteLength % elementSize) {
+ scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
+ return;
+ }
} else {
double l = qBound(0., callData->args[2].toInteger(), (double)UINT_MAX);
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
l *= elementSize;
- if (buffer->byteLength() - byteOffset < l)
- return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
+ if (buffer->byteLength() - byteOffset < l) {
+ scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
+ return;
+ }
byteLength = (uint)l;
}
@@ -300,20 +315,25 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
array->d()->buffer = buffer->d();
array->d()->byteLength = byteLength;
array->d()->byteOffset = byteOffset;
- return array.asReturnedValue();
+ scope.result = array.asReturnedValue();
+ return;
}
// ECMA 6 22.2.1.3
ScopedObject o(scope, callData->argument(0));
uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length()))->toInteger(), (double)UINT_MAX);
- if (scope.engine->hasException)
- return scope.engine->throwTypeError();
+ if (scope.engine->hasException) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
uint elementSize = operations[that->d()->type].bytesPerElement;
Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(l * elementSize));
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer = newBuffer->d();
@@ -326,19 +346,21 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData)
while (idx < l) {
val = o->getIndexed(idx);
array->d()->type->write(scope.engine, b, 0, val);
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (scope.engine->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
++idx;
b += elementSize;
}
- return array.asReturnedValue();
+ scope.result = array.asReturnedValue();
}
-ReturnedValue TypedArrayCtor::call(const Managed *that, CallData *callData)
+void TypedArrayCtor::call(const Managed *that, Scope &scope, CallData *callData)
{
- return construct(that, callData);
+ construct(that, scope, callData);
}
Heap::TypedArray::TypedArray(Type t)
@@ -582,5 +604,6 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx)
callData->args[0] = buffer;
callData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
callData->args[2] = Encode(newLen);
- return constructor->construct(callData);
+ constructor->construct(scope, callData);
+ return scope.result.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 757273e4ed..d96027b96a 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -140,8 +140,8 @@ struct TypedArrayCtor: FunctionObject
{
V4_OBJECT2(TypedArrayCtor, FunctionObject)
- static ReturnedValue construct(const Managed *m, CallData *callData);
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4util_p.h b/src/qml/jsruntime/qv4util_p.h
index 59c12c5e46..2669a3e4bf 100644
--- a/src/qml/jsruntime/qv4util_p.h
+++ b/src/qml/jsruntime/qv4util_p.h
@@ -90,6 +90,9 @@ public:
: bits(size, value)
{}
+ void clear()
+ { bits = std::vector<bool>(bits.size(), false); }
+
void reserve(int size)
{ bits.reserve(size); }
@@ -153,6 +156,9 @@ public:
: bits(size, value)
{}
+ void clear()
+ { bits = QBitArray(bits.size(), false); }
+
void reserve(int size)
{ Q_UNUSED(size); }
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index a8d9b0fa71..78cd4de9fb 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -72,6 +72,7 @@ typedef uint Bool;
struct Q_QML_PRIVATE_EXPORT Value
{
+private:
/*
We use two different ways of encoding JS values. One for 32bit and one for 64bit systems.
@@ -96,40 +97,73 @@ struct Q_QML_PRIVATE_EXPORT Value
quint64 _val;
- Q_ALWAYS_INLINE quint64 val() const { return _val; }
- Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; }
- Q_ALWAYS_INLINE void setValue(quint32 v) { memcpy(&_val, &v, 4); }
- Q_ALWAYS_INLINE void setTag(quint32 t) { memcpy(4 + (quint8 *)&_val, &t, 4); }
+public:
+ Q_ALWAYS_INLINE quint64 &rawValueRef() { return _val; }
+ Q_ALWAYS_INLINE quint64 rawValue() const { return _val; }
+ Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; }
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
static inline int valueOffset() { return 0; }
static inline int tagOffset() { return 4; }
- Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
- Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); }
- Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; }
#else // !Q_LITTLE_ENDIAN
static inline int valueOffset() { return 4; }
static inline int tagOffset() { return 0; }
- Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; }
- Q_ALWAYS_INLINE quint32 tag() const { return _val & quint64(~quint32(0)); }
- Q_ALWAYS_INLINE quint32 value() const { return _val >> 32; }
#endif
+ Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
+ Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); }
+ Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; }
#if defined(V4_BOOTSTRAP)
Q_ALWAYS_INLINE Heap::Base *m() const { Q_UNREACHABLE(); return Q_NULLPTR; }
Q_ALWAYS_INLINE void setM(Heap::Base *b) { Q_UNUSED(b); Q_UNREACHABLE(); }
#elif defined(QV4_USE_64_BIT_VALUE_ENCODING)
- Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; }
- Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); }
+ Q_ALWAYS_INLINE Heap::Base *m() const
+ {
+ Heap::Base *b;
+ memcpy(&b, &_val, 8);
+ return b;
+ }
+ Q_ALWAYS_INLINE void setM(Heap::Base *b)
+ {
+ memcpy(&_val, &b, 8);
+ }
#else // !QV4_USE_64_BIT_VALUE_ENCODING
- Q_ALWAYS_INLINE Heap::Base *m() const { Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32)); Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; }
- Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); }
+ Q_ALWAYS_INLINE Heap::Base *m() const
+ {
+ Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32));
+ Heap::Base *b;
+ quint32 v = value();
+ memcpy(&b, &v, 4);
+ return b;
+ }
+ Q_ALWAYS_INLINE void setM(Heap::Base *b)
+ {
+ quint32 v;
+ memcpy(&v, &b, 4);
+ setTagValue(Managed_Type, v);
+ }
#endif
- Q_ALWAYS_INLINE int int_32() const { int i; quint32 v = value(); memcpy(&i, &v, 4); return i; }
- Q_ALWAYS_INLINE void setInt_32(int i) { quint32 u; memcpy(&u, &i, 4); setValue(u); }
+ Q_ALWAYS_INLINE int int_32() const
+ {
+ return int(value());
+ }
+ Q_ALWAYS_INLINE void setInt_32(int i)
+ {
+ setTagValue(Integer_Type_Internal, quint32(i));
+ }
Q_ALWAYS_INLINE uint uint_32() const { return value(); }
+ Q_ALWAYS_INLINE void setEmpty()
+ {
+ setTagValue(Empty_Type, value());
+ }
+
+ Q_ALWAYS_INLINE void setEmpty(int i)
+ {
+ setTagValue(Empty_Type, quint32(i));
+ }
+
#ifndef QV4_USE_64_BIT_VALUE_ENCODING
enum Masks {
SilentNaNBit = 0x00040000,
@@ -266,7 +300,6 @@ struct Q_QML_PRIVATE_EXPORT Value
int i = (int)d;
if (i == d) {
setInt_32(i);
- setTag(Integer_Type_Internal);
return true;
}
}
@@ -286,34 +319,28 @@ struct Q_QML_PRIVATE_EXPORT Value
}
Q_ALWAYS_INLINE String *stringValue() const {
+ if (!isString())
+ return nullptr;
return m() ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0;
}
Q_ALWAYS_INLINE Object *objectValue() const {
+ if (!isObject())
+ return nullptr;
return m() ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0;
}
Q_ALWAYS_INLINE Managed *managed() const {
+ if (!isManaged())
+ return nullptr;
return m() ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0;
}
Q_ALWAYS_INLINE Heap::Base *heapObject() const {
- return m();
+ return isManaged() ? m() : nullptr;
}
- Q_ALWAYS_INLINE quint64 &rawValueRef() {
- return _val;
- }
- Q_ALWAYS_INLINE quint64 rawValue() const {
- return _val;
- }
- Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; }
-
static inline Value fromHeapObject(Heap::Base *m)
{
Value v;
- v.setRawValue(0);
v.setM(m);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
- v.setTag(Managed_Type);
-#endif
return v;
}
@@ -334,7 +361,7 @@ struct Q_QML_PRIVATE_EXPORT Value
inline bool tryIntegerConversion() {
bool b = integerCompatible();
if (b)
- setTag(Integer_Type_Internal);
+ setTagValue(Integer_Type_Internal, value());
return b;
}
@@ -357,7 +384,10 @@ struct Q_QML_PRIVATE_EXPORT Value
}
template <typename T>
T *as() {
- return const_cast<T *>(const_cast<const Value *>(this)->as<T>());
+ if (isManaged())
+ return const_cast<T *>(const_cast<const Value *>(this)->as<T>());
+ else
+ return nullptr;
}
template<typename T> inline T *cast() {
@@ -384,7 +414,7 @@ struct Q_QML_PRIVATE_EXPORT Value
Value &operator=(ReturnedValue v) { _val = v; return *this; }
Value &operator=(Managed *m) {
if (!m) {
- setTagValue(Undefined_Type, 0);
+ setM(0);
} else {
_val = reinterpret_cast<Value *>(m)->_val;
}
@@ -392,19 +422,13 @@ struct Q_QML_PRIVATE_EXPORT Value
}
Value &operator=(Heap::Base *o) {
setM(o);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
- setTag(Managed_Type);
-#endif
return *this;
}
template<typename T>
Value &operator=(const Scoped<T> &t);
- Value &operator=(const Value &v) {
- _val = v._val;
- return *this;
- }
};
+Q_STATIC_ASSERT(std::is_trivial<Value>::value);
inline bool Value::isString() const
{
@@ -485,13 +509,7 @@ struct Q_QML_PRIVATE_EXPORT Primitive : public Value
inline Primitive Primitive::undefinedValue()
{
Primitive v;
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- v.setRawValue(quint64(Undefined_Type) << Tag_Shift);
-#else
- v.setRawValue(0);
- v.setTag(Undefined_Type);
- v.setValue(0);
-#endif
+ v.setTagValue(Undefined_Type, 0);
return v;
}
@@ -505,11 +523,7 @@ inline Primitive Primitive::emptyValue()
inline Primitive Primitive::nullValue()
{
Primitive v;
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
- v.setRawValue(quint64(Null_Type_Internal) << Tag_Shift);
-#else
v.setTagValue(Null_Type_Internal, 0);
-#endif
return v;
}
@@ -530,7 +544,7 @@ inline Primitive Primitive::fromDouble(double d)
inline Primitive Primitive::fromInt32(int i)
{
Primitive v;
- v.setTagValue(Integer_Type_Internal, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
+ v.setTagValue(Integer_Type_Internal, 0);
v.setInt_32(i);
return v;
}
@@ -539,8 +553,7 @@ inline Primitive Primitive::fromUInt32(uint i)
{
Primitive v;
if (i < INT_MAX) {
- v.setTagValue(Integer_Type_Internal, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
- v.setInt_32((int)i);
+ v.setTagValue(Integer_Type_Internal, i);
} else {
v.setDouble(i);
}
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 444c0a37e0..39b41dd0d8 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -138,8 +138,11 @@ QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx)
if (!o)
return Encode::undefined();
QString result = o->d()->data.toString();
- if (result.isEmpty() && !o->d()->data.canConvert(QVariant::String))
- result = QStringLiteral("QVariant(%0)").arg(QString::fromLatin1(o->d()->data.typeName()));
+ if (result.isEmpty() && !o->d()->data.canConvert(QVariant::String)) {
+ result = QLatin1String("QVariant(")
+ + QLatin1String(o->d()->data.typeName())
+ + QLatin1Char(')');
+ }
return Encode(ctx->d()->engine->newString(result));
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 9ad21305f7..9d18713253 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -142,6 +142,7 @@ Q_QML_EXPORT int qt_v4DebuggerHook(const char *json);
} // extern "C"
+#ifndef QT_NO_QML_DEBUGGER
static int qt_v4BreakpointCount = 0;
static bool qt_v4IsDebugging = true;
static bool qt_v4IsStepping = false;
@@ -203,7 +204,7 @@ int qt_v4DebuggerHook(const char *json)
QJsonDocument doc = QJsonDocument::fromJson(json);
QJsonObject ob = doc.object();
- QByteArray command = ob.value(QStringLiteral("command")).toString().toUtf8();
+ QByteArray command = ob.value(QLatin1String("command")).toString().toUtf8();
if (command == "protocolVersion") {
return ProtocolVersion; // Version number.
@@ -217,17 +218,17 @@ int qt_v4DebuggerHook(const char *json)
if (command == "insertBreakpoint") {
Breakpoint bp;
bp.bpNumber = ++qt_v4BreakpointCount;
- bp.lineNumber = ob.value(QStringLiteral("lineNumber")).toString().toInt();
- bp.engineName = ob.value(QStringLiteral("engineName")).toString();
- bp.fullName = ob.value(QStringLiteral("fullName")).toString();
- bp.condition = ob.value(QStringLiteral("condition")).toString();
+ bp.lineNumber = ob.value(QLatin1String("lineNumber")).toString().toInt();
+ bp.engineName = ob.value(QLatin1String("engineName")).toString();
+ bp.fullName = ob.value(QLatin1String("fullName")).toString();
+ bp.condition = ob.value(QLatin1String("condition")).toString();
qt_v4Breakpoints.append(bp);
return bp.bpNumber;
}
if (command == "removeBreakpoint") {
- int lineNumber = ob.value(QStringLiteral("lineNumber")).toString().toInt();
- QString fullName = ob.value(QStringLiteral("fullName")).toString();
+ int lineNumber = ob.value(QLatin1String("lineNumber")).toString().toInt();
+ QString fullName = ob.value(QLatin1String("fullName")).toString();
if (qt_v4Breakpoints.last().matches(fullName, lineNumber)) {
qt_v4Breakpoints.removeLast();
return Success;
@@ -285,6 +286,7 @@ static void qt_v4CheckForBreak(QV4::ExecutionContext *context, QV4::Value **scop
}
}
+#endif // QT_NO_QML_DEBUGGER
// End of debugger interface
using namespace QV4;
@@ -400,7 +402,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
QV4::Value **scopes = static_cast<QV4::Value **>(alloca(sizeof(QV4::Value *)*(2 + 2*scopeDepth)));
{
- scopes[0] = const_cast<QV4::Value *>(context->d()->compilationUnit->data->constants());
+ scopes[0] = const_cast<QV4::Value *>(context->d()->compilationUnit->constants);
// stack gets setup in push instruction
scopes[1] = 0;
QV4::Heap::ExecutionContext *scope = context->d();
@@ -519,62 +521,22 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
STOREVALUE(instr.result, engine->runtime.getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadQObjectProperty)
- MOTH_BEGIN_INSTR(LoadQRealQObjectPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQObjectQRealProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
- MOTH_END_INSTR(LoadQRealQObjectPropertyDirectly)
-
- MOTH_BEGIN_INSTR(LoadQObjectQObjectPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQObjectQObjectProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
- MOTH_END_INSTR(LoadQObjectQObjectPropertyDirectly)
-
- MOTH_BEGIN_INSTR(LoadIntQObjectPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQObjectIntProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
- MOTH_END_INSTR(LoadIntQObjectPropertyDirectly)
-
- MOTH_BEGIN_INSTR(LoadBoolQObjectPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQObjectBoolProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
- MOTH_END_INSTR(LoadQRealQObjectPropertyDirectly)
-
- MOTH_BEGIN_INSTR(LoadQStringQObjectPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQObjectQStringProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
- MOTH_END_INSTR(LoadQStringQObjectPropertyDirectly)
-
MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
engine->runtime.setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreScopeObjectProperty)
MOTH_BEGIN_INSTR(LoadScopeObjectProperty)
- STOREVALUE(instr.result, engine->runtime.getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex));
+ STOREVALUE(instr.result, engine->runtime.getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadScopeObjectProperty)
- MOTH_BEGIN_INSTR(LoadScopeObjectQRealPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQRealProperty(VALUE(instr.base), instr.accessors));
- MOTH_END_INSTR(LoadScopeObjectQRealPropertyDirectly)
-
- MOTH_BEGIN_INSTR(LoadScopeObjectQObjectPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQObjectProperty(VALUE(instr.base), instr.accessors));
- MOTH_END_INSTR(LoadScopeObjectQObjectPropertyDirectly)
-
- MOTH_BEGIN_INSTR(LoadScopeObjectIntPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectIntProperty(VALUE(instr.base), instr.accessors));
- MOTH_END_INSTR(LoadScopeObjectIntPropertyDirectly)
-
- MOTH_BEGIN_INSTR(LoadScopeObjectBoolPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectBoolProperty(VALUE(instr.base), instr.accessors));
- MOTH_END_INSTR(LoadScopeObjectBoolPropertyDirectly)
-
- MOTH_BEGIN_INSTR(LoadScopeObjectQStringPropertyDirectly)
- STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQStringProperty(engine, VALUE(instr.base), instr.accessors));
- MOTH_END_INSTR(LoadScopeObjectQStringPropertyDirectly)
-
MOTH_BEGIN_INSTR(StoreContextObjectProperty)
engine->runtime.setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreContextObjectProperty)
MOTH_BEGIN_INSTR(LoadContextObjectProperty)
- STOREVALUE(instr.result, engine->runtime.getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex));
+ STOREVALUE(instr.result, engine->runtime.getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadContextObjectProperty)
MOTH_BEGIN_INSTR(LoadIdObject)
@@ -944,9 +906,10 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
return VALUE(instr.result).asReturnedValue();
MOTH_END_INSTR(Ret)
+#ifndef QT_NO_QML_DEBUGGER
MOTH_BEGIN_INSTR(Debug)
engine->current->lineNumber = instr.lineNumber;
- QV4::Debugging::Debugger *debugger = context->engine()->debugger;
+ QV4::Debugging::Debugger *debugger = context->engine()->debugger();
if (debugger && debugger->pauseAtNextOpportunity())
debugger->maybeBreakAtInstruction();
if (qt_v4IsDebugging)
@@ -958,6 +921,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
if (qt_v4IsDebugging)
qt_v4CheckForBreak(context, scopes, scopeDepth);
MOTH_END_INSTR(Line)
+#endif // QT_NO_QML_DEBUGGER
MOTH_BEGIN_INSTR(LoadThis)
VALUE(instr.result) = context->thisObject();
@@ -1010,7 +974,7 @@ void **VME::instructionJumpTable()
QV4::ReturnedValue VME::exec(ExecutionEngine *engine, const uchar *code)
{
VME vme;
- QV4::Debugging::Debugger *debugger = engine->debugger;
+ QV4::Debugging::Debugger *debugger = engine->debugger();
if (debugger)
debugger->enteringFunction();
QV4::ReturnedValue retVal = vme.run(engine, code);
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index ed7a531766..d15d14e463 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -52,6 +52,11 @@
#include <QtCore/QString>
#include <private/qv4global_p.h>
+#include <QSharedPointer>
+
+// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their
+// parent's init all up the inheritance chain), define QML_CHECK_INIT_DESTROY_CALLS below.
+#undef QML_CHECK_INIT_DESTROY_CALLS
QT_BEGIN_NAMESPACE
@@ -119,13 +124,20 @@ struct Q_QML_EXPORT Base {
void *operator new(size_t, Managed *m) { return m; }
void *operator new(size_t, Heap::Base *m) { return m; }
void operator delete(void *, Heap::Base *) {}
+
+ void init() { setInitialized(); }
+#ifdef QML_CHECK_INIT_DESTROY_CALLS
+ bool _isInitialized;
+ void _checkIsInitialized() { Q_ASSERT(_isInitialized); }
+ void setInitialized() { Q_ASSERT(!_isInitialized); _isInitialized = true; }
+#else
+ Q_ALWAYS_INLINE void _checkIsInitialized() {}
+ Q_ALWAYS_INLINE void setInitialized() {}
+#endif
};
template <typename T>
struct Pointer {
- Pointer() {}
- Pointer(T *t) : ptr(t) {}
-
T *operator->() const { return ptr; }
operator T *() const { return ptr; }
@@ -136,9 +148,65 @@ struct Pointer {
T *ptr;
};
+Q_STATIC_ASSERT(std::is_trivial<Pointer<void>>::value);
}
+#ifdef QT_NO_QOBJECT
+template <class T>
+struct QQmlQPointer {
+};
+#else
+template <class T>
+struct QQmlQPointer {
+ void init()
+ {
+ d = nullptr;
+ qObject = nullptr;
+ }
+
+ void init(T *o)
+ {
+ Q_ASSERT(d == nullptr);
+ Q_ASSERT(qObject == nullptr);
+ if (o) {
+ d = QtSharedPointer::ExternalRefCountData::getAndRef(o);
+ qObject = o;
+ }
+ }
+
+ void destroy()
+ {
+ if (d && !d->weakref.deref())
+ delete d;
+ d = nullptr;
+ qObject = nullptr;
+ }
+
+ T *data() const {
+ return d == nullptr || d->strongref.load() == 0 ? nullptr : qObject;
+ }
+ operator T*() const { return data(); }
+ inline T* operator->() const { return data(); }
+ QQmlQPointer &operator=(T *o)
+ {
+ if (d)
+ destroy();
+ init(o);
+ return *this;
+ }
+ bool isNull() const Q_DECL_NOTHROW
+ {
+ return d == nullptr || qObject == nullptr || d->strongref.load() == 0;
+ }
+
+private:
+ QtSharedPointer::ExternalRefCountData *d;
+ QObject *qObject;
+};
+Q_STATIC_ASSERT(std::is_trivial<QQmlQPointer<QObject>>::value);
+#endif
+
}
QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 4fb2acebc5..3d25bd1639 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -48,6 +48,7 @@
#include <QTime>
#include <QMap>
+#include <QScopedValueRollback>
#include <iostream>
#include <cstdlib>
@@ -60,6 +61,10 @@
#include <valgrind/memcheck.h>
#endif
+#ifdef V4_USE_HEAPTRACK
+#include <heaptrack_api.h>
+#endif
+
#if OS(QNX)
#include <sys/storage.h> // __tls()
#endif
@@ -79,9 +84,9 @@ static uint maxShiftValue()
static uint result = 0;
if (!result) {
result = 6;
- if (Q_UNLIKELY(qEnvironmentVariableIsSet("QV4_MM_MAXBLOCK_SHIFT"))) {
+ if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAXBLOCK_SHIFT))) {
bool ok;
- const uint overrideValue = qgetenv("QV4_MM_MAXBLOCK_SHIFT").toUInt(&ok);
+ const uint overrideValue = qgetenv(QV4_MM_MAXBLOCK_SHIFT).toUInt(&ok);
if (ok && overrideValue <= 11 && overrideValue > 0)
result = overrideValue;
}
@@ -94,9 +99,9 @@ static std::size_t maxChunkSizeValue()
static std::size_t result = 0;
if (!result) {
result = 32 * 1024;
- if (Q_UNLIKELY(qEnvironmentVariableIsSet("QV4_MM_MAX_CHUNK_SIZE"))) {
+ if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAX_CHUNK_SIZE))) {
bool ok;
- const std::size_t overrideValue = qgetenv("QV4_MM_MAX_CHUNK_SIZE").toUInt(&ok);
+ const std::size_t overrideValue = qgetenv(QV4_MM_MAX_CHUNK_SIZE).toUInt(&ok);
if (ok)
result = overrideValue;
}
@@ -170,7 +175,7 @@ struct MemoryManager::Data
, maxShift(maxShiftValue())
, gcBlocked(false)
, aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
- , gcStats(!qEnvironmentVariableIsEmpty("QV4_MM_STATS"))
+ , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS))
{
memset(nonFullChunks, 0, sizeof(nonFullChunks));
memset(nChunks, 0, sizeof(nChunks));
@@ -181,7 +186,7 @@ struct MemoryManager::Data
~Data()
{
for (std::vector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
- Q_V4_PROFILE_DEALLOC(engine, 0, i->size(), Profiling::HeapPage);
+ Q_V4_PROFILE_DEALLOC(engine, i->size(), Profiling::HeapPage);
i->deallocate();
}
}
@@ -232,7 +237,10 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec
VALGRIND_DISABLE_ERROR_REPORTING;
VALGRIND_MEMPOOL_FREE(engine->memoryManager, m);
#endif
- Q_V4_PROFILE_DEALLOC(engine, m, header->itemSize, Profiling::SmallItem);
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_free(m);
+#endif
+ Q_V4_PROFILE_DEALLOC(engine, header->itemSize, Profiling::SmallItem);
++(*itemsInUse);
}
// Relink all free blocks to rewrite references to any released chunk.
@@ -295,10 +303,11 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
runGC();
// we use malloc for this
- MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(
- malloc(Q_V4_PROFILE_ALLOC(engine, size + sizeof(MemoryManager::Data::LargeItem),
- Profiling::LargeItem)));
- memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem));
+ const size_t totalSize = size + sizeof(MemoryManager::Data::LargeItem);
+ Q_V4_PROFILE_ALLOC(engine, totalSize, Profiling::LargeItem);
+ MemoryManager::Data::LargeItem *item =
+ static_cast<MemoryManager::Data::LargeItem *>(malloc(totalSize));
+ memset(item, 0, totalSize);
item->next = m_d->largeItems;
item->size = size;
m_d->largeItems = item;
@@ -331,9 +340,8 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
shift = m_d->maxShift;
std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
allocSize = roundUpToMultipleOf(m_d->pageSize, allocSize);
- PageAllocation allocation = PageAllocation::allocate(
- Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage),
- OSAllocator::JSGCHeapPages);
+ Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage);
+ PageAllocation allocation = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
m_d->heapChunks.push_back(allocation);
header = reinterpret_cast<Data::ChunkHeader *>(allocation.base());
@@ -362,12 +370,18 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
VALGRIND_MAKE_MEM_NOACCESS(allocation.base(), allocSize);
VALGRIND_MEMPOOL_ALLOC(this, header, sizeof(Data::ChunkHeader));
#endif
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_alloc(header, sizeof(Data::ChunkHeader));
+#endif
}
found:
#ifdef V4_USE_VALGRIND
VALGRIND_MEMPOOL_ALLOC(this, m, size);
#endif
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_alloc(m, size);
+#endif
Q_V4_PROFILE_ALLOC(engine, size, Profiling::SmallItem);
++m_d->allocCount[pos];
@@ -382,6 +396,7 @@ static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
{
while (engine->jsStackTop > markBase) {
Heap::Base *h = engine->popForGC();
+ Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
Q_ASSERT (h->vtable()->markObjects);
h->vtable()->markObjects(h, engine);
}
@@ -438,10 +453,10 @@ void MemoryManager::sweep(bool lastSweep)
for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
if (!(*it).isManaged())
continue;
- Managed *m = (*it).as<Managed>();
+ Managed *m = (*it).managed();
if (m->markBit())
continue;
- // we need to call detroyObject on qobjectwrappers now, so that they can emit the destroyed
+ // we need to call destroyObject on qobjectwrappers now, so that they can emit the destroyed
// signal before we start sweeping the heap
if (QObjectWrapper *qobjectWrapper = (*it).as<QObjectWrapper>())
qobjectWrapper->destroyObject(lastSweep);
@@ -449,6 +464,17 @@ void MemoryManager::sweep(bool lastSweep)
(*it) = Primitive::undefinedValue();
}
+ // onDestruction handlers may have accessed other QObject wrappers and reset their value, so ensure
+ // that they are all set to undefined.
+ for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
+ if (!(*it).isManaged())
+ continue;
+ Managed *m = (*it).as<Managed>();
+ if (m->markBit())
+ continue;
+ (*it) = Primitive::undefinedValue();
+ }
+
// Now it is time to free QV4::QObjectWrapper Value, we must check the Value's tag to make sure its object has been destroyed
const int pendingCount = m_pendingFreedObjectWrapperValue.count();
if (pendingCount) {
@@ -493,10 +519,13 @@ void MemoryManager::sweep(bool lastSweep)
// Release that chunk if it could have been spared since the last GC run without any difference.
if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) {
- Q_V4_PROFILE_DEALLOC(engine, 0, chunkIter->size(), Profiling::HeapPage);
+ Q_V4_PROFILE_DEALLOC(engine, chunkIter->size(), Profiling::HeapPage);
#ifdef V4_USE_VALGRIND
VALGRIND_MEMPOOL_FREE(this, header);
#endif
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_free(header);
+#endif
--m_d->nChunks[pos];
m_d->availableItems[pos] -= uint(decrease);
m_d->totalItems -= int(decrease);
@@ -525,8 +554,8 @@ void MemoryManager::sweep(bool lastSweep)
m->vtable()->destroy(m);
*last = i->next;
- free(Q_V4_PROFILE_DEALLOC(engine, i, i->size + sizeof(Data::LargeItem),
- Profiling::LargeItem));
+ Q_V4_PROFILE_DEALLOC(engine, i->size + sizeof(Data::LargeItem), Profiling::LargeItem);
+ free(i);
i = *last;
}
@@ -557,6 +586,8 @@ void MemoryManager::runGC()
return;
}
+ QScopedValueRollback<bool> gcBlocker(m_d->gcBlocked, true);
+
if (!m_d->gcStats) {
mark();
sweep();
@@ -676,7 +707,7 @@ void MemoryManager::collectFromJSStack() const
Value *v = engine->jsStackBase;
Value *top = engine->jsStackTop;
while (v < top) {
- Managed *m = v->as<Managed>();
+ Managed *m = v->managed();
if (m && m->inUse())
// Skip pointers to already freed objects, they are bogus as well
m->mark(engine);
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index e169675f7d..6db5b54760 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -59,6 +59,10 @@
//#define DETAILED_MM_STATS
+#define QV4_MM_MAXBLOCK_SHIFT "QV4_MM_MAXBLOCK_SHIFT"
+#define QV4_MM_MAX_CHUNK_SIZE "QV4_MM_MAX_CHUNK_SIZE"
+#define QV4_MM_STATS "QV4_MM_STATS"
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -272,7 +276,7 @@ public:
{
Scope scope(engine);
Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- (void)new (t->d()) typename ManagedType::Data(arg1, arg2);
+ t->d_unchecked()->init(arg1, arg2);
return t->d();
}
@@ -281,7 +285,7 @@ public:
{
Scope scope(engine);
Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3);
+ t->d_unchecked()->init(arg1, arg2, arg3);
return t->d();
}
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 2ca4e883d6..846ea42571 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -273,12 +273,12 @@ public:
: expression(expression)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return lparenToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rparenToken; }
// attributes
@@ -294,12 +294,12 @@ public:
ThisExpression() { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return thisToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return thisToken; }
// attributes
@@ -314,12 +314,12 @@ public:
IdentifierExpression(const QStringRef &n):
name (n) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return identifierToken; }
// attributes
@@ -334,12 +334,12 @@ public:
NullExpression() { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return nullToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return nullToken; }
// attributes
@@ -353,12 +353,12 @@ public:
TrueLiteral() { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return trueToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return trueToken; }
// attributes
@@ -372,12 +372,12 @@ public:
FalseLiteral() { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return falseToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return falseToken; }
// attributes
@@ -392,12 +392,12 @@ public:
NumericLiteral(double v):
value(v) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return literalToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return literalToken; }
// attributes:
@@ -413,12 +413,12 @@ public:
StringLiteral(const QStringRef &v):
value (v) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return literalToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return literalToken; }
// attributes:
@@ -434,12 +434,12 @@ public:
RegExpLiteral(const QStringRef &p, int f):
pattern (p), flags (f) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return literalToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return literalToken; }
// attributes:
@@ -465,12 +465,12 @@ public:
elements (elts), elision (e)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return lbracketToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbracketToken; }
// attributes
@@ -492,12 +492,12 @@ public:
ObjectLiteral(PropertyAssignmentList *plist):
properties (plist) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return lbraceToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
// attributes
@@ -521,12 +521,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return commaToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : commaToken; }
inline Elision *finish ()
@@ -565,16 +565,16 @@ public:
return front;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{
if (elision)
return elision->firstSourceLocation();
return expression->firstSourceLocation();
}
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{
if (next)
return next->lastSourceLocation();
@@ -595,10 +595,10 @@ public:
PropertyName() { kind = K; }
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return propertyNameToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return propertyNameToken; }
virtual QString asString() const = 0;
@@ -642,12 +642,12 @@ public:
return front;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return assignment->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : assignment->lastSourceLocation(); }
// attributes
@@ -665,12 +665,12 @@ public:
: PropertyAssignment(n), value(v)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return name->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return value->lastSourceLocation(); }
// attributes
@@ -697,12 +697,12 @@ public:
: PropertyAssignment(n), type(Setter), formals(f), functionBody (b)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return getSetToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
// attributes
@@ -724,9 +724,9 @@ public:
IdentifierPropertyName(const QStringRef &n):
id (n) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual QString asString() const { return id.toString(); }
+ QString asString() const override { return id.toString(); }
// attributes
QStringRef id;
@@ -740,9 +740,9 @@ public:
StringLiteralPropertyName(const QStringRef &n):
id (n) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual QString asString() const { return id.toString(); }
+ QString asString() const override { return id.toString(); }
// attributes
QStringRef id;
@@ -756,9 +756,9 @@ public:
NumericLiteralPropertyName(double n):
id (n) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual QString asString() const { return QString::number(id, 'g', 16); }
+ QString asString() const override { return QString::number(id, 'g', 16); }
// attributes
double id;
@@ -773,12 +773,12 @@ public:
base (b), expression (e)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbracketToken; }
// attributes
@@ -797,12 +797,12 @@ public:
base (b), name (n)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return identifierToken; }
// attributes
@@ -821,12 +821,12 @@ public:
base (b), arguments (a)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return newToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rparenToken; }
// attributes
@@ -845,12 +845,12 @@ public:
NewExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return newToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -867,12 +867,12 @@ public:
base (b), arguments (a)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rparenToken; }
// attributes
@@ -899,12 +899,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return expression->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{
if (next)
return next->lastSourceLocation();
@@ -932,12 +932,12 @@ public:
PostIncrementExpression(ExpressionNode *b):
base (b) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return incrementToken; }
// attributes
@@ -953,12 +953,12 @@ public:
PostDecrementExpression(ExpressionNode *b):
base (b) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return decrementToken; }
// attributes
@@ -974,12 +974,12 @@ public:
DeleteExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return deleteToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -995,12 +995,12 @@ public:
VoidExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return voidToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -1016,12 +1016,12 @@ public:
TypeOfExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return typeofToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -1037,12 +1037,12 @@ public:
PreIncrementExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return incrementToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -1058,12 +1058,12 @@ public:
PreDecrementExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return decrementToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -1079,12 +1079,12 @@ public:
UnaryPlusExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return plusToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -1100,12 +1100,12 @@ public:
UnaryMinusExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return minusToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -1121,12 +1121,12 @@ public:
TildeExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return tildeToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -1142,12 +1142,12 @@ public:
NotExpression(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return notToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression->lastSourceLocation(); }
// attributes
@@ -1164,14 +1164,14 @@ public:
left (l), op (o), right (r)
{ kind = K; }
- virtual BinaryExpression *binaryExpressionCast();
+ BinaryExpression *binaryExpressionCast() override;
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return left->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return right->lastSourceLocation(); }
// attributes
@@ -1190,12 +1190,12 @@ public:
expression (e), ok (t), ko (f)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return expression->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return ko->lastSourceLocation(); }
// attributes
@@ -1214,12 +1214,12 @@ public:
Expression(ExpressionNode *l, ExpressionNode *r):
left (l), right (r) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return left->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return right->lastSourceLocation(); }
// attributes
@@ -1236,12 +1236,12 @@ public:
Block(StatementList *slist):
statements (slist) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return lbraceToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
// attributes
@@ -1267,12 +1267,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return statement->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : statement->lastSourceLocation(); }
inline StatementList *finish ()
@@ -1296,12 +1296,12 @@ public:
declarations (vlist)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return declarationKindToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -1319,12 +1319,12 @@ public:
name (n), expression (e), readOnly(false)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return expression ? expression->lastSourceLocation() : identifierToken; }
// attributes
@@ -1351,12 +1351,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return declaration->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{
if (next)
return next->lastSourceLocation();
@@ -1388,12 +1388,12 @@ public:
EmptyStatement() { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return semicolonToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -1408,12 +1408,12 @@ public:
ExpressionStatement(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return expression->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -1430,12 +1430,12 @@ public:
expression (e), ok (t), ko (f)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return ifToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{
if (ko)
return ko->lastSourceLocation();
@@ -1462,12 +1462,12 @@ public:
statement (stmt), expression (e)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return doToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -1489,12 +1489,12 @@ public:
expression (e), statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return whileToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -1514,12 +1514,12 @@ public:
initialiser (i), condition (c), expression (e), statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return forToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -1543,12 +1543,12 @@ public:
declarations (vlist), condition (c), expression (e), statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return forToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -1573,12 +1573,12 @@ public:
initialiser (i), expression (e), statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return forToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -1600,12 +1600,12 @@ public:
declaration (v), expression (e), statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return forToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -1627,12 +1627,12 @@ public:
ContinueStatement(const QStringRef &l = QStringRef()):
label (l) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return continueToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -1650,12 +1650,12 @@ public:
BreakStatement(const QStringRef &l):
label (l) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return breakToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -1673,12 +1673,12 @@ public:
ReturnStatement(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return returnToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -1696,12 +1696,12 @@ public:
expression (e), statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return withToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -1721,12 +1721,12 @@ public:
clauses (c), defaultClause (d), moreClauses (r)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return lbraceToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
// attributes
@@ -1746,12 +1746,12 @@ public:
expression (e), block (b)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return switchToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return block->rbraceToken; }
// attributes
@@ -1771,12 +1771,12 @@ public:
expression (e), statements (slist)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return caseToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statements ? statements->lastSourceLocation() : colonToken; }
// attributes
@@ -1803,12 +1803,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return clause->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : clause->lastSourceLocation(); }
inline CaseClauses *finish ()
@@ -1832,12 +1832,12 @@ public:
statements (slist)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return defaultToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statements ? statements->lastSourceLocation() : colonToken; }
// attributes
@@ -1855,12 +1855,12 @@ public:
label (l), statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -1878,12 +1878,12 @@ public:
ThrowStatement(ExpressionNode *e):
expression (e) { kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return throwToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -1901,12 +1901,12 @@ public:
name (n), statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return catchToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -1927,12 +1927,12 @@ public:
statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return finallyToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement ? statement->lastSourceLocation() : finallyToken; }
// attributes
@@ -1957,12 +1957,12 @@ public:
statement (stmt), catchExpression (c), finallyExpression (0)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return tryToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{
if (finallyExpression)
return finallyExpression->statement->rbraceToken;
@@ -1988,12 +1988,12 @@ public:
name (n), formals (f), body (b)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return functionToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
// attributes
@@ -2017,7 +2017,7 @@ public:
FunctionExpression(n, f, b)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
};
class QML_PARSER_EXPORT FormalParameterList: public Node
@@ -2037,12 +2037,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : identifierToken; }
inline FormalParameterList *finish ()
@@ -2085,12 +2085,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return element->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : element->lastSourceLocation(); }
inline SourceElements *finish ()
@@ -2114,12 +2114,12 @@ public:
elements (elts)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return elements ? elements->firstSourceLocation() : SourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return elements ? elements->lastSourceLocation() : SourceLocation(); }
// attributes
@@ -2135,12 +2135,12 @@ public:
elements (elts)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return elements ? elements->firstSourceLocation() : SourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return elements ? elements->lastSourceLocation() : SourceLocation(); }
// attributes
@@ -2156,12 +2156,12 @@ public:
declaration (f)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return declaration->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return declaration->lastSourceLocation(); }
// attributes
@@ -2177,12 +2177,12 @@ public:
statement (stmt)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return statement->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
// attributes
@@ -2197,12 +2197,12 @@ public:
DebuggerStatement()
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return debuggerToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -2234,12 +2234,12 @@ public:
return head;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : identifierToken; }
// attributes
@@ -2261,12 +2261,12 @@ public:
: importUri(uri)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return importToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -2284,10 +2284,10 @@ public:
class QML_PARSER_EXPORT UiObjectMember: public Node
{
public:
- virtual SourceLocation firstSourceLocation() const = 0;
- virtual SourceLocation lastSourceLocation() const = 0;
+ SourceLocation firstSourceLocation() const override = 0;
+ SourceLocation lastSourceLocation() const override = 0;
- virtual UiObjectMember *uiObjectMemberCast();
+ UiObjectMember *uiObjectMemberCast() override;
};
class QML_PARSER_EXPORT UiObjectMemberList: public Node
@@ -2307,12 +2307,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return member->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
UiObjectMemberList *finish()
@@ -2351,12 +2351,12 @@ public:
return head;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : identifierToken; }
// attributes
@@ -2374,12 +2374,12 @@ public:
: pragmaType(type)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return pragmaToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return semicolonToken; }
// attributes
@@ -2424,12 +2424,12 @@ public:
return head;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return headerItem->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : headerItem->lastSourceLocation(); }
// attributes
@@ -2446,9 +2446,9 @@ public:
: headers(headers), members(members)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{
if (headers)
return headers->firstSourceLocation();
@@ -2457,7 +2457,7 @@ public:
return SourceLocation();
}
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{
if (members)
return members->lastSourceLocation();
@@ -2488,12 +2488,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return member->firstSourceLocation(); }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
UiArrayMemberList *finish()
@@ -2518,12 +2518,12 @@ public:
: members(members)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return lbraceToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
// attributes
@@ -2549,12 +2549,12 @@ public:
previous->next = this;
}
- virtual void accept0(Visitor *);
+ void accept0(Visitor *) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return propertyTypeToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : identifierToken; }
inline UiParameterList *finish ()
@@ -2589,9 +2589,9 @@ public:
: type(Property), memberType(memberType), name(name), statement(statement), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{
if (defaultToken.isValid())
return defaultToken;
@@ -2601,7 +2601,7 @@ public:
return propertyToken;
}
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{
if (binding)
return binding->lastSourceLocation();
@@ -2641,12 +2641,12 @@ public:
: qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer)
{ kind = K; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return qualifiedTypeNameId->identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return initializer->rbraceToken; }
// attributes
@@ -2663,7 +2663,7 @@ public:
: sourceElement(sourceElement)
{ kind = K; }
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{
if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
return funDecl->firstSourceLocation();
@@ -2673,7 +2673,7 @@ public:
return SourceLocation();
}
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{
if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
return funDecl->lastSourceLocation();
@@ -2683,7 +2683,7 @@ public:
return SourceLocation();
}
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
// attributes
@@ -2704,7 +2704,7 @@ public:
hasOnToken(false)
{ kind = K; }
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{
if (hasOnToken && qualifiedTypeNameId)
return qualifiedTypeNameId->identifierToken;
@@ -2712,10 +2712,10 @@ public:
return qualifiedId->identifierToken;
}
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return initializer->rbraceToken; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
// attributes
@@ -2737,13 +2737,13 @@ public:
statement(statement)
{ kind = K; }
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return qualifiedId->identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
// attributes
UiQualifiedId *qualifiedId;
@@ -2762,13 +2762,13 @@ public:
members(members)
{ kind = K; }
- virtual SourceLocation firstSourceLocation() const
+ SourceLocation firstSourceLocation() const override
{ return qualifiedId->identifierToken; }
- virtual SourceLocation lastSourceLocation() const
+ SourceLocation lastSourceLocation() const override
{ return rbracketToken; }
- virtual void accept0(Visitor *visitor);
+ void accept0(Visitor *visitor) override;
// attributes
UiQualifiedId *qualifiedId;
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp
index 07064a4889..7a6d9c3826 100644
--- a/src/qml/parser/qqmljsengine_p.cpp
+++ b/src/qml/parser/qqmljsengine_p.cpp
@@ -114,7 +114,7 @@ double integerFromString(const char *buf, int size, int radix)
double integerFromString(const QString &str, int radix)
{
- QByteArray ba = str.trimmed().toLatin1();
+ QByteArray ba = QStringRef(&str).trimmed().toLatin1();
return integerFromString(ba.constData(), ba.size(), radix);
}
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index bae8f25efc..13e00d8812 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -22,6 +22,15 @@ exists("qqml_enable_gcov") {
LIBS_PRIVATE += -lgcov
}
+gcc:!intel_icc:greaterThan(QT_GCC_MAJOR_VERSION, 5) {
+ # Our code is bad. Temporary workaround.
+ QMAKE_CXXFLAGS += -fno-delete-null-pointer-checks -fno-lifetime-dse
+}
+
+# QTBUG-55238, disable new optimizer for MSVC 2015/Update 3.
+release:win32-msvc*:equals(QT_CL_MAJOR_VERSION, 19):equals(QT_CL_MINOR_VERSION, 00): \
+ greaterThan(QT_CL_PATCH_VERSION, 24212):QMAKE_CXXFLAGS += -d2SSAOptimizer-
+
QMAKE_DOCS = $$PWD/doc/qtqml.qdocconf
# 2415: variable "xx" of static storage duration was declared but never referenced
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
index addf1d9ff8..87d80d04bc 100644
--- a/src/qml/qml/ftw/ftw.pri
+++ b/src/qml/qml/ftw/ftw.pri
@@ -8,11 +8,11 @@ HEADERS += \
$$PWD/qqmlthread_p.h \
$$PWD/qfinitestack_p.h \
$$PWD/qrecursionwatcher_p.h \
- $$PWD/qdeletewatcher_p.h \
$$PWD/qrecyclepool_p.h \
$$PWD/qflagpointer_p.h \
$$PWD/qlazilyallocated_p.h \
$$PWD/qqmlnullablevalue_p.h \
+ $$PWD/qdeferredcleanup_p.h \
SOURCES += \
$$PWD/qintrusivelist.cpp \
@@ -21,4 +21,4 @@ SOURCES += \
# mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri
# clock_gettime() is implemented in librt on these systems
-contains(QT_CONFIG, clock-gettime):linux-*|hpux-*|solaris-*:LIBS_PRIVATE *= -lrt
+qtConfig(clock-gettime):linux-*|hpux-*|solaris-*:LIBS_PRIVATE *= -lrt
diff --git a/src/qml/qml/ftw/qdeferredcleanup_p.h b/src/qml/qml/ftw/qdeferredcleanup_p.h
new file mode 100644
index 0000000000..6b59f04a77
--- /dev/null
+++ b/src/qml/qml/ftw/qdeferredcleanup_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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$
+**
+****************************************************************************/
+
+#ifndef QDEFERREDCLEANUP_P_H
+#define QDEFERREDCLEANUP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+struct QDeferredCleanup
+{
+ std::function<void()> callback;
+ template <typename Callback>
+ QDeferredCleanup(Callback &&cb)
+ : callback(cb)
+ {}
+ ~QDeferredCleanup() { callback(); }
+ QDeferredCleanup(const QDeferredCleanup &) = delete;
+ QDeferredCleanup &operator=(const QDeferredCleanup &) = delete;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDEFERREDCLEANUP_P_H
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 5c5d2a31ac..117670dbfc 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -39,30 +39,7 @@
#include "qhashedstring_p.h"
-inline quint32 stringHash(const QChar* data, int length)
-{
- return QV4::String::createHashValue(data, length, Q_NULLPTR);
-}
-inline quint32 stringHash(const char *data, int length)
-{
- return QV4::String::createHashValue(data, length, Q_NULLPTR);
-}
-
-void QHashedString::computeHash() const
-{
- m_hash = stringHash(constData(), length());
-}
-
-void QHashedStringRef::computeHash() const
-{
- m_hash = stringHash(m_data, m_length);
-}
-
-void QHashedCStringRef::computeHash() const
-{
- m_hash = stringHash(m_data, m_length);
-}
/*
A QHash has initially around pow(2, MinNumBits) buckets. For
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index 6ff3e4a11b..9ee50ec931 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
// #define QSTRINGHASH_LINK_DEBUG
class QHashedStringRef;
-class Q_AUTOTEST_EXPORT QHashedString : public QString
+class Q_QML_PRIVATE_EXPORT QHashedString : public QString
{
public:
inline QHashedString();
@@ -85,16 +85,20 @@ public:
static bool compare(const QChar *lhs, const QChar *rhs, int length);
static inline bool compare(const QChar *lhs, const char *rhs, int length);
static inline bool compare(const char *lhs, const char *rhs, int length);
+
+ static inline quint32 stringHash(const QChar* data, int length);
+ static inline quint32 stringHash(const char *data, int length);
+
private:
friend class QHashedStringRef;
friend class QStringHashNode;
- void computeHash() const;
+ inline void computeHash() const;
mutable quint32 m_hash;
};
class QHashedCStringRef;
-class Q_AUTOTEST_EXPORT QHashedStringRef
+class Q_QML_PRIVATE_EXPORT QHashedStringRef
{
public:
inline QHashedStringRef();
@@ -136,7 +140,7 @@ public:
private:
friend class QHashedString;
- void computeHash() const;
+ inline void computeHash() const;
const QChar *m_data;
int m_length;
@@ -163,7 +167,7 @@ public:
private:
friend class QHashedStringRef;
- void computeHash() const;
+ inline void computeHash() const;
const char *m_data;
int m_length;
@@ -1214,6 +1218,11 @@ bool QHashedStringRef::isLatin1() const
return true;
}
+void QHashedStringRef::computeHash() const
+{
+ m_hash = QHashedString::stringHash(m_data, m_length);
+}
+
bool QHashedStringRef::startsWithUpper() const
{
if (m_length < 1) return false;
@@ -1280,6 +1289,11 @@ void QHashedCStringRef::writeUtf16(quint16 *output) const
*output++ = *d++;
}
+void QHashedCStringRef::computeHash() const
+{
+ m_hash = QHashedString::stringHash(m_data, m_length);
+}
+
bool QHashedString::compare(const QChar *lhs, const char *rhs, int length)
{
Q_ASSERT(lhs && rhs);
@@ -1295,6 +1309,21 @@ bool QHashedString::compare(const char *lhs, const char *rhs, int length)
return 0 == ::memcmp(lhs, rhs, length);
}
+quint32 QHashedString::stringHash(const QChar *data, int length)
+{
+ return QV4::String::createHashValue(data, length, Q_NULLPTR);
+}
+
+quint32 QHashedString::stringHash(const char *data, int length)
+{
+ return QV4::String::createHashValue(data, length, Q_NULLPTR);
+}
+
+void QHashedString::computeHash() const
+{
+ m_hash = stringHash(constData(), length());
+}
+
QT_END_NAMESPACE
#endif // QHASHEDSTRING_P_H
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index 1523817c9e..ffa6e29290 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -55,7 +55,7 @@ public:
QQmlThreadPrivate(QQmlThread *);
QQmlThread *q;
- virtual void run();
+ void run() override;
inline void lock() { _mutex.lock(); }
inline void unlock() { _mutex.unlock(); }
@@ -81,12 +81,12 @@ public:
void threadEvent();
protected:
- virtual bool event(QEvent *);
+ bool event(QEvent *) override;
private:
struct MainObject : public QObject {
MainObject(QQmlThreadPrivate *p);
- virtual bool event(QEvent *e);
+ bool event(QEvent *e) override;
QQmlThreadPrivate *p;
};
MainObject m_mainObject;
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
index 9f180b1f14..295235e255 100644
--- a/src/qml/qml/ftw/qqmlthread_p.h
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -142,7 +142,7 @@ void QQmlThread::callMethodInThread(void (O::*Member)())
struct I : public Message {
void (O::*Member)();
I(void (O::*Member)()) : Member(Member) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)();
}
@@ -157,7 +157,7 @@ void QQmlThread::callMethodInThread(void (O::*Member)(V), const T &arg)
void (O::*Member)(V);
T arg;
I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)(arg);
}
@@ -173,7 +173,7 @@ void QQmlThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, cons
T arg;
T2 arg2;
I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)(arg, arg2);
}
@@ -187,7 +187,7 @@ void QQmlThread::callMethodInMain(void (O::*Member)())
struct I : public Message {
void (O::*Member)();
I(void (O::*Member)()) : Member(Member) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)();
}
@@ -202,7 +202,7 @@ void QQmlThread::callMethodInMain(void (O::*Member)(V), const T &arg)
void (O::*Member)(V);
T arg;
I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)(arg);
}
@@ -218,7 +218,7 @@ void QQmlThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const
T arg;
T2 arg2;
I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)(arg, arg2);
}
@@ -232,7 +232,7 @@ void QQmlThread::postMethodToThread(void (O::*Member)())
struct I : public Message {
void (O::*Member)();
I(void (O::*Member)()) : Member(Member) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)();
}
@@ -247,7 +247,7 @@ void QQmlThread::postMethodToThread(void (O::*Member)(V), const T &arg)
void (O::*Member)(V);
T arg;
I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)(arg);
}
@@ -263,7 +263,7 @@ void QQmlThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, cons
T arg;
T2 arg2;
I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)(arg, arg2);
}
@@ -277,7 +277,7 @@ void QQmlThread::postMethodToMain(void (O::*Member)())
struct I : public Message {
void (O::*Member)();
I(void (O::*Member)()) : Member(Member) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)();
}
@@ -292,7 +292,7 @@ void QQmlThread::postMethodToMain(void (O::*Member)(V), const T &arg)
void (O::*Member)(V);
T arg;
I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)(arg);
}
@@ -308,7 +308,7 @@ void QQmlThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const
T arg;
T2 arg2;
I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- virtual void call(QQmlThread *thread) {
+ void call(QQmlThread *thread) override {
O *me = static_cast<O *>(thread);
(me->*Member)(arg, arg2);
}
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 91d883c29f..8d8da3742d 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -12,7 +12,6 @@ SOURCES += \
$$PWD/qqmlpropertyvalueinterceptor.cpp \
$$PWD/qqmlproxymetaobject.cpp \
$$PWD/qqmlvme.cpp \
- $$PWD/qqmlcompileddata.cpp \
$$PWD/qqmlboundsignal.cpp \
$$PWD/qqmlmetatype.cpp \
$$PWD/qqmlstringconverters.cpp \
@@ -21,7 +20,6 @@ SOURCES += \
$$PWD/qqmlinfo.cpp \
$$PWD/qqmlerror.cpp \
$$PWD/qqmlvaluetype.cpp \
- $$PWD/qqmlaccessors.cpp \
$$PWD/qqmlxmlhttprequest.cpp \
$$PWD/qqmlcleanup.cpp \
$$PWD/qqmlpropertycache.cpp \
@@ -39,7 +37,6 @@ SOURCES += \
$$PWD/qqmlvaluetypeproxybinding.cpp \
$$PWD/qqmlglobal.cpp \
$$PWD/qqmlfile.cpp \
- $$PWD/qqmlmemoryprofiler.cpp \
$$PWD/qqmlplatform.cpp \
$$PWD/qqmlbinding.cpp \
$$PWD/qqmlabstracturlinterceptor.cpp \
@@ -51,7 +48,8 @@ SOURCES += \
$$PWD/qqmlfileselector.cpp \
$$PWD/qqmlobjectcreator.cpp \
$$PWD/qqmldirparser.cpp \
- $$PWD/qqmldelayedcallqueue.cpp
+ $$PWD/qqmldelayedcallqueue.cpp \
+ $$PWD/qqmlloggingcategory.cpp
HEADERS += \
$$PWD/qqmlglobal_p.h \
@@ -71,7 +69,6 @@ HEADERS += \
$$PWD/qqmlparserstatus.h \
$$PWD/qqmlproxymetaobject_p.h \
$$PWD/qqmlvme_p.h \
- $$PWD/qqmlcompiler_p.h \
$$PWD/qqmlengine_p.h \
$$PWD/qqmlexpression_p.h \
$$PWD/qqmlprivate.h \
@@ -89,10 +86,10 @@ HEADERS += \
$$PWD/qqmldata_p.h \
$$PWD/qqmlerror.h \
$$PWD/qqmlvaluetype_p.h \
- $$PWD/qqmlaccessors_p.h \
$$PWD/qqmlxmlhttprequest_p.h \
$$PWD/qqmlcleanup_p.h \
$$PWD/qqmlpropertycache_p.h \
+ $$PWD/qqmlpropertyindex_p.h \
$$PWD/qqmlnotifier_p.h \
$$PWD/qqmltypenotavailable_p.h \
$$PWD/qqmltypenamecache_p.h \
@@ -109,7 +106,6 @@ HEADERS += \
$$PWD/qqmlabstractbinding_p.h \
$$PWD/qqmlvaluetypeproxybinding_p.h \
$$PWD/qqmlfile.h \
- $$PWD/qqmlmemoryprofiler_p.h \
$$PWD/qqmlplatform_p.h \
$$PWD/qqmlbinding_p.h \
$$PWD/qqmlextensionplugin_p.h \
@@ -124,7 +120,8 @@ HEADERS += \
$$PWD/qqmlfileselector.h \
$$PWD/qqmlobjectcreator_p.h \
$$PWD/qqmldirparser_p.h \
- $$PWD/qqmldelayedcallqueue_p.h
+ $$PWD/qqmldelayedcallqueue_p.h \
+ $$PWD/qqmlloggingcategory_p.h
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 8fb710ad9d..39764b8001 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -238,6 +238,9 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+
+Q_QML_EXPORT int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason);
+
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp
index abaf95fa11..39d609454f 100644
--- a/src/qml/qml/qqmlabstractbinding.cpp
+++ b/src/qml/qml/qqmlabstractbinding.cpp
@@ -78,24 +78,26 @@ void QQmlAbstractBinding::addToObject()
QQmlData *data = QQmlData::get(obj, true);
- int coreIndex;
- if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) {
+ int coreIndex = targetPropertyIndex().coreIndex();
+ if (targetPropertyIndex().hasValueTypeIndex()) {
// Value type
// Find the value type proxy (if there is one)
QQmlValueTypeProxyBinding *proxy = 0;
if (data->hasBindingBit(coreIndex)) {
QQmlAbstractBinding *b = data->bindings;
- while (b && b->targetPropertyIndex() != coreIndex)
+ while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
+ b->targetPropertyIndex().hasValueTypeIndex()))
b = b->nextBinding();
Q_ASSERT(b && b->isValueTypeProxy());
proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
}
if (!proxy) {
- proxy = new QQmlValueTypeProxyBinding(obj, coreIndex);
+ proxy = new QQmlValueTypeProxyBinding(obj, QQmlPropertyIndex(coreIndex));
- Q_ASSERT(proxy->targetPropertyIndex() == coreIndex);
+ Q_ASSERT(proxy->targetPropertyIndex().coreIndex() == coreIndex);
+ Q_ASSERT(!proxy->targetPropertyIndex().hasValueTypeIndex());
Q_ASSERT(proxy->targetObject() == obj);
proxy->addToObject();
@@ -137,12 +139,13 @@ void QQmlAbstractBinding::removeFromObject()
next = nextBinding();
setNextBinding(0);
- int coreIndex;
- if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) {
+ int coreIndex = targetPropertyIndex().coreIndex();
+ if (targetPropertyIndex().hasValueTypeIndex()) {
// Find the value type binding
QQmlAbstractBinding *vtbinding = data->bindings;
- while (vtbinding->targetPropertyIndex() != coreIndex) {
+ while (vtbinding && (vtbinding->targetPropertyIndex().coreIndex() != coreIndex ||
+ vtbinding->targetPropertyIndex().hasValueTypeIndex())) {
vtbinding = vtbinding->nextBinding();
Q_ASSERT(vtbinding);
}
diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h
index 45221a4bcd..bea2d253e4 100644
--- a/src/qml/qml/qqmlabstractbinding_p.h
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -76,13 +76,13 @@ public:
// Should return the encoded property index for the binding. Should return this value
// even if the binding is not enabled or added to an object.
// Encoding is: coreIndex | (valueTypeIndex << 16)
- int targetPropertyIndex() const { return m_targetIndex; }
+ QQmlPropertyIndex targetPropertyIndex() const { return m_targetIndex; }
// Should return the object for the binding. Should return this object even if the
// binding is not enabled or added to the object.
QObject *targetObject() const { return m_target.data(); }
- virtual void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f = QQmlPropertyPrivate::DontRemoveBinding) = 0;
+ virtual void setEnabled(bool e, QQmlPropertyData::WriteFlags f = QQmlPropertyData::DontRemoveBinding) = 0;
void addToObject();
void removeFromObject();
@@ -91,6 +91,8 @@ public:
inline QQmlAbstractBinding *nextBinding() const;
+ inline bool canUseAccessor() const
+ { return m_nextBinding.flag2(); }
struct RefCount {
RefCount() : refCount(0) {}
@@ -111,9 +113,16 @@ protected:
inline void setNextBinding(QQmlAbstractBinding *);
- int m_targetIndex;
+ QQmlPropertyIndex m_targetIndex;
+
+ // Pointer is the target object to which the binding binds
+ // flag1 is the updating flag
+ // flag2 is the enabled flag
QFlagPointer<QObject> m_target;
+
// Pointer to the next binding in the linked list of bindings.
+ // flag1 is used for addedToObject
+ // flag2 indicates if an accessor is can be used (i.e. there is no interceptor on the target)
QFlagPointer<QQmlAbstractBinding> m_nextBinding;
};
diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h
deleted file mode 100644
index 55562a5307..0000000000
--- a/src/qml/qml/qqmlaccessors_p.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-#ifndef QQMLACCESSORS_P_H
-#define QQMLACCESSORS_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtqmlglobal_p.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qhash.h>
-#include <QtCore/QReadWriteLock>
-
-#if defined(Q_OS_QNX) || defined(Q_OS_LINUX)
-#include <stdint.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QObject;
-struct QMetaObject;
-class QQmlNotifier;
-
-// QML "accessor properties" allow V4 and V8 to bypass Qt's meta system to read and, more
-// importantly, subscribe to properties directly. Any property that is primarily read
-// from bindings is a candidate for inclusion as an accessor property.
-//
-// To define accessor properties, use the QML_DECLARE_PROPERTIES() and QML_DEFINE_PROPERTIES()
-// macros. The QML_DECLARE_PROPERTIES() macro is used to specify the properties, and the
-// QML_DEFINE_PROPERTIES() macro to register the properties with the
-// QQmlAccessorProperties singleton.
-//
-// A class with accessor properties must also add the Q_CLASSINFO("qt_HasQmlAccessors", "true")
-// tag to its declaration. This is essential for QML to maintain internal consistency,
-// and forgetting to do so will probably cause your application to qFatal() with a
-// helpful reminder of this requirement.
-//
-// It is important that QML_DEFINE_PROPERTIES() has been called before QML ever sees
-// the type with the accessor properties. As QML_DEFINE_PROPERTIES() is idempotent, it is
-// recommended to call it in the type's constructor as well as when the type is registered
-// as a QML element (if it ever is). QML_DEFINE_PROPERTIES() is a very cheap operation
-// if registration has already occurred.
-
-#define QML_DECLARE_PROPERTIES(type) \
- static volatile bool qqml_accessor_properties_isregistered_ ## type = false; \
- static QQmlAccessorProperties::Property qqml_accessor_properties_ ## type[] =
-
-#define QML_DEFINE_PROPERTIES(type) \
- do { \
- if (!qqml_accessor_properties_isregistered_ ## type) { \
- int count = sizeof(qqml_accessor_properties_ ## type) / \
- sizeof(QQmlAccessorProperties::Property); \
- QQmlAccessorProperties::registerProperties(&type::staticMetaObject, count, \
- qqml_accessor_properties_ ## type);\
- qqml_accessor_properties_isregistered_ ## type = true; \
- } \
- } while (false);
-
-#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \
- static void clazz ## _ ## name ## Read(QObject *o, void *rv) \
- { \
- clazz ## Private *d = clazz ## Private::get(static_cast<clazz *>(o)); \
- *static_cast<cpptype *>(rv) = d->variable; \
- }
-
-#define QML_PROPERTY_NAME(name) #name, sizeof #name - 1
-
-class QQmlAccessors
-{
-public:
- void (*read)(QObject *object, void *output);
- void (*notifier)(QObject *object, QQmlNotifier **notifier);
-};
-
-namespace QQmlAccessorProperties {
- struct Property {
- const char *name;
- unsigned int nameLength;
- qintptr data;
- QQmlAccessors *accessors;
- };
-
- struct Properties {
- inline Properties();
- Properties(Property *, int);
-
- bool operator==(const Properties &o) const {
- return count == o.count && properties == o.properties;
- }
-
- inline Property *property(const char *name);
-
- int count;
- Property *properties;
- quint32 nameMask;
- };
-
- Properties properties(const QMetaObject *);
- void Q_QML_PRIVATE_EXPORT registerProperties(const QMetaObject *, int, Property *);
-};
-
-QQmlAccessorProperties::Property *
-QQmlAccessorProperties::Properties::property(const char *name)
-{
- if (count == 0)
- return 0;
-
- const unsigned int length = (unsigned int)strlen(name);
-
- Q_ASSERT(length);
-
- if (nameMask & (1 << qMin(31U, length - 1))) {
-
- for (int ii = 0; ii < count; ++ii) {
- if (properties[ii].nameLength == length && 0 == qstrcmp(name, properties[ii].name))
- return &properties[ii];
- }
-
- }
-
- return 0;
-}
-
-QQmlAccessorProperties::Properties::Properties()
-: count(0), properties(0), nameMask(0)
-{
-}
-
-QT_END_NAMESPACE
-
-#endif // QQMLACCESSORS_P_H
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 8c342e0592..fef2da753b 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -69,6 +69,7 @@ void QQmlApplicationEnginePrivate::init()
q->connect(&statusMapper, SIGNAL(mapped(QObject*)),
q, SLOT(_q_finishLoad(QObject*)));
q->connect(q, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
+ q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(), &QCoreApplication::exit);
#ifndef QT_NO_TRANSLATION
QTranslator* qtTranslator = new QTranslator;
if (qtTranslator->load(QLatin1String("qt_") + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
@@ -134,7 +135,7 @@ void QQmlApplicationEnginePrivate::_q_finishLoad(QObject *o)
break;
case QQmlComponent::Ready:
objects << c->create();
- q->objectCreated(objects.last(), c->url());
+ q->objectCreated(objects.constLast(), c->url());
break;
case QQmlComponent::Loading:
case QQmlComponent::Null:
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 1249e1b6c8..90698c3b24 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -42,7 +42,6 @@
#include "qqml.h"
#include "qqmlcontext.h"
#include "qqmlinfo.h"
-#include "qqmlcompiler_p.h"
#include "qqmldata_p.h"
#include <private/qqmlprofiler_p.h>
#include <private/qqmlexpression_p.h>
@@ -51,33 +50,36 @@
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4variantobject_p.h>
#include <QVariant>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
-QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContext *ctxt)
{
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt));
- setScopeObject(obj);
+ QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt));
+ b->setScopeObject(obj);
- createQmlBinding(context(), obj, str, QString(), 0);
+ b->createQmlBinding(b->context(), obj, str, QString(), 0);
+
+ return b;
}
-QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
{
+ QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+
if (ctxt && !ctxt->isValid())
- return;
+ return b;
const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
- return;
+ return b;
QString url;
QV4::Function *runtimeFunction = 0;
@@ -90,53 +92,61 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
}
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
- setScopeObject(obj ? obj : scriptPrivate->scope);
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
+ b->setScopeObject(obj ? obj : scriptPrivate->scope);
- QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(b->context()->engine)->v4engine();
if (runtimeFunction) {
- m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, scopeObject(), runtimeFunction));
+ b->m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, b->scopeObject(), runtimeFunction));
} else {
QString code = scriptPrivate->script;
- createQmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber);
+ b->createQmlBinding(b->context(), b->scopeObject(), code, url, scriptPrivate->lineNumber);
}
+
+ return b;
}
-QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContextData *ctxt)
{
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(ctxt);
- setScopeObject(obj);
+ QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
- createQmlBinding(ctxt, obj, str, QString(), 0);
+ b->createQmlBinding(ctxt, obj, str, QString(), 0);
+
+ return b;
}
-QQmlBinding::QQmlBinding(const QString &str, QObject *obj,
- QQmlContextData *ctxt,
- const QString &url, quint16 lineNumber, quint16 columnNumber)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj,
+ QQmlContextData *ctxt, const QString &url, quint16 lineNumber,
+ quint16 columnNumber)
{
+ QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+
Q_UNUSED(columnNumber);
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(ctxt);
- setScopeObject(obj);
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
- createQmlBinding(ctxt, obj, str, url, lineNumber);
+ b->createQmlBinding(ctxt, obj, str, url, lineNumber);
+
+ return b;
}
-QQmlBinding::QQmlBinding(const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt)
- : QQmlJavaScriptExpression(),
- QQmlAbstractBinding()
+QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt)
{
- setNotifyOnValueChanged(true);
- QQmlJavaScriptExpression::setContext(ctxt);
- setScopeObject(obj);
+ QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
- m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr);
+ b->m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr);
+
+ return b;
}
QQmlBinding::~QQmlBinding()
@@ -148,7 +158,7 @@ void QQmlBinding::setNotifyOnValueChanged(bool v)
QQmlJavaScriptExpression::setNotifyOnValueChanged(v);
}
-void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
+void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
{
if (!enabledFlag() || !context() || !context()->isValid())
return;
@@ -157,44 +167,75 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
if (QQmlData::wasDeleted(targetObject()))
return;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
- QV4::Scope scope(ep->v4engine());
- QV4::ScopedFunctionObject f(scope, m_function.value());
- Q_ASSERT(f);
-
- if (updatingFlag()) {
- QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0);
+ // Check for a binding update loop
+ if (Q_UNLIKELY(updatingFlag())) {
+ QQmlPropertyData *d = nullptr;
+ QQmlPropertyData vtd;
+ getPropertyData(&d, &vtd);
+ Q_ASSERT(d);
+ QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), *d, &vtd, 0);
QQmlAbstractBinding::printBindingLoopError(p);
return;
}
-
- QQmlBindingProfiler prof(ep->profiler, this, f);
setUpdatingFlag(true);
- QQmlJavaScriptExpression::DeleteWatcher watcher(this);
+ DeleteWatcher watcher(this);
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
+ QV4::Scope scope(ep->v4engine());
+ QV4::ScopedFunctionObject f(scope, m_function.value());
+ Q_ASSERT(f);
- QQmlPropertyData pd = getPropertyData();
+ if (canUseAccessor())
+ flags.setFlag(QQmlPropertyData::BypassInterceptor);
- if (pd.propType == qMetaTypeId<QQmlBinding *>()) {
+ QQmlBindingProfiler prof(ep->profiler, this, f);
+ doUpdate(watcher, flags, scope, f);
- int idx = pd.coreIndex;
- Q_ASSERT(idx != -1);
+ if (!watcher.wasDeleted())
+ setUpdatingFlag(false);
+}
- QQmlBinding *t = this;
- int status = -1;
- void *a[] = { &t, 0, &status, &flags };
- QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a);
+// QQmlBindingBinding is for target properties which are of type "binding" (instead of, say, int or
+// double). The reason for being is that GenericBinding::fastWrite needs a compile-time constant
+// expression for the switch for the compiler to generate the optimal code, but
+// qMetaTypeId<QQmlBinding *>() needs to be used for the ID. So QQmlBinding::newBinding uses that
+// to instantiate this class.
+class QQmlBindingBinding: public QQmlBinding
+{
+protected:
+ void doUpdate(const DeleteWatcher &,
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &,
+ const QV4::ScopedFunctionObject &) Q_DECL_OVERRIDE Q_DECL_FINAL
+ {
+ Q_ASSERT(!m_targetIndex.hasValueTypeIndex());
+ QQmlPropertyData *pd = nullptr;
+ getPropertyData(&pd, nullptr);
+ QQmlBinding *thisPtr = this;
+ pd->writeProperty(*m_target, &thisPtr, flags);
+ }
+};
- } else {
+// For any target that's not a binding, we have a common doUpdate. However, depending on the type
+// of the target property, there is a specialized write method.
+class QQmlNonbindingBinding: public QQmlBinding
+{
+protected:
+ void doUpdate(const DeleteWatcher &watcher,
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &scope,
+ const QV4::ScopedFunctionObject &f) Q_DECL_OVERRIDE Q_DECL_FINAL
+ {
+ auto ep = QQmlEnginePrivate::get(scope.engine);
ep->referenceScarceResources();
bool isUndefined = false;
- QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+ QV4::ScopedCallData callData(scope);
+ QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope);
bool error = false;
if (!watcher.wasDeleted() && isAddedToObject() && !hasError())
- error = !write(pd, result, isUndefined, flags);
+ error = !write(scope.result, isUndefined, flags);
if (!watcher.wasDeleted()) {
@@ -211,66 +252,88 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
}
+ cancelPermanentGuards();
+
ep->dereferenceScarceResources();
}
- if (!watcher.wasDeleted())
- setUpdatingFlag(false);
-}
+ virtual bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags) = 0;
+};
-// Returns true if successful, false if an error description was set on expression
-bool QQmlBinding::write(const QQmlPropertyData &core,
- const QV4::Value &result, bool isUndefined,
- QQmlPropertyPrivate::WriteFlags flags)
+template<int StaticPropType>
+class GenericBinding: public QQmlNonbindingBinding
{
- Q_ASSERT(m_target.data());
- Q_ASSERT(core.coreIndex != -1);
-
-#define QUICK_STORE(cpptype, conversion) \
- { \
- cpptype o = (conversion); \
- int status = -1; \
- void *argv[] = { &o, 0, &status, &flags }; \
- QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, core.coreIndex, argv); \
- return true; \
- } \
-
-
- if (Q_LIKELY(!isUndefined && !core.isValueTypeVirtual())) {
- switch (core.propType) {
- case QMetaType::Int:
- if (result.isInteger())
- QUICK_STORE(int, result.integerValue())
- else if (result.isNumber())
- QUICK_STORE(int, result.doubleValue())
- break;
- case QMetaType::Double:
- if (result.isNumber())
- QUICK_STORE(double, result.asDouble())
- break;
- case QMetaType::Float:
- if (result.isNumber())
- QUICK_STORE(float, result.asDouble())
- break;
- case QMetaType::QString:
- if (result.isString())
- QUICK_STORE(QString, result.toQStringNoThrow())
- break;
- default:
- if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType->typeId == core.propType) {
- return vtw->write(m_target.data(), core.coreIndex);
+protected:
+ // Returns true if successful, false if an error description was set on expression
+ Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags) Q_DECL_OVERRIDE Q_DECL_FINAL
+ {
+ Q_ASSERT(targetObject());
+
+ QQmlPropertyData *pd;
+ QQmlPropertyData vpd;
+ getPropertyData(&pd, &vpd);
+ Q_ASSERT(pd);
+
+ int propertyType = StaticPropType; // If the binding is specialized to a type, the if and switch below will be constant-folded.
+ if (propertyType == QMetaType::UnknownType)
+ propertyType = pd->propType();
+
+ if (Q_LIKELY(!isUndefined && !vpd.isValid())) {
+ switch (propertyType) {
+ case QMetaType::Bool:
+ if (result.isBoolean())
+ return doStore<bool>(result.booleanValue(), pd, flags);
+ else
+ return doStore<bool>(result.toBoolean(), pd, flags);
+ case QMetaType::Int:
+ if (result.isInteger())
+ return doStore<int>(result.integerValue(), pd, flags);
+ else if (result.isNumber())
+ return doStore<int>(result.doubleValue(), pd, flags);
+ break;
+ case QMetaType::Double:
+ if (result.isNumber())
+ return doStore<double>(result.asDouble(), pd, flags);
+ break;
+ case QMetaType::Float:
+ if (result.isNumber())
+ return doStore<float>(result.asDouble(), pd, flags);
+ break;
+ case QMetaType::QString:
+ if (result.isString())
+ return doStore<QString>(result.toQStringNoThrow(), pd, flags);
+ break;
+ default:
+ if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
+ if (vtw->d()->valueType->typeId == pd->propType()) {
+ return vtw->write(m_target.data(), pd->coreIndex());
+ }
}
+ break;
}
- break;
}
+
+ return slowWrite(*pd, vpd, result, isUndefined, flags);
+ }
+
+ template <typename T>
+ Q_ALWAYS_INLINE bool doStore(T value, const QQmlPropertyData *pd, QQmlPropertyData::WriteFlags flags) const
+ {
+ void *o = &value;
+ return pd->writeProperty(targetObject(), o, flags);
}
-#undef QUICK_STORE
+};
+Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
+ const QQmlPropertyData &valueTypeData,
+ const QV4::Value &result,
+ bool isUndefined, QQmlPropertyData::WriteFlags flags)
+{
QQmlEngine *engine = context()->engine;
QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
- int type = core.isValueTypeVirtual() ? core.valueTypePropType : core.propType;
+ int type = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
QQmlJavaScriptExpression::DeleteWatcher watcher(this);
@@ -282,7 +345,7 @@ bool QQmlBinding::write(const QQmlPropertyData &core,
value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >());
} else if (result.isNull() && core.isQObject()) {
value = QVariant::fromValue((QObject *)0);
- } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
+ } else if (core.propType() == qMetaTypeId<QList<QUrl> >()) {
value = QQmlPropertyPrivate::resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context());
} else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
value = QV8Engine::getV4(v8engine)->toVariant(result, type);
@@ -301,28 +364,27 @@ bool QQmlBinding::write(const QQmlPropertyData &core,
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
Q_ASSERT(vmemo);
- vmemo->setVMEProperty(core.coreIndex, result);
+ vmemo->setVMEProperty(core.coreIndex(), result);
} else if (isUndefined && core.isResettable()) {
void *args[] = { 0 };
- QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex, args);
+ QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
} else if (isUndefined && type == qMetaTypeId<QVariant>()) {
- QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant(), context(), flags);
+ QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant(), context(), flags);
} else if (type == qMetaTypeId<QJSValue>()) {
const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
if (f && f->isBinding()) {
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
return false;
}
- QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant::fromValue(
+ QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant::fromValue(
QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())),
context(), flags);
} else if (isUndefined) {
- QString errorStr = QLatin1String("Unable to assign [undefined] to ");
- if (!QMetaType::typeName(type))
- errorStr += QLatin1String("[unknown property type]");
- else
- errorStr += QLatin1String(QMetaType::typeName(type));
- delayedError()->setErrorDescription(errorStr);
+ const QLatin1String typeName(QMetaType::typeName(type)
+ ? QMetaType::typeName(type)
+ : "[unknown property type]");
+ delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ")
+ + typeName);
return false;
} else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) {
if (f->isBinding())
@@ -330,7 +392,7 @@ bool QQmlBinding::write(const QQmlPropertyData &core,
else
delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
return false;
- } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, value, context(), flags)) {
+ } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, value, context(), flags)) {
if (watcher.wasDeleted())
return true;
@@ -338,7 +400,8 @@ bool QQmlBinding::write(const QQmlPropertyData &core,
const char *valueType = 0;
const char *propertyType = 0;
- if (value.userType() == QMetaType::QObjectStar) {
+ const int userType = value.userType();
+ if (userType == QMetaType::QObjectStar) {
if (QObject *o = *(QObject *const *)value.constData()) {
valueType = o->metaObject()->className();
@@ -346,11 +409,11 @@ bool QQmlBinding::write(const QQmlPropertyData &core,
if (!propertyMetaObject.isNull())
propertyType = propertyMetaObject.className();
}
- } else if (value.userType() != QVariant::Invalid) {
- if (value.userType() == QMetaType::VoidStar)
+ } else if (userType != QVariant::Invalid) {
+ if (userType == QMetaType::Nullptr || userType == QMetaType::VoidStar)
valueType = "null";
else
- valueType = QMetaType::typeName(value.userType());
+ valueType = QMetaType::typeName(userType);
}
if (!valueType)
@@ -378,11 +441,12 @@ QVariant QQmlBinding::evaluate()
bool isUndefined = false;
QV4::Scope scope(ep->v4engine());
- QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+ QV4::ScopedCallData callData(scope);
+ QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope);
ep->dereferenceScarceResources();
- return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >());
+ return scope.engine->toVariant(scope.result, qMetaTypeId<QList<QObject*> >());
}
QString QQmlBinding::expressionIdentifier()
@@ -395,8 +459,7 @@ QString QQmlBinding::expressionIdentifier()
QString url = function->sourceFile();
quint16 lineNumber = function->compiledFunction->location.line;
quint16 columnNumber = function->compiledFunction->location.column;
-
- return url + QLatin1Char(':') + QString::number(lineNumber) + QLatin1Char(':') + QString::number(columnNumber);
+ return url + QString::asprintf(":%u:%u", uint(lineNumber), uint(columnNumber));
}
void QQmlBinding::expressionChanged()
@@ -409,11 +472,17 @@ void QQmlBinding::refresh()
update();
}
-void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
{
setEnabledFlag(e);
setNotifyOnValueChanged(e);
+ m_nextBinding.setFlag2(); // Always use accessors, only not when:
+ if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
+ if (!m_targetIndex.isValid() || interceptorMetaObject->intercepts(m_targetIndex))
+ m_nextBinding.clearFlag2();
+ }
+
if (e)
update(flags);
}
@@ -427,29 +496,28 @@ QString QQmlBinding::expression() const
void QQmlBinding::setTarget(const QQmlProperty &prop)
{
- setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core);
+ auto pd = QQmlPropertyPrivate::get(prop);
+ setTarget(prop.object(), pd->core, &pd->valueTypeData);
}
-void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core)
+void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
{
m_target = object;
if (!object) {
- m_targetIndex = -1;
+ m_targetIndex = QQmlPropertyIndex();
return;
}
- QQmlPropertyData pd = core;
-
- while (pd.isAlias()) {
- int coreIndex = pd.coreIndex;
- int valueTypeIndex = pd.getValueTypeCoreIndex();
+ int coreIndex = core.coreIndex();
+ int valueTypeIndex = valueType ? valueType->coreIndex() : -1;
+ for (bool isAlias = core.isAlias(); isAlias; ) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
int aValueTypeIndex;
if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
m_target = 0;
- m_targetIndex = -1;
+ m_targetIndex = QQmlPropertyIndex();
return;
}
if (valueTypeIndex == -1)
@@ -458,25 +526,17 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core)
QQmlData *data = QQmlData::get(object, false);
if (!data || !data->propertyCache) {
m_target = 0;
- m_targetIndex = -1;
+ m_targetIndex = QQmlPropertyIndex();
return;
}
QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
Q_ASSERT(propertyData);
m_target = object;
- pd = *propertyData;
- if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(pd.propType);
- Q_ASSERT(valueTypeMetaObject);
- QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex);
- pd.setFlags(pd.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
- pd.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp);
- pd.valueTypePropType = vtProp.userType();
- pd.valueTypeCoreIndex = valueTypeIndex;
- }
+ isAlias = propertyData->isAlias();
+ coreIndex = propertyData->coreIndex();
}
- m_targetIndex = pd.encodedIndex();
+ m_targetIndex = QQmlPropertyIndex(coreIndex, valueTypeIndex);
QQmlData *data = QQmlData::get(*m_target, true);
if (!data->propertyCache) {
@@ -485,28 +545,110 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core)
}
}
-QQmlPropertyData QQmlBinding::getPropertyData() const
+void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
{
- int coreIndex;
- int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex);
+ Q_ASSERT(propertyData);
QQmlData *data = QQmlData::get(*m_target, false);
Q_ASSERT(data && data->propertyCache);
- QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
- Q_ASSERT(propertyData);
+ *propertyData = data->propertyCache->property(m_targetIndex.coreIndex());
+ Q_ASSERT(*propertyData);
- QQmlPropertyData d = *propertyData;
- if (Q_UNLIKELY(valueTypeIndex != -1)) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d.propType);
+ if (Q_UNLIKELY(m_targetIndex.hasValueTypeIndex() && valueTypeData)) {
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType((*propertyData)->propType());
Q_ASSERT(valueTypeMetaObject);
- QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex);
- d.setFlags(d.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
- d.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp);
- d.valueTypePropType = vtProp.userType();
- d.valueTypeCoreIndex = valueTypeIndex;
+ QMetaProperty vtProp = valueTypeMetaObject->property(m_targetIndex.valueTypeIndex());
+ valueTypeData->setFlags(QQmlPropertyData::flagsForProperty(vtProp));
+ valueTypeData->setPropType(vtProp.userType());
+ valueTypeData->setCoreIndex(m_targetIndex.valueTypeIndex());
+ }
+}
+
+class QObjectPointerBinding: public QQmlNonbindingBinding
+{
+ QQmlMetaObject targetMetaObject;
+
+public:
+ QObjectPointerBinding(QQmlEnginePrivate *engine, int propertyType)
+ : targetMetaObject(QQmlPropertyPrivate::rawMetaObjectForType(engine, propertyType))
+ {}
+
+protected:
+ Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags) Q_DECL_OVERRIDE Q_DECL_FINAL
+ {
+ QQmlPropertyData *pd;
+ QQmlPropertyData vtpd;
+ getPropertyData(&pd, &vtpd);
+ if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
+ return slowWrite(*pd, vtpd, result, isUndefined, flags);
+
+ // Check if the result is a QObject:
+ QObject *resultObject = nullptr;
+ QQmlMetaObject resultMo;
+ if (result.isNull()) {
+ // Special case: we can always write a nullptr. Don't bother checking anything else.
+ return pd->writeProperty(targetObject(), &resultObject, flags);
+ } else if (auto wrapper = result.as<QV4::QObjectWrapper>()) {
+ resultObject = wrapper->object();
+ if (!resultObject)
+ return pd->writeProperty(targetObject(), &resultObject, flags);
+ if (QQmlData *ddata = QQmlData::get(resultObject, false))
+ resultMo = ddata->propertyCache;
+ if (resultMo.isNull()) {
+ resultMo = resultObject->metaObject();
+ }
+ } else if (auto variant = result.as<QV4::VariantObject>()) {
+ QVariant value = variant->d()->data;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context());
+ resultMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, value.userType());
+ if (resultMo.isNull())
+ return slowWrite(*pd, vtpd, result, isUndefined, flags);
+ resultObject = *static_cast<QObject *const *>(value.constData());
+ } else {
+ return slowWrite(*pd, vtpd, result, isUndefined, flags);
+ }
+
+ // Compare & set:
+ if (QQmlMetaObject::canConvert(resultMo, targetMetaObject)) {
+ return pd->writeProperty(targetObject(), &resultObject, flags);
+ } else if (!resultObject && QQmlMetaObject::canConvert(targetMetaObject, resultMo)) {
+ // In the case of a null QObject, we assign the null if there is
+ // any change that the null variant type could be up or down cast to
+ // the property type.
+ return pd->writeProperty(targetObject(), &resultObject, flags);
+ } else {
+ return slowWrite(*pd, vtpd, result, isUndefined, flags);
+ }
+ }
+};
+
+QQmlBinding *QQmlBinding::newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property)
+{
+ if (property && property->isQObject())
+ return new QObjectPointerBinding(engine, property->propType());
+
+ const int type = (property && property->isFullyResolved()) ? property->propType() : QMetaType::UnknownType;
+
+ if (type == qMetaTypeId<QQmlBinding *>()) {
+ return new QQmlBindingBinding;
+ }
+
+ switch (type) {
+ case QMetaType::Bool:
+ return new GenericBinding<QMetaType::Bool>;
+ case QMetaType::Int:
+ return new GenericBinding<QMetaType::Int>;
+ case QMetaType::Double:
+ return new GenericBinding<QMetaType::Double>;
+ case QMetaType::Float:
+ return new GenericBinding<QMetaType::Float>;
+ case QMetaType::QString:
+ return new GenericBinding<QMetaType::QString>;
+ default:
+ return new GenericBinding<QMetaType::UnknownType>;
}
- return d;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 45c360f07e..6d42a8ea8a 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -72,24 +72,24 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
{
friend class QQmlAbstractBinding;
public:
- QQmlBinding(const QString &, QObject *, QQmlContext *);
- QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *);
- QQmlBinding(const QString &, QObject *, QQmlContextData *);
- QQmlBinding(const QString &, QObject *, QQmlContextData *,
- const QString &url, quint16 lineNumber, quint16 columnNumber);
- QQmlBinding(const QV4::Value &, QObject *, QQmlContextData *);
+ static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContext *);
+ static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *);
+ static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *);
+ static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *,
+ const QString &url, quint16 lineNumber, quint16 columnNumber);
+ static QQmlBinding *create(const QQmlPropertyData *, const QV4::Value &, QObject *, QQmlContextData *);
~QQmlBinding();
void setTarget(const QQmlProperty &);
- void setTarget(QObject *, const QQmlPropertyData &);
+ void setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
void setNotifyOnValueChanged(bool);
void refresh() Q_DECL_OVERRIDE;
- void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding) Q_DECL_OVERRIDE;
+ void setEnabled(bool, QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding) Q_DECL_OVERRIDE;
QString expression() const Q_DECL_OVERRIDE;
- void update(QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding);
+ void update(QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding);
typedef int Identifier;
enum {
@@ -101,17 +101,24 @@ public:
QString expressionIdentifier() Q_DECL_OVERRIDE;
void expressionChanged() Q_DECL_OVERRIDE;
+protected:
+ virtual void doUpdate(const DeleteWatcher &watcher,
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &scope,
+ const QV4::ScopedFunctionObject &f) = 0;
+
+ void getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const;
+ int getPropertyType() const;
+
+ bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
+ const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags);
+
private:
inline bool updatingFlag() const;
inline void setUpdatingFlag(bool);
inline bool enabledFlag() const;
inline void setEnabledFlag(bool);
- QQmlPropertyData getPropertyData() const;
-
- bool write(const QQmlPropertyData &core,
- const QV4::Value &result, bool isUndefined,
- QQmlPropertyPrivate::WriteFlags flags);
+ static QQmlBinding *newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property);
};
bool QQmlBinding::updatingFlag() const
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index f423a7d452..4e63790290 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -51,9 +51,9 @@
#include <private/qqmlprofiler_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
-#include <private/qqmlcompiler_p.h>
#include "qqmlinfo.h"
+#include <private/qjsvalue_p.h>
#include <private/qv4value_p.h>
#include <private/qv4qobjectwrapper_p.h>
@@ -80,8 +80,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
// Add some leading whitespace to account for the binding's column offset.
// It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
- function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2);
- function += QStringLiteral("(function ") + handlerName + QLatin1Char('(');
+ function += QString(qMax(column, (quint16)2) - 2, QChar(QChar::Space))
+ + QLatin1String("(function ") + handlerName + QLatin1Char('(');
if (parameterString.isEmpty()) {
QString error;
@@ -97,7 +97,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
} else
function += parameterString;
- function += QStringLiteral(") { ") + expression + QStringLiteral(" })");
+ function += QLatin1String(") { ") + expression + QLatin1String(" })");
m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line));
if (m_function.isNullOrUndefined())
@@ -206,10 +206,10 @@ void QQmlBoundSignalExpression::evaluate(void **a)
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QVarLengthArray<int, 9> dummy;
+ QQmlMetaObject::ArgTypeStorage storage;
//TODO: lookup via signal index rather than method index as an optimization
int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
- int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0);
+ int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, &storage, 0);
int argCount = argsTypes ? *argsTypes : 0;
QV4::ScopedCallData callData(scope, argCount);
@@ -218,7 +218,9 @@ void QQmlBoundSignalExpression::evaluate(void **a)
//### ideally we would use metaTypeToJS, however it currently gives different results
// for several cases (such as QVariant type and QObject-derived types)
//args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
- if (type == QMetaType::QVariant) {
+ if (type == qMetaTypeId<QJSValue>()) {
+ callData->args[ii] = *QJSValuePrivate::getValue(reinterpret_cast<QJSValue *>(a[ii + 1]));
+ } else if (type == QMetaType::QVariant) {
callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1]));
} else if (type == QMetaType::Int) {
//### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
@@ -235,7 +237,7 @@ void QQmlBoundSignalExpression::evaluate(void **a)
}
}
- QQmlJavaScriptExpression::evaluate(callData, 0);
+ QQmlJavaScriptExpression::evaluate(callData, 0, scope);
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
@@ -257,7 +259,7 @@ void QQmlBoundSignalExpression::evaluate(const QList<QVariant> &args)
callData->args[ii] = scope.engine->fromVariant(args[ii]);
}
- QQmlJavaScriptExpression::evaluate(callData, 0);
+ QQmlJavaScriptExpression::evaluate(callData, 0, scope);
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index 10c59b07c1..e940ca7401 100644
--- a/src/qml/qml/qqmlboundsignal_p.h
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -79,8 +79,8 @@ public:
QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction);
// inherited from QQmlJavaScriptExpression.
- virtual QString expressionIdentifier();
- virtual void expressionChanged();
+ QString expressionIdentifier() override;
+ void expressionChanged() override;
// evaluation of a bound signal expression doesn't return any value
void evaluate(void **a);
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
deleted file mode 100644
index b25792054c..0000000000
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qqmlcompiler_p.h"
-#include "qqmlengine.h"
-#include "qqmlcomponent.h"
-#include "qqmlcomponent_p.h"
-#include "qqmlcontext.h"
-#include "qqmlcontext_p.h"
-#include "qqmlpropertymap.h"
-#ifdef QML_THREADED_VME_INTERPRETER
-#include "qqmlvme_p.h"
-#endif
-
-#include <QtCore/qdebug.h>
-
-#include <private/qobject_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
-: engine(engine), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false)
-{
- Q_ASSERT(engine);
-}
-
-void QQmlCompiledData::destroy()
-{
- if (engine && hasEngine())
- QQmlEnginePrivate::deleteInEngineThread(engine, this);
- else
- delete this;
-}
-
-QQmlCompiledData::~QQmlCompiledData()
-{
- if (isRegisteredWithEngine)
- QQmlEnginePrivate::get(engine)->unregisterInternalCompositeType(this);
-
- clear();
-
- for (QHash<int, TypeReference*>::Iterator resolvedType = resolvedTypes.begin(), end = resolvedTypes.end();
- resolvedType != end; ++resolvedType) {
- if ((*resolvedType)->component)
- (*resolvedType)->component->release();
- if ((*resolvedType)->typePropertyCache)
- (*resolvedType)->typePropertyCache->release();
- }
- qDeleteAll(resolvedTypes);
- resolvedTypes.clear();
-}
-
-void QQmlCompiledData::clear()
-{
-}
-
-/*!
-Returns the property cache, if one alread exists. The cache is not referenced.
-*/
-QQmlPropertyCache *QQmlCompiledData::TypeReference::propertyCache() const
-{
- if (type)
- return typePropertyCache;
- else
- return component->compilationUnit->rootPropertyCache();
-}
-
-/*!
-Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
-*/
-QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngine *engine)
-{
- if (typePropertyCache) {
- return typePropertyCache;
- } else if (type) {
- typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type->metaObject());
- typePropertyCache->addref();
- return typePropertyCache;
- } else {
- return component->compilationUnit->rootPropertyCache();
- }
-}
-
-template <typename T>
-bool qtTypeInherits(const QMetaObject *mo) {
- while (mo) {
- if (mo == &T::staticMetaObject)
- return true;
- mo = mo->superClass();
- }
- return false;
-}
-
-void QQmlCompiledData::TypeReference::doDynamicTypeCheck()
-{
- const QMetaObject *mo = 0;
- if (typePropertyCache)
- mo = typePropertyCache->firstCppMetaObject();
- else if (type)
- mo = type->metaObject();
- else if (component)
- mo = component->compilationUnit->rootPropertyCache()->firstCppMetaObject();
- isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
-}
-
-void QQmlCompiledData::initialize(QQmlEngine *engine)
-{
- Q_ASSERT(!hasEngine());
- QQmlCleanup::addToEngine(engine);
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- if (compilationUnit && !compilationUnit->engine)
- compilationUnit->linkToEngine(v4);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
deleted file mode 100644
index 2c9e04d5e0..0000000000
--- a/src/qml/qml/qqmlcompiler_p.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-#ifndef QQMLCOMPILER_P_H
-#define QQMLCOMPILER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qqml.h"
-#include "qqmlerror.h"
-#include "qqmlengine_p.h"
-#include <private/qbitfield_p.h>
-#include "qqmlpropertycache_p.h"
-#include "qqmltypenamecache_p.h"
-#include "qqmltypeloader_p.h"
-#include "private/qv4identifier_p.h"
-#include <private/qqmljsastfwd_p.h>
-#include "qqmlcustomparser_p.h"
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qset.h>
-#include <QtCore/QCoreApplication>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace CompiledData {
-struct CompilationUnit;
-struct Unit;
-}
-}
-
-class QQmlEngine;
-class QQmlComponent;
-class QQmlContext;
-class QQmlContextData;
-
-// ### Merge with QV4::CompiledData::CompilationUnit
-class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup
-{
-public:
- QQmlCompiledData(QQmlEngine *engine);
- virtual ~QQmlCompiledData();
-
- QQmlEngine *engine;
-
- int metaTypeId;
- int listMetaTypeId;
- bool isRegisteredWithEngine;
-
- struct TypeReference
- {
- TypeReference()
- : type(0), typePropertyCache(0), component(0)
- , majorVersion(0)
- , minorVersion(0)
- , isFullyDynamicType(false)
- {}
-
- QQmlType *type;
- QQmlPropertyCache *typePropertyCache;
- QQmlCompiledData *component;
-
- int majorVersion;
- int minorVersion;
- // Types such as QQmlPropertyMap can add properties dynamically at run-time and
- // therefore cannot have a property cache installed when instantiated.
- bool isFullyDynamicType;
-
- QQmlPropertyCache *propertyCache() const;
- QQmlPropertyCache *createPropertyCache(QQmlEngine *);
-
- void doDynamicTypeCheck();
- };
- // map from name index
- QHash<int, TypeReference*> resolvedTypes;
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
-
- bool isInitialized() const { return hasEngine(); }
- void initialize(QQmlEngine *);
-
-protected:
- virtual void destroy(); // From QQmlRefCount
- virtual void clear(); // From QQmlCleanup
-
-private:
- QQmlCompiledData(const QQmlCompiledData &other);
- QQmlCompiledData &operator=(const QQmlCompiledData &other);
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLCOMPILER_P_H
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index eb4f590222..b78028dcf9 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -41,7 +41,6 @@
#include "qqmlcomponent_p.h"
#include "qqmlcomponentattached_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlcontext_p.h"
#include "qqmlengine_p.h"
#include "qqmlvme_p.h"
@@ -62,6 +61,7 @@
#include <private/qv4objectiterator_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <QDir>
#include <QStack>
#include <QStringList>
#include <QThreadStorage>
@@ -335,14 +335,11 @@ void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data)
{
url = data->finalUrl();
- QQmlCompiledData *c = data->compiledData();
+ compilationUnit = data->compilationUnit();
- if (!c) {
+ if (!compilationUnit) {
Q_ASSERT(data->isError());
state.errors = data->errors();
- } else {
- cc = c;
- cc->addref();
}
data->release();
@@ -356,10 +353,7 @@ void QQmlComponentPrivate::clear()
typeData = 0;
}
- if (cc) {
- cc->release();
- cc = 0;
- }
+ compilationUnit = nullptr;
}
/*!
@@ -382,7 +376,7 @@ QQmlComponent::~QQmlComponent()
if (isError()) {
qWarning() << "This may have been caused by one of the following errors:";
- foreach (const QQmlError &error, d->state.errors)
+ for (const QQmlError &error : qAsConst(d->state.errors))
qWarning().nospace().noquote() << QLatin1String(" ") << error;
}
@@ -393,8 +387,6 @@ QQmlComponent::~QQmlComponent()
d->typeData->unregisterCallback(d);
d->typeData->release();
}
- if (d->cc)
- d->cc->release();
}
/*!
@@ -422,7 +414,7 @@ QQmlComponent::Status QQmlComponent::status() const
return Loading;
else if (!d->state.errors.isEmpty())
return Error;
- else if (d->engine && d->cc)
+ else if (d->engine && d->compilationUnit)
return Ready;
else
return Null;
@@ -558,20 +550,20 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode);
+ const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : d->engine->baseUrl().resolved(QUrl(fileName));
+ d->loadUrl(url, mode);
}
/*!
\internal
*/
-QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent)
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::CompiledData::CompilationUnit *compilationUnit, int start, QObject *parent)
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- d->cc = cc;
- cc->addref();
+ d->compilationUnit = compilationUnit;
d->start = start;
- d->url = cc->compilationUnit->url();
+ d->url = compilationUnit->url();
d->progress = 1.0;
}
@@ -717,7 +709,7 @@ QString QQmlComponent::errorString() const
QString ret;
if(!isError())
return ret;
- foreach(const QQmlError &e, d->state.errors) {
+ for (const QQmlError &e : d->state.errors) {
ret += e.url().toString() + QLatin1Char(':') +
QString::number(e.line()) + QLatin1Char(' ') +
e.description() + QLatin1Char('\n');
@@ -864,7 +856,7 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
enginePriv->referenceScarceResources();
QObject *rv = 0;
- state.creator.reset(new QQmlObjectCreator(context, cc, creationContext));
+ state.creator.reset(new QQmlObjectCreator(context, compilationUnit, creationContext));
rv = state.creator->create(start);
if (!rv)
state.errors = state.creator->errors;
@@ -884,11 +876,13 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
depthIncreased = false;
}
- QQmlEngineDebugService *service = QQmlDebugConnector::service<QQmlEngineDebugService>();
- if (service && rv) {
- if (!context->isInternal)
- context->asQQmlContextPrivate()->instances.append(rv);
- service->objectCreated(engine, rv);
+ if (rv) {
+ if (QQmlEngineDebugService *service =
+ QQmlDebugConnector::service<QQmlEngineDebugService>()) {
+ if (!context->isInternal)
+ context->asQQmlContextPrivate()->instances.append(rv);
+ service->objectCreated(engine, rv);
+ }
}
return rv;
@@ -905,7 +899,7 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
Q_ASSERT(ddata->deferredData);
QQmlData::DeferredData *deferredData = ddata->deferredData;
QQmlContextData *creationContext = 0;
- state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compiledData, creationContext));
+ state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compilationUnit, creationContext));
if (!state->creator->populateDeferredProperties(object))
state->errors << state->creator->errors;
}
@@ -1049,9 +1043,9 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
- p->compiledData = d->cc;
- p->compiledData->addref();
- p->creator.reset(new QQmlObjectCreator(contextData, d->cc, d->creationContext, p.data()));
+ p->compilationUnit = d->compilationUnit;
+ p->enginePriv = enginePriv;
+ p->creator.reset(new QQmlObjectCreator(contextData, d->compilationUnit, d->creationContext, p.data()));
p->subComponentToCreate = d->start;
enginePriv->incubate(incubator, forContextData);
@@ -1065,8 +1059,9 @@ namespace Heap {
struct QmlIncubatorObject : Object {
QmlIncubatorObject(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
+ ~QmlIncubatorObject() { parent.destroy(); }
QScopedPointer<QQmlComponentIncubator> incubator;
- QPointer<QObject> parent;
+ QQmlQPointer<QObject> parent;
QV4::Value valuemap;
QV4::Value statusChanged;
Pointer<Heap::QmlContext> qmlContext;
@@ -1103,13 +1098,13 @@ public:
, incubatorObject(inc)
{}
- virtual void statusChanged(Status s) {
+ void statusChanged(Status s) override {
QV4::Scope scope(incubatorObject->internalClass->engine);
QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject);
i->statusChanged(s);
}
- virtual void setInitialState(QObject *o) {
+ void setInitialState(QObject *o) override {
QV4::Scope scope(incubatorObject->internalClass->engine);
QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject);
i->setInitialState(o);
@@ -1143,7 +1138,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
}
/*!
- \qmlmethod object Component::createObject(Item parent, object properties)
+ \qmlmethod object Component::createObject(QtObject parent, object properties)
Creates and returns an object instance of this component that will have
the given \a parent and \a properties. The \a properties argument is optional.
@@ -1184,7 +1179,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
*/
-static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v)
+void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v)
{
QV4::Scope scope(engine);
QV4::ScopedObject object(scope);
@@ -1273,7 +1268,7 @@ void QQmlComponent::createObject(QQmlV4Function *args)
if (!valuemap->isUndefined()) {
QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext());
- setInitialProperties(v4, qmlContext, object, valuemap);
+ QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap);
}
d->completeCreate();
@@ -1492,8 +1487,9 @@ QQmlComponentExtension::~QQmlComponentExtension()
QV4::Heap::QmlIncubatorObject::QmlIncubatorObject(QQmlIncubator::IncubationMode m)
: valuemap(QV4::Primitive::undefinedValue())
, statusChanged(QV4::Primitive::undefinedValue())
- , qmlContext(0)
{
+ parent.init();
+ qmlContext = nullptr;
incubator.reset(new QQmlComponentIncubator(this, m));
}
@@ -1506,7 +1502,7 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o)
QV4::Scope scope(v4);
QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o));
QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext);
- setInitialProperties(v4, qmlCtxt, obj, d()->valuemap);
+ QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap);
}
}
@@ -1537,7 +1533,7 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QV4::ScopedCallData callData(scope, 1);
callData->thisObject = this;
callData->args[0] = QV4::Primitive::fromUInt32(s);
- f->call(callData);
+ f->call(scope, callData);
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error);
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index aefbf20aff..ca60f01eb5 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -55,10 +55,15 @@ class QQmlEngine;
class QQmlComponent;
class QQmlIncubator;
class QQmlV4Function;
-class QQmlCompiledData;
class QQmlComponentPrivate;
class QQmlComponentAttached;
+namespace QV4 {
+namespace CompiledData {
+struct CompilationUnit;
+}
+}
+
class Q_QML_EXPORT QQmlComponent : public QObject
{
Q_OBJECT
@@ -122,7 +127,7 @@ protected:
Q_INVOKABLE void incubateObject(QQmlV4Function *);
private:
- QQmlComponent(QQmlEngine *, QQmlCompiledData *, int, QObject *parent);
+ QQmlComponent(QQmlEngine *, QV4::CompiledData::CompilationUnit *compilationUnit, int, QObject *parent);
Q_DISABLE_COPY(QQmlComponent)
friend class QQmlTypeData;
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 039b267433..d01a987acc 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -71,7 +71,6 @@ QT_BEGIN_NAMESPACE
class QQmlComponent;
class QQmlEngine;
-class QQmlCompiledData;
class QQmlComponentAttached;
class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback
@@ -80,17 +79,18 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public
public:
QQmlComponentPrivate()
- : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), depthIncreased(false) {}
+ : typeData(0), progress(0.), start(-1), engine(0), creationContext(0), depthIncreased(false) {}
void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
QObject *beginCreate(QQmlContextData *);
void completeCreate();
void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate);
+ static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v);
QQmlTypeData *typeData;
- virtual void typeDataReady(QQmlTypeData *);
- virtual void typeDataProgress(QQmlTypeData *, qreal);
+ void typeDataReady(QQmlTypeData *) override;
+ void typeDataProgress(QQmlTypeData *, qreal) override;
void fromTypeData(QQmlTypeData *data);
@@ -98,7 +98,7 @@ public:
qreal progress;
int start;
- QQmlCompiledData *cc;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
struct ConstructionState {
ConstructionState()
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index b3081ddbe6..018841b9b1 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -383,7 +383,7 @@ QVariant QQmlContext::contextProperty(const QString &name) const
QQmlPropertyData *property =
QQmlPropertyCache::property(data->engine, obj, name, data, local);
- if (property) value = obj->metaObject()->property(property->coreIndex).read(obj);
+ if (property) value = obj->metaObject()->property(property->coreIndex()).read(obj);
}
if (!value.isValid() && parentContext())
value = parentContext()->contextProperty(name);
@@ -524,7 +524,7 @@ QQmlContextData::QQmlContextData(QQmlContext *ctxt)
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
publicContext(ctxt), activeVMEData(0), componentObjectIndex(-1),
- contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ contextObject(0), childContexts(0), nextChild(0), prevChild(0),
expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
componentAttached(0)
{
@@ -628,9 +628,6 @@ void QQmlContextData::destroy()
}
contextGuards = 0;
- if (imports)
- imports->release();
-
delete [] idValues;
if (isInternal)
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index 05ce39401e..62cd3d4877 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -174,7 +174,7 @@ public:
QString urlString() const;
// List of imports that apply to this context
- QQmlTypeNameCache *imports;
+ QQmlRefPointer<QQmlTypeNameCache> imports;
// My children
QQmlContextData *childContexts;
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index 2d0ebad764..13d708bc17 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -66,14 +66,15 @@ Heap::QmlContextWrapper::QmlContextWrapper(QQmlContextData *context, QObject *sc
, ownsContext(ownsContext)
, isNullWrapper(false)
, context(context)
- , scopeObject(scopeObject)
{
+ this->scopeObject.init(scopeObject);
}
Heap::QmlContextWrapper::~QmlContextWrapper()
{
if (context && ownsContext)
context->destroy();
+ scopeObject.destroy();
}
ReturnedValue QmlContextWrapper::qmlScope(ExecutionEngine *v4, QQmlContextData *ctxt, QObject *scope)
diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h
index ca7fcf1d75..2b8c16f274 100644
--- a/src/qml/qml/qqmlcontextwrapper_p.h
+++ b/src/qml/qml/qqmlcontextwrapper_p.h
@@ -71,7 +71,7 @@ struct QmlContextWrapper : Object {
bool isNullWrapper;
QQmlGuardedContextData context;
- QPointer<QObject> scopeObject;
+ QQmlQPointer<QObject> scopeObject;
};
}
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 134002cf33..85c91a592a 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -39,7 +39,6 @@
#include "qqmlcustomparser_p.h"
-#include "qqmlcompiler_p.h"
#include <private/qqmltypecompiler_p.h>
#include <QtCore/qdebug.h>
@@ -101,11 +100,7 @@ void QQmlCustomParser::clearErrors()
*/
void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
- QQmlError error;
- error.setLine(location.line);
- error.setColumn(location.column);
- error.setDescription(description);
- exceptions << error;
+ exceptions << QQmlCompileError(location, description);
}
struct StaticQtMetaObject : public QObject
@@ -166,11 +161,13 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
*/
const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
{
+ if (!imports.isT1())
+ return nullptr;
QQmlType *qmltype = 0;
- if (!validator->imports().resolveType(name, &qmltype, 0, 0, 0))
- return 0;
+ if (!imports.asT1()->resolveType(name, &qmltype, 0, 0, 0))
+ return nullptr;
if (!qmltype)
- return 0;
+ return nullptr;
return qmltype->metaObject();
}
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 9aa052c1ad..5eb409990d 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -54,13 +54,13 @@
#include "qqmlmetatype_p.h"
#include "qqmlerror.h"
#include "qqmlbinding_p.h"
+#include <private/qqmltypecompiler_p.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qxmlstream.h>
QT_BEGIN_NAMESPACE
-class QQmlCompiledData;
class QQmlPropertyValidator;
class QQmlEnginePrivate;
@@ -84,7 +84,7 @@ public:
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
- QList<QQmlError> errors() const { return exceptions; }
+ QVector<QQmlCompileError> errors() const { return exceptions; }
protected:
void error(const QV4::CompiledData::Binding *binding, const QString& description)
@@ -98,7 +98,7 @@ protected:
const QMetaObject *resolveType(const QString&) const;
private:
- QList<QQmlError> exceptions;
+ QVector<QQmlCompileError> exceptions;
QQmlEnginePrivate *engine;
const QQmlPropertyValidator *validator;
Flags m_flags;
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index ad2456a68d..dce75c51aa 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -53,7 +53,7 @@
#include <private/qtqmlglobal_p.h>
#include <private/qobject_p.h>
-
+#include <private/qqmlpropertyindex_p.h>
#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
#include <qjsengine.h>
@@ -63,7 +63,6 @@ QT_BEGIN_NAMESPACE
template <class Key, class T> class QHash;
class QQmlEngine;
class QQmlGuardImpl;
-class QQmlCompiledData;
class QQmlAbstractBinding;
class QQmlBoundSignal;
class QQmlContext;
@@ -72,6 +71,13 @@ class QQmlContextData;
class QQmlNotifier;
class QQmlDataExtended;
class QQmlNotifierEndpoint;
+
+namespace QV4 {
+namespace CompiledData {
+struct CompilationUnit;
+}
+}
+
// This class is structured in such a way, that simply zero'ing it is the
// default state for elemental object allocations. This is crucial in the
// workings of the QQmlInstruction::CreateSimpleObject instruction.
@@ -123,14 +129,16 @@ public:
quint32 parentFrozen:1;
quint32 dummy:21;
- // When bindingBitsSize < 32, we store the binding bit flags inside
- // bindingBitsValue. When we need more than 32 bits, we allocated
+ // When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside
+ // bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated
// sufficient space and use bindingBits to point to it.
int bindingBitsSize;
+ typedef quintptr BindingBitsType;
union {
- quint32 *bindingBits;
- quint32 bindingBitsValue;
+ BindingBitsType *bindingBits;
+ BindingBitsType bindingBitsValue;
};
+ enum { MaxInlineBits = sizeof(BindingBitsType) * 8 };
struct NotifyList {
quint64 connectionMask;
@@ -168,7 +176,7 @@ public:
void clearBindingBit(int);
void setBindingBit(QObject *obj, int);
- inline bool hasPendingBindingBit(int) const;
+ inline bool hasPendingBindingBit(int index) const;
void setPendingBindingBit(QObject *obj, int);
void clearPendingBindingBit(int);
@@ -179,10 +187,10 @@ public:
struct DeferredData {
unsigned int deferredIdx;
- QQmlCompiledData *compiledData;//Not always the same as the other compiledData
+ QV4::CompiledData::CompilationUnit *compilationUnit;//Not always the same as the other compilation unit
QQmlContextData *context;//Could be either context or outerContext
};
- QQmlCompiledData *compiledData;
+ QV4::CompiledData::CompilationUnit *compilationUnit;
DeferredData *deferredData;
QV4::WeakValue jsWrapper;
@@ -221,15 +229,26 @@ public:
static void markAsDeleted(QObject *);
static void setQueuedForDeletion(QObject *);
- static inline void flushPendingBinding(QObject *, int coreIndex);
+ static inline void flushPendingBinding(QObject *, QQmlPropertyIndex propertyIndex);
- static void ensurePropertyCache(QJSEngine *engine, QObject *object);
+ static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object);
private:
// For attachedProperties
mutable QQmlDataExtended *extendedData;
- void flushPendingBindingImpl(int coreIndex);
+ void flushPendingBindingImpl(QQmlPropertyIndex index);
+
+ Q_ALWAYS_INLINE bool hasBitSet(int bit) const
+ {
+ if (bindingBitsSize <= bit)
+ return false;
+
+ if (bindingBitsSize == MaxInlineBits)
+ return bindingBitsValue & (BindingBitsType(1) << bit);
+ else
+ return bindingBits[bit / MaxInlineBits] & (BindingBitsType(1) << (bit % MaxInlineBits));
+ }
};
bool QQmlData::wasDeleted(QObject *object)
@@ -275,27 +294,25 @@ inline bool QQmlData::signalHasEndpoint(int index) const
bool QQmlData::hasBindingBit(int coreIndex) const
{
- int bit = coreIndex * 2;
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
- return bindingBitsSize > bit &&
- ((bindingBitsSize == 32) ? (bindingBitsValue & (1 << bit)) :
- (bindingBits[bit / 32] & (1 << (bit % 32))));
+ return hasBitSet(coreIndex * 2);
}
bool QQmlData::hasPendingBindingBit(int coreIndex) const
{
- int bit = coreIndex * 2 + 1;
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
- return bindingBitsSize > bit &&
- ((bindingBitsSize == 32) ? (bindingBitsValue & (1 << bit)) :
- (bindingBits[bit / 32] & (1 << (bit % 32))));
+ return hasBitSet(coreIndex * 2 + 1);
}
-void QQmlData::flushPendingBinding(QObject *o, int coreIndex)
+void QQmlData::flushPendingBinding(QObject *o, QQmlPropertyIndex propertyIndex)
{
QQmlData *data = QQmlData::get(o, false);
- if (data && data->hasPendingBindingBit(coreIndex))
- data->flushPendingBindingImpl(coreIndex);
+ if (data && data->hasPendingBindingBit(propertyIndex.coreIndex()))
+ data->flushPendingBindingImpl(propertyIndex);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index b3a0baffb4..d10a8c7718 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -74,7 +74,7 @@ void QQmlDelayedCallQueue::DelayedFunctionCall::execute(QV4::ExecutionEngine *en
const QV4::FunctionObject *callback = m_function.as<QV4::FunctionObject>();
Q_ASSERT(callback);
- callback->call(callData);
+ callback->call(scope, callData);
if (scope.engine->hasException) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index fd1795499e..daa12fae26 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -42,7 +42,6 @@
#include "qqmlcomponentattached_p.h"
#include "qqmlcontext_p.h"
-#include "qqmlcompiler_p.h"
#include "qqml.h"
#include "qqmlcontext.h"
#include "qqmlexpression.h"
@@ -58,7 +57,6 @@
#include "qqmllist_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmlnotifier_p.h"
-#include <private/qqmldebugconnector_p.h>
#include "qqmlincubator.h"
#include "qqmlabstracturlinterceptor.h"
#include <private/qqmlboundsignal_p.h>
@@ -91,6 +89,7 @@
#include <private/qqmlobjectmodel_p.h>
#include <private/qquickworkerscript_p.h>
#include <private/qqmlinstantiator_p.h>
+#include <private/qqmlloggingcategory_p.h>
#ifdef Q_OS_WIN // for %APPDATA%
# include <qt_windows.h>
@@ -107,6 +106,9 @@ Q_DECLARE_METATYPE(QQmlProperty)
QT_BEGIN_NAMESPACE
+typedef QQmlData::BindingBitsType BindingBitsType;
+enum { MaxInlineBits = QQmlData::MaxInlineBits };
+
void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
{
QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor);
@@ -114,6 +116,39 @@ void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
QQmlValueTypeFactory::registerValueTypes(uri, versionMajor, versionMinor);
}
+// Declared in qqml.h
+int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
+ const char *uri, int versionMajor,
+ int versionMinor, const char *qmlName,
+ const QString& reason)
+{
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ 0,
+ 0,
+ 0,
+ Q_NULLPTR,
+ reason,
+
+ uri, versionMajor, versionMinor, qmlName, &staticMetaObject,
+
+ QQmlAttachedPropertiesFunc(),
+ Q_NULLPTR,
+
+ 0,
+ 0,
+ 0,
+
+ Q_NULLPTR, Q_NULLPTR,
+
+ Q_NULLPTR,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
/*!
\qmltype QtObject
\instantiates QObject
@@ -186,6 +221,7 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1
qmlRegisterCustomType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections", new QQmlConnectionsParser);
qmlRegisterType<QQmlInstanceModel>();
+ qmlRegisterType<QQmlLoggingCategory>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "LoggingCategory"); //Only available in >=2.8
}
@@ -404,11 +440,10 @@ The following functions are also on the Qt object.
\li \c "ios" - iOS
\li \c "tvos" - tvOS
\li \c "linux" - Linux
- \li \c "osx" - OS X
+ \li \c "osx" - \macos
\li \c "unix" - Other Unix-based OS
\li \c "windows" - Windows
- \li \c "wince" - Windows CE
- \li \c "winrt" - Windows RT
+ \li \c "winrt" - Windows Runtime
\li \c "winphone" - Windows Phone
\endlist
\endtable
@@ -519,6 +554,18 @@ The following functions are also on the Qt object.
\li This read-only property can be used to determine whether or not the
platform supports multiple windows. Some embedded platforms do not support
multiple windows, for example.
+
+ \row
+ \li \c application.screens
+ \li An array containing the descriptions of all connected screens. The
+ elements of the array are objects with the same properties as the
+ \l{Screen} attached object. In practice the array corresponds to the screen
+ list returned by QGuiApplication::screens(). In addition to examining
+ properties like name, width, height, etc., the array elements can also be
+ assigned to the targetScreen property of Window items, thus serving as an
+ alternative to the C++ side's QWindow::setScreen(). This property has been
+ added in Qt 5.9.
+
\endtable
The object also has one signal, aboutToQuit(), which is the same as \l QCoreApplication::aboutToQuit().
@@ -535,6 +582,8 @@ The following functions are also on the Qt object.
\li application.layoutDirection
\li application.font
\endlist
+
+ \sa Screen, Window, Window.targetScreen
*/
/*!
@@ -604,7 +653,10 @@ the same object as is returned from the Qt.include() call.
QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
: propertyCapture(0), rootContext(0),
- profiler(0), outputWarningsToMsgLog(true),
+#ifndef QT_NO_QML_DEBUGGER
+ profiler(0),
+#endif
+ outputWarningsToMsgLog(true),
cleanup(0), erroredBindings(0), inProgressCreations(0),
workerScriptEngine(0),
activeObjectCreator(0),
@@ -619,7 +671,6 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
QQmlEnginePrivate::~QQmlEnginePrivate()
{
typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt;
- typedef QHash<int, QQmlCompiledData *>::const_iterator CompositeTypesIt;
if (inProgressCreations)
qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
@@ -640,7 +691,7 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
for (TypePropertyCacheIt iter = typePropertyCache.cbegin(), end = typePropertyCache.cend(); iter != end; ++iter)
(*iter)->release();
- for (CompositeTypesIt iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) {
+ for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) {
iter.value()->isRegisteredWithEngine = false;
// since unregisterInternalCompositeType() will not be called in this
@@ -648,12 +699,9 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
QMetaType::unregisterType(iter.value()->metaTypeId);
QMetaType::unregisterType(iter.value()->listMetaTypeId);
}
+#ifndef QT_NO_QML_DEBUGGER
delete profiler;
-}
-
-void QQmlEnginePrivate::enableProfiler()
-{
- profiler = new QQmlProfiler();
+#endif
}
void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
@@ -680,9 +728,10 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
QQmlData::QQmlData()
: ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
- hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0),
+ hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
+ bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0), context(0), outerContext(0),
bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0),
- lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0),
+ lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), deferredData(0),
propertyCache(0), guards(0), extendedData(0)
{
init();
@@ -840,18 +889,20 @@ void QQmlData::setQueuedForDeletion(QObject *object)
}
}
-void QQmlData::flushPendingBindingImpl(int coreIndex)
+void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index)
{
- clearPendingBindingBit(coreIndex);
+ clearPendingBindingBit(index.coreIndex());
// Find the binding
QQmlAbstractBinding *b = bindings;
- while (b && b->targetPropertyIndex() != coreIndex)
+ while (b && (b->targetPropertyIndex().coreIndex() != index.coreIndex() ||
+ b->targetPropertyIndex().hasValueTypeIndex()))
b = b->nextBinding();
- if (b && b->targetPropertyIndex() == coreIndex)
- b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::DontRemoveBinding);
+ if (b && b->targetPropertyIndex().coreIndex() == index.coreIndex() &&
+ !b->targetPropertyIndex().hasValueTypeIndex())
+ b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::DontRemoveBinding);
}
bool QQmlEnginePrivate::baseModulesUninitialized = true;
@@ -969,8 +1020,8 @@ QQmlEngine::~QQmlEngine()
// we do this here and not in the private dtor since otherwise a crash can
// occur (if we are the QObject parent of the QObject singleton instance)
// XXX TODO: performance -- store list of singleton types separately?
- QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes();
- foreach (QQmlType *currType, singletonTypes)
+ const QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes();
+ for (QQmlType *currType : singletonTypes)
currType->singletonInstanceInfo()->destroy(this);
delete d->rootContext;
@@ -979,8 +1030,19 @@ QQmlEngine::~QQmlEngine()
/*! \fn void QQmlEngine::quit()
This signal is emitted when the QML loaded by the engine would like to quit.
+
+ \sa exit()
*/
+/*! \fn void QQmlEngine::exit(int retCode)
+ This signal is emitted when the QML loaded by the engine would like to exit
+ from the event loop with the specified return code.
+
+ \since 5.8
+ \sa quit()
+ */
+
+
/*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
This signal is emitted when \a warnings messages are generated by QML.
*/
@@ -1411,7 +1473,7 @@ void qmlExecuteDeferred(QObject *object)
QQmlComponentPrivate::beginDeferred(ep, object, &state);
// Release the reference for the deferral action (we still have one from construction)
- data->deferredData->compiledData->release();
+ data->deferredData->compilationUnit->release();
delete data->deferredData;
data->deferredData = 0;
@@ -1642,13 +1704,13 @@ void QQmlData::destroyed(QObject *object)
if (bindings && !bindings->ref.deref())
delete bindings;
- if (compiledData) {
- compiledData->release();
- compiledData = 0;
+ if (compilationUnit) {
+ compilationUnit->release();
+ compilationUnit = 0;
}
if (deferredData) {
- deferredData->compiledData->release();
+ deferredData->compilationUnit->release();
delete deferredData;
deferredData = 0;
}
@@ -1671,7 +1733,7 @@ void QQmlData::destroyed(QObject *object)
QString source = expr->expression();
if (source.size() > 100) {
source.truncate(96);
- source.append(QStringLiteral(" ..."));
+ source.append(QLatin1String(" ..."));
}
locationString.append(source);
} else {
@@ -1691,7 +1753,7 @@ void QQmlData::destroyed(QObject *object)
signalHandler = next;
}
- if (bindingBitsSize > 32)
+ if (bindingBitsSize > MaxInlineBits)
free(bindingBits);
if (propertyCache)
@@ -1716,6 +1778,8 @@ void QQmlData::destroyed(QObject *object)
if (ownMemory)
delete this;
+ else
+ this->~QQmlData();
}
DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
@@ -1739,31 +1803,27 @@ void QQmlData::parentChanged(QObject *object, QObject *parent)
static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit)
{
- if (data->bindingBitsSize == 0 && bit < 32) {
- data->bindingBitsSize = 32;
- }
-
- if (data->bindingBitsSize <= bit) {
+ if (Q_UNLIKELY(data->bindingBitsSize <= bit)) {
int props = QQmlMetaObject(obj).propertyCount();
Q_ASSERT(bit < 2 * props);
- int arraySize = (2 * props + 31) / 32;
+ int arraySize = (2 * props + MaxInlineBits - 1) / MaxInlineBits;
Q_ASSERT(arraySize > 1);
// special handling for 32 here is to make sure we wipe the first byte
// when going from bindingBitsValue to bindingBits, and preserve the old
// set bits so we can restore them after the allocation
- int oldArraySize = data->bindingBitsSize > 32 ? data->bindingBitsSize / 32 : 0;
- quint32 oldValue = data->bindingBitsSize == 32 ? data->bindingBitsValue : 0;
+ int oldArraySize = data->bindingBitsSize > MaxInlineBits ? data->bindingBitsSize / MaxInlineBits : 0;
+ quintptr oldValue = data->bindingBitsSize == MaxInlineBits ? data->bindingBitsValue : 0;
- data->bindingBits = (quint32 *)realloc((data->bindingBitsSize == 32) ? 0 : data->bindingBits,
- arraySize * sizeof(quint32));
+ data->bindingBits = static_cast<BindingBitsType *>(realloc((data->bindingBitsSize == MaxInlineBits) ? 0 : data->bindingBits,
+ arraySize * sizeof(BindingBitsType)));
memset(data->bindingBits + oldArraySize,
0x00,
- sizeof(quint32) * (arraySize - oldArraySize));
+ sizeof(BindingBitsType) * (arraySize - oldArraySize));
- data->bindingBitsSize = arraySize * 32;
+ data->bindingBitsSize = arraySize * MaxInlineBits;
// reinstate bindingBitsValue after we dropped it
if (oldValue) {
@@ -1771,50 +1831,60 @@ static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit)
}
}
- if (data->bindingBitsSize == 32)
- data->bindingBitsValue |= (1 << (bit % 32));
+ if (data->bindingBitsSize == MaxInlineBits)
+ data->bindingBitsValue |= BindingBitsType(1) << bit;
else
- data->bindingBits[bit / 32] |= (1 << (bit % 32));
+ data->bindingBits[bit / MaxInlineBits] |= (BindingBitsType(1) << (bit % MaxInlineBits));
}
static void QQmlData_clearBit(QQmlData *data, int bit)
{
if (data->bindingBitsSize > bit) {
- if (data->bindingBitsSize == 32)
- data->bindingBitsValue &= ~(1 << (bit % 32));
+ if (data->bindingBitsSize == MaxInlineBits)
+ data->bindingBitsValue &= ~(BindingBitsType(1) << (bit % MaxInlineBits));
else
- data->bindingBits[bit / 32] &= ~(1 << (bit % 32));
+ data->bindingBits[bit / MaxInlineBits] &= ~(BindingBitsType(1) << (bit % MaxInlineBits));
}
}
void QQmlData::clearBindingBit(int coreIndex)
{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
QQmlData_clearBit(this, coreIndex * 2);
}
void QQmlData::setBindingBit(QObject *obj, int coreIndex)
{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
QQmlData_setBit(this, obj, coreIndex * 2);
}
void QQmlData::clearPendingBindingBit(int coreIndex)
{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
QQmlData_clearBit(this, coreIndex * 2 + 1);
}
void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
QQmlData_setBit(this, obj, coreIndex * 2 + 1);
}
-void QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object)
+QQmlPropertyCache *QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object)
{
Q_ASSERT(engine);
QQmlData *ddata = QQmlData::get(object, /*create*/true);
- if (ddata->propertyCache)
- return;
- ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object);
- if (ddata->propertyCache) ddata->propertyCache->addref();
+ if (!ddata->propertyCache) {
+ ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object);
+ if (ddata->propertyCache)
+ ddata->propertyCache->addref();
+ }
+ return ddata->propertyCache;
}
void QQmlEnginePrivate::sendQuit()
@@ -1826,6 +1896,14 @@ void QQmlEnginePrivate::sendQuit()
}
}
+void QQmlEnginePrivate::sendExit(int retCode)
+{
+ Q_Q(QQmlEngine);
+ if (q->receivers(SIGNAL(exit(int))) == 0)
+ qWarning("Signal QQmlEngine::exit() emitted, but no receivers connected to handle it.");
+ emit q->exit(retCode);
+}
+
static void dumpwarning(const QQmlError &error)
{
QMessageLogger(error.url().toString().toLatin1().constData(),
@@ -2225,9 +2303,9 @@ int QQmlEnginePrivate::listType(int t) const
QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
{
Locker locker(this);
- QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t);
+ auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->compilationUnit->rootPropertyCache());
+ return QQmlMetaObject((*iter)->rootPropertyCache());
} else {
QQmlType *type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type?type->baseMetaObject():0);
@@ -2237,9 +2315,9 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
{
Locker locker(this);
- QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t);
+ auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->compilationUnit->rootPropertyCache());
+ return QQmlMetaObject((*iter)->rootPropertyCache());
} else {
QQmlType *type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type?type->metaObject():0);
@@ -2249,9 +2327,9 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
{
Locker locker(this);
- QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t);
+ auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return (*iter)->compilationUnit->rootPropertyCache();
+ return (*iter)->rootPropertyCache();
} else {
QQmlType *type = QQmlMetaType::qmlType(t);
locker.unlock();
@@ -2262,9 +2340,9 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
{
Locker locker(this);
- QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t);
+ auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return (*iter)->compilationUnit->rootPropertyCache();
+ return (*iter)->rootPropertyCache();
} else {
QQmlType *type = QQmlMetaType::qmlType(t);
locker.unlock();
@@ -2272,9 +2350,9 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
}
}
-void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data)
+void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
{
- QByteArray name = data->compilationUnit->rootPropertyCache()->className();
+ QByteArray name = compilationUnit->rootPropertyCache()->className();
QByteArray ptr = name + '*';
QByteArray lst = "QQmlListProperty<" + name + '>';
@@ -2292,21 +2370,21 @@ void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data)
static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
static_cast<QMetaObject*>(0));
- data->metaTypeId = ptr_type;
- data->listMetaTypeId = lst_type;
- data->isRegisteredWithEngine = true;
+ compilationUnit->metaTypeId = ptr_type;
+ compilationUnit->listMetaTypeId = lst_type;
+ compilationUnit->isRegisteredWithEngine = true;
Locker locker(this);
m_qmlLists.insert(lst_type, ptr_type);
// The QQmlCompiledData is not referenced here, but it is removed from this
// hash in the QQmlCompiledData destructor
- m_compositeTypes.insert(ptr_type, data);
+ m_compositeTypes.insert(ptr_type, compilationUnit);
}
-void QQmlEnginePrivate::unregisterInternalCompositeType(QQmlCompiledData *data)
+void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
{
- int ptr_type = data->metaTypeId;
- int lst_type = data->listMetaTypeId;
+ int ptr_type = compilationUnit->metaTypeId;
+ int lst_type = compilationUnit->listMetaTypeId;
Locker locker(this);
m_qmlLists.remove(lst_type);
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 132af78f80..3111d1013e 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -151,10 +151,11 @@ public:
static ObjectOwnership objectOwnership(QObject *);
protected:
QQmlEngine(QQmlEnginePrivate &dd, QObject *p);
- virtual bool event(QEvent *);
+ bool event(QEvent *) override;
Q_SIGNALS:
void quit();
+ void exit(int retCode);
void warnings(const QList<QQmlError> &warnings);
private:
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 18bee387dd..713b03dbf3 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -134,8 +134,12 @@ public:
QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
QQmlContext *rootContext;
+
+#ifdef QT_NO_QML_DEBUGGER
+ static const quintptr profiler = 0;
+#else
QQmlProfiler *profiler;
- void enableProfiler();
+#endif
bool outputWarningsToMsgLog;
@@ -216,13 +220,14 @@ public:
QQmlMetaObject metaObjectForType(int) const;
QQmlPropertyCache *propertyCacheForType(int);
QQmlPropertyCache *rawPropertyCacheForType(int);
- void registerInternalCompositeType(QQmlCompiledData *);
- void unregisterInternalCompositeType(QQmlCompiledData *);
+ void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit);
+ void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit);
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
void sendQuit();
+ void sendExit(int retCode = 0);
void warning(const QQmlError &);
void warning(const QList<QQmlError> &);
void warning(QQmlDelayedError *);
@@ -260,7 +265,7 @@ private:
// the threaded loader. Only access them through their respective accessor methods.
QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
QHash<int, int> m_qmlLists;
- QHash<int, QQmlCompiledData *> m_compositeTypes;
+ QHash<int, QV4::CompiledData::CompilationUnit *> m_compositeTypes;
static bool s_designerMode;
// These members is protected by the full QQmlEnginePrivate::mutex mutex
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
index 74ceeabeb4..b309550ca8 100644
--- a/src/qml/qml/qqmlerror.cpp
+++ b/src/qml/qml/qqmlerror.cpp
@@ -249,9 +249,9 @@ QString QQmlError::toString() const
int l(line());
if (u.isEmpty() || (u.isLocalFile() && u.path().isEmpty()))
- rv = QLatin1String("<Unknown File>");
+ rv += QLatin1String("<Unknown File>");
else
- rv = u.toString();
+ rv += u.toString();
if (l != -1) {
rv += QLatin1Char(':') + QString::number(l);
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index 50880e70ea..6afbd05e3e 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -44,7 +44,7 @@
#include "qqmlengine_p.h"
#include "qqmlcontext_p.h"
#include "qqmlscriptstring_p.h"
-#include "qqmlcompiler_p.h"
+#include "qqmlbinding_p.h"
#include <private/qv8engine_p.h>
#include <QtCore/qdebug.h>
@@ -245,14 +245,15 @@ void QQmlExpression::setExpression(const QString &expression)
}
// Must be called with a valid handle scope
-QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined)
+void QQmlExpressionPrivate::v4value(bool *isUndefined, QV4::Scope &scope)
{
if (!expressionFunctionValid) {
createQmlBinding(context(), scopeObject(), expression, url, line);
expressionFunctionValid = true;
}
- return evaluate(isUndefined);
+ QV4::ScopedCallData callData(scope);
+ evaluate(callData, isUndefined, scope);
}
QVariant QQmlExpressionPrivate::value(bool *isUndefined)
@@ -271,9 +272,9 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined)
{
QV4::Scope scope(QV8Engine::getV4(ep->v8engine()));
- QV4::ScopedValue result(scope, v4value(isUndefined));
+ v4value(isUndefined, scope);
if (!hasError())
- rv = scope.engine->toVariant(result, -1);
+ rv = scope.engine->toVariant(scope.result, -1);
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index ccc629a3a3..81a749e017 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -56,7 +56,6 @@
#include <private/qqmlengine_p.h>
#include <private/qfieldlist_p.h>
#include <private/qflagpointer_p.h>
-#include <private/qdeletewatcher_p.h>
#include <private/qqmljavascriptexpression_p.h>
QT_BEGIN_NAMESPACE
@@ -76,7 +75,7 @@ public:
QVariant value(bool *isUndefined = 0);
- QV4::ReturnedValue v4value(bool *isUndefined = 0);
+ void v4value(bool *isUndefined, QV4::Scope &scope);
static inline QQmlExpressionPrivate *get(QQmlExpression *expr);
static inline QQmlExpression *get(QQmlExpressionPrivate *expr);
@@ -86,8 +85,8 @@ public:
bool expressionFunctionValid:1;
// Inherited from QQmlJavaScriptExpression
- virtual QString expressionIdentifier();
- virtual void expressionChanged();
+ QString expressionIdentifier() override;
+ void expressionChanged() override;
QString expression;
diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h
index de482d0352..934cf0f51a 100644
--- a/src/qml/qml/qqmlextensionplugin.h
+++ b/src/qml/qml/qqmlextensionplugin.h
@@ -64,7 +64,7 @@ public:
QUrl baseUrl() const;
virtual void registerTypes(const char *uri) = 0;
- virtual void initializeEngine(QQmlEngine *engine, const char *uri);
+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
private:
Q_DISABLE_COPY(QQmlExtensionPlugin)
diff --git a/src/qml/qml/qqmlfileselector_p.h b/src/qml/qml/qqmlfileselector_p.h
index 57ef194c10..a7360f83d9 100644
--- a/src/qml/qml/qqmlfileselector_p.h
+++ b/src/qml/qml/qqmlfileselector_p.h
@@ -80,7 +80,7 @@ public:
QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate* pd);
QQmlFileSelectorPrivate* d;
protected:
- virtual QUrl intercept(const QUrl &path, DataType type);
+ QUrl intercept(const QUrl &path, DataType type) override;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 01f1042de4..4c5179dc75 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -229,7 +229,7 @@ public:
};
QList<Import *> imports;
- Import *findImport(const QString &uri);
+ Import *findImport(const QString &uri) const;
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
int *vmajor, int *vminor, QQmlType** type_return,
@@ -399,9 +399,7 @@ bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QSt
if (baseUrl.startsWith(importUrl))
{
- QString typeUrl(importUrl);
- typeUrl.append(fileName);
- if (typeUrl == baseUrl)
+ if (fileName == baseUrl.midRef(importUrl.size()))
return false;
}
@@ -455,7 +453,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
const QQmlImportNamespace::Import *import = set.imports.at(ii);
- foreach (const QQmlDirParser::Script &script, import->qmlDirScripts) {
+ for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
ScriptReference ref;
ref.nameSpace = script.nameSpace;
ref.location = QUrl(import->url).resolved(QUrl(script.fileName));
@@ -469,7 +467,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
const QQmlImportNamespace::Import *import = set.imports.at(ii);
- foreach (const QQmlDirParser::Script &script, import->qmlDirScripts) {
+ for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
ScriptReference ref;
ref.nameSpace = script.nameSpace;
ref.qualifier = set.prefix;
@@ -540,10 +538,10 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version)
{
if (version == QQmlImports::FullyVersioned) {
// extension with fully encoded version number (eg. MyModule.3.2)
- return QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin);
+ return QString::asprintf(".%d.%d", vmaj, vmin);
} else if (version == QQmlImports::PartiallyVersioned) {
// extension with encoded version major (eg. MyModule.3)
- return QString(QLatin1String(".%1")).arg(vmaj);
+ return QString::asprintf(".%d", vmaj);
} // else extension without version number (eg. MyModule)
return QString();
}
@@ -786,14 +784,13 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return false;
}
-QQmlImportNamespace::Import *QQmlImportNamespace::findImport(const QString &uri)
+QQmlImportNamespace::Import *QQmlImportNamespace::findImport(const QString &uri) const
{
- for (QList<Import *>::iterator it = imports.begin(), end = imports.end(); it != end; ++it) {
- if ((*it)->uri == uri)
- return *it;
+ for (Import *import : imports) {
+ if (import->uri == uri)
+ return import;
}
-
- return 0;
+ return nullptr;
}
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
@@ -900,6 +897,21 @@ static QStringList versionUriList(const QString &uri, int vmaj, int vmin)
}
#ifndef QT_NO_LIBRARY
+static QVector<QStaticPlugin> makePlugins()
+{
+ QVector<QStaticPlugin> plugins;
+ // To avoid traversing all static plugins for all imports, we cut down
+ // the list the first time called to only contain QML plugins:
+ const auto staticPlugins = QPluginLoader::staticPlugins();
+ for (const QStaticPlugin &plugin : staticPlugins) {
+ if (plugin.metaData().value(QLatin1String("IID")).toString()
+ == QLatin1String(QQmlExtensionInterface_iid)) {
+ plugins.append(plugin);
+ }
+ }
+ return plugins;
+}
+
/*!
Get all static plugins that are QML plugins and has a meta data URI that matches with one of
\a versionUris, which is a list of all possible versioned URI combinations - see versionUriList()
@@ -908,20 +920,11 @@ static QStringList versionUriList(const QString &uri, int vmaj, int vmin)
bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
const QString &qmldirPath, QList<QQmlError> *errors)
{
- static QVector<QStaticPlugin> plugins;
- if (plugins.isEmpty()) {
- // To avoid traversing all static plugins for all imports, we cut down
- // the list the first time called to only contain QML plugins:
- foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) {
- if (plugin.metaData().value(QStringLiteral("IID")).toString() == QLatin1String(QQmlExtensionInterface_iid))
- plugins.append(plugin);
- }
- }
-
- foreach (const QStaticPlugin &plugin, plugins) {
+ static const QVector<QStaticPlugin> plugins = makePlugins();
+ for (const QStaticPlugin &plugin : plugins) {
// Since a module can list more than one plugin, we keep iterating even after we found a match.
if (QQmlExtensionPlugin *instance = qobject_cast<QQmlExtensionPlugin *>(plugin.instance())) {
- const QJsonArray metaTagsUriList = plugin.metaData().value(QStringLiteral("uri")).toArray();
+ const QJsonArray metaTagsUriList = plugin.metaData().value(QLatin1String("uri")).toArray();
if (metaTagsUriList.isEmpty()) {
if (errors) {
QQmlError error;
@@ -933,7 +936,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
return false;
}
// A plugin can be set up to handle multiple URIs, so go through the list:
- foreach (const QJsonValue &metaTagUri, metaTagsUriList) {
+ for (const QJsonValue &metaTagUri : metaTagsUriList) {
if (versionUris.contains(metaTagUri.toString())) {
result.append(qMakePair(plugin, metaTagsUriList));
break;
@@ -1000,7 +1003,8 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
int staticPluginsFound = 0;
#if defined(QT_SHARED)
- foreach (const QQmlDirParser::Plugin &plugin, qmldir->plugins()) {
+ const auto qmldirPlugins = qmldir->plugins();
+ for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
if (!resolvedFilePath.isEmpty()) {
dynamicPluginsFound++;
@@ -1034,8 +1038,8 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
const QString basePath = QFileInfo(qmldirPath).absoluteFilePath();
for (const QString &versionUri : versionUris) {
- foreach (const StaticPluginPair &pair, pluginPairs) {
- foreach (const QJsonValue &metaTagUri, pair.second) {
+ for (const StaticPluginPair &pair : qAsConst(pluginPairs)) {
+ for (const QJsonValue &metaTagUri : pair.second) {
if (versionUri == metaTagUri.toString()) {
staticPluginsFound++;
QObject *instance = pair.first.instance();
@@ -1132,7 +1136,7 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
std::sort(paths.begin(), paths.end(), I::greaterThan); // Ensure subdirs preceed their parents.
QString stableRelativePath = dir;
- foreach(const QString &path, paths) {
+ for (const QString &path : qAsConst(paths)) {
if (dir.startsWith(path)) {
stableRelativePath = dir.mid(path.length()+1);
break;
@@ -1395,15 +1399,9 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
// The uri for this import. For library imports this is the same as uri
// specified by the user, but it may be different in the case of file imports.
QString importUri = uri;
-
- QString qmldirPath = importUri;
- if (importUri.endsWith(Slash))
- qmldirPath += String_qmldir;
- else
- qmldirPath += Slash_qmldir;
-
- QString qmldirUrl = resolveLocalUrl(base, qmldirPath);
-
+ QString qmldirUrl = resolveLocalUrl(base, importUri + (importUri.endsWith(Slash)
+ ? String_qmldir
+ : Slash_qmldir));
QString qmldirIdentifier;
if (QQmlFile::isLocalFile(qmldirUrl)) {
@@ -1679,8 +1677,7 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
if (!qmldirPluginPathIsRelative)
searchPaths.prepend(qmldirPluginPath);
- foreach (const QString &pluginPath, searchPaths) {
-
+ for (const QString &pluginPath : qAsConst(searchPaths)) {
QString resolvedPath;
if (pluginPath == QLatin1String(".")) {
if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty() && qmldirPluginPath != QLatin1String("."))
@@ -1701,10 +1698,9 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
if (!resolvedPath.endsWith(Slash))
resolvedPath += Slash;
- foreach (const QString &suffix, suffixes) {
- QString pluginFileName = prefix + baseName + suffix;
-
- QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName);
+ resolvedPath += prefix + baseName;
+ for (const QString &suffix : suffixes) {
+ const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
if (!absolutePath.isEmpty())
return absolutePath;
}
@@ -1726,7 +1722,7 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
\header \li Platform \li Valid suffixes
\row \li Windows \li \c .dll
\row \li Unix/Linux \li \c .so
- \row \li OS X \li \c .dylib, \c .bundle, \c .so
+ \row \li \macos \li \c .dylib, \c .bundle, \c .so
\endtable
Version number on unix are ignored.
@@ -1736,29 +1732,32 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
const QString &baseName)
{
#if defined(Q_OS_WIN)
- return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
- QStringList()
+ static const QString prefix;
+ static const QStringList suffixes = {
# ifdef QT_DEBUG
- << QLatin1String("d.dll") // try a qmake-style debug build first
+ QLatin1String("d.dll"), // try a qmake-style debug build first
# endif
- << QLatin1String(".dll"));
+ QLatin1String(".dll")
+ };
#elif defined(Q_OS_DARWIN)
-
- return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
- QStringList()
+ static const QString prefix = QLatin1String("lib");
+ static const QStringList suffixes = {
# ifdef QT_DEBUG
- << QLatin1String("_debug.dylib") // try a qmake-style debug build first
- << QLatin1String(".dylib")
+ QLatin1String("_debug.dylib"), // try a qmake-style debug build first
+ QLatin1String(".dylib"),
# else
- << QLatin1String(".dylib")
- << QLatin1String("_debug.dylib") // try a qmake-style debug build after
+ QLatin1String(".dylib"),
+ QLatin1String("_debug.dylib"), // try a qmake-style debug build after
# endif
- << QLatin1String(".so")
- << QLatin1String(".bundle"),
- QLatin1String("lib"));
+ QLatin1String(".so"),
+ QLatin1String(".bundle")
+ };
# else // Unix
- return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, QStringList() << QLatin1String(".so"), QLatin1String("lib"));
+ static const QString prefix = QLatin1String("lib");
+ static const QStringList suffixes = { QLatin1String(".so") };
#endif
+
+ return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix);
}
/*!
@@ -1817,7 +1816,7 @@ void QQmlImportDatabase::addImportPath(const QString& path)
} else if (path.startsWith(QLatin1Char(':'))) {
// qrc directory, e.g. :/foo
// need to convert to a qrc url, e.g. qrc:/foo
- cPath = QStringLiteral("qrc") + path;
+ cPath = QLatin1String("qrc") + path;
cPath.replace(Backslash, Slash);
} else if (url.isRelative() ||
(url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
@@ -1842,7 +1841,7 @@ QStringList QQmlImportDatabase::importPathList(PathType type) const
return fileImportPath;
QStringList list;
- foreach (const QString &path, fileImportPath) {
+ for (const QString &path : fileImportPath) {
bool localPath = isPathAbsolute(path) || QQmlFile::isLocalFile(path);
if (localPath == (type == Local))
list.append(path);
@@ -1936,7 +1935,7 @@ bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &b
if (!registrationFailures.isEmpty()) {
if (errors) {
- foreach (const QString &failure, registrationFailures) {
+ for (const QString &failure : qAsConst(registrationFailures)) {
QQmlError error;
error.setDescription(failure);
errors->prepend(error);
@@ -1957,7 +1956,7 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba
#ifndef QT_NO_LIBRARY
// Dynamic plugins are differentiated by their filepath. For static plugins we
// don't have that information so we use their address as key instead.
- QString uniquePluginID = QString().sprintf("%p", instance);
+ const QString uniquePluginID = QString::asprintf("%p", instance);
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
QMutexLocker lock(&plugins->mutex);
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index eba93bfb1a..963638ca34 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -41,7 +41,6 @@
#include "qqmlcomponent.h"
#include "qqmlincubator_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlexpression_p.h"
#include "qqmlmemoryprofiler_p.h"
#include "qqmlobjectcreator_p.h"
@@ -132,7 +131,7 @@ QQmlIncubationController *QQmlEngine::incubationController() const
QQmlIncubatorPrivate::QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m)
: q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute),
- result(0), compiledData(0), waitingOnMe(0)
+ result(0), enginePriv(0), waitingOnMe(0)
{
}
@@ -143,20 +142,15 @@ QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
void QQmlIncubatorPrivate::clear()
{
+ compilationUnit = nullptr;
if (next.isInList()) {
next.remove();
- Q_ASSERT(compiledData);
- QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(compiledData->engine);
- compiledData->release();
- compiledData = 0;
enginePriv->incubatorCount--;
QQmlIncubationController *controller = enginePriv->incubationController;
if (controller)
controller->incubatingObjectCountChanged(enginePriv->incubatorCount);
- } else if (compiledData) {
- compiledData->release();
- compiledData = 0;
}
+ enginePriv = 0;
if (!rootContext.isNull()) {
rootContext->activeVMEData = 0;
rootContext = 0;
@@ -212,7 +206,7 @@ public:
}
protected:
- virtual void timerEvent(QTimerEvent *) {
+ void timerEvent(QTimerEvent *) override {
incubateFor(5);
}
};
@@ -278,21 +272,20 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i)
void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
{
- if (!compiledData)
+ if (!compilationUnit)
return;
- QML_MEMORY_SCOPE_URL(compiledData->compilationUnit->url());
+ QML_MEMORY_SCOPE_URL(compilationUnit->url());
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this);
QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this);
-
- QQmlEngine *engine = compiledData->engine;
- QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
+ // get a copy of the engine pointer as it might get reset;
+ QQmlEnginePrivate *enginePriv = this->enginePriv;
if (!vmeGuard.isOK()) {
QQmlError error;
- error.setUrl(compiledData->compilationUnit->url());
+ error.setUrl(compilationUnit->url());
error.setDescription(QQmlComponent::tr("Object destroyed during incubation"));
errors << error;
progress = QQmlIncubatorPrivate::Completed;
@@ -440,7 +433,7 @@ example shows a simple use of QQmlIncubator.
QQmlIncubator incubator;
component->create(incubator);
-while (incubator.isReady()) {
+while (!incubator.isReady()) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
}
@@ -563,17 +556,16 @@ void QQmlIncubator::clear()
if (s == Null)
return;
- QQmlEnginePrivate *enginePriv = 0;
+ QQmlEnginePrivate *enginePriv = d->enginePriv;
if (s == Loading) {
- Q_ASSERT(d->compiledData);
- enginePriv = QQmlEnginePrivate::get(d->compiledData->engine);
+ Q_ASSERT(d->compilationUnit);
if (d->result) d->result->deleteLater();
d->result = 0;
}
d->clear();
- Q_ASSERT(d->compiledData == 0);
+ Q_ASSERT(d->compilationUnit.isNull());
Q_ASSERT(d->waitingOnMe.data() == 0);
Q_ASSERT(d->waitingFor.isEmpty());
@@ -713,7 +705,7 @@ QQmlIncubator::Status QQmlIncubatorPrivate::calculateStatus() const
return QQmlIncubator::Error;
else if (result && progress == QQmlIncubatorPrivate::Completed && waitingFor.isEmpty())
return QQmlIncubator::Ready;
- else if (compiledData)
+ else if (compilationUnit)
return QQmlIncubator::Loading;
else
return QQmlIncubator::Null;
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index a12ff9c5e2..ecf3b6d2ca 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -59,7 +59,6 @@
QT_BEGIN_NAMESPACE
-class QQmlCompiledData;
class QQmlIncubator;
class QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
{
@@ -85,7 +84,8 @@ public:
QPointer<QObject> result;
QQmlGuardedContextData rootContext;
- QQmlCompiledData *compiledData;
+ QQmlEnginePrivate *enginePriv;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
QScopedPointer<QQmlObjectCreator> creator;
int subComponentToCreate;
QQmlVMEGuard vmeGuard;
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 8ba4b5eba1..8020bdb2be 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -106,7 +106,8 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
m_nextExpression->m_prevExpression = m_prevExpression;
}
- clearGuards();
+ clearActiveGuards();
+ clearPermanentGuards();
if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
m_scopeObject.asT2()->_s = 0;
}
@@ -114,12 +115,17 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
{
activeGuards.setFlagValue(v);
- if (!v) clearGuards();
+ permanentGuards.setFlagValue(v);
+ if (!v) {
+ clearActiveGuards();
+ clearPermanentGuards();
+ m_permanentDependenciesRegistered = false;
+ }
}
void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
{
- clearGuards();
+ setNotifyOnValueChanged(false);
}
void QQmlJavaScriptExpression::setContext(QQmlContextData *context)
@@ -147,16 +153,9 @@ void QQmlJavaScriptExpression::refresh()
{
}
-QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined)
-{
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_context->engine);
- QV4::Scope scope(v4);
- QV4::ScopedCallData callData(scope);
- return evaluate(callData, isUndefined);
-}
-QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined)
+void QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined, QV4::Scope &scope)
{
Q_ASSERT(m_context && m_context->engine);
@@ -164,7 +163,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
if (!f || f->isUndefined()) {
if (isUndefined)
*isUndefined = true;
- return QV4::Encode::undefined();
+ return;
}
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine);
@@ -184,8 +183,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
capture.guards.copyAndClearPrepend(activeGuards);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
- QV4::Scope scope(v4);
- QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue());
+ scope.result = QV4::Primitive::undefinedValue();
callData->thisObject = v4->globalObject;
if (scopeObject()) {
QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(v4, scopeObject()));
@@ -193,7 +191,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
callData->thisObject = value;
}
- result = f->as<QV4::FunctionObject>()->call(callData);
+ f->as<QV4::FunctionObject>()->call(scope, callData);
if (scope.hasException()) {
if (watcher.wasDeleted())
scope.engine->catchException(); // ignore exception
@@ -203,7 +201,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
*isUndefined = true;
} else {
if (isUndefined)
- *isUndefined = result->isUndefined();
+ *isUndefined = scope.result.isUndefined();
if (!watcher.wasDeleted() && hasDelayedError())
delayedError()->clearError();
@@ -220,11 +218,9 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
g->Delete();
ep->propertyCapture = lastPropertyCapture;
-
- return result->asReturnedValue();
}
-void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
+void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration)
{
if (watcher->wasDeleted())
return;
@@ -244,14 +240,17 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
g->connect(n);
}
- expression->activeGuards.prepend(g);
+ if (duration == Permanently)
+ expression->permanentGuards.prepend(g);
+ else
+ expression->activeGuards.prepend(g);
}
/*! \internal
\a n is in the signal index range (see QObjectPrivate::signalIndex()).
*/
-void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n)
+void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration)
{
if (watcher->wasDeleted())
return;
@@ -290,49 +289,60 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n)
g->connect(o, n, engine);
}
- expression->activeGuards.prepend(g);
+ if (duration == Permanently)
+ expression->permanentGuards.prepend(g);
+ else
+ expression->activeGuards.prepend(g);
}
}
-void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction)
+void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope)
{
// Let the caller check and avoid the function call :)
Q_ASSERT(compiledFunction->hasQmlDependencies());
+ QV4::ExecutionEngine *engine = scope.engine;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine());
if (!ep)
return;
QQmlPropertyCapture *capture = ep->propertyCapture;
- if (!capture)
+ if (!capture || capture->watcher->wasDeleted())
+ return;
+
+ if (capture->expression->m_permanentDependenciesRegistered)
return;
- QV4::Scope scope(engine);
+ capture->expression->m_permanentDependenciesRegistered = true;
+
QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext());
QQmlContextData *qmlContext = context->qmlContext();
- const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
+ const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
const int idObjectDependencyCount = compiledFunction->nDependingIdObjects;
for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) {
Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount);
- capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings);
+ capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings,
+ QQmlPropertyCapture::Permanently);
}
Q_ASSERT(qmlContext->contextObject);
- const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
+ const QV4::CompiledData::LEUInt32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
for (int i = 0; i < contextPropertyDependencyCount; ++i) {
const int propertyIndex = *contextPropertyDependency++;
const int notifyIndex = *contextPropertyDependency++;
- capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex);
+ capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex,
+ QQmlPropertyCapture::Permanently);
}
QObject *scopeObject = context->qmlScope();
- const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
+ const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties;
for (int i = 0; i < scopePropertyDependencyCount; ++i) {
const int propertyIndex = *scopePropertyDependency++;
const int notifyIndex = *scopePropertyDependency++;
- capture->captureProperty(scopeObject, propertyIndex, notifyIndex);
+ capture->captureProperty(scopeObject, propertyIndex, notifyIndex,
+ QQmlPropertyCapture::Permanently);
}
}
@@ -416,12 +426,19 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *
}
-void QQmlJavaScriptExpression::clearGuards()
+void QQmlJavaScriptExpression::clearActiveGuards()
{
while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst())
g->Delete();
}
+void QQmlJavaScriptExpression::clearPermanentGuards()
+{
+ m_permanentDependenciesRegistered = false;
+ while (QQmlJavaScriptExpressionGuard *g = permanentGuards.takeFirst())
+ g->Delete();
+}
+
void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **)
{
QQmlJavaScriptExpression *expression =
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 94479f6c5e..5f9cffb56d 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -103,8 +103,7 @@ public:
virtual QString expressionIdentifier() = 0;
virtual void expressionChanged() = 0;
- QV4::ReturnedValue evaluate(bool *isUndefined);
- QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined);
+ void evaluate(QV4::CallData *callData, bool *isUndefined, QV4::Scope &scope);
inline bool notifyOnValueChanged() const;
@@ -137,7 +136,8 @@ public:
inline bool hasDelayedError() const;
QQmlError error(QQmlEngine *) const;
void clearError();
- void clearGuards();
+ void clearActiveGuards();
+ void clearPermanentGuards();
QQmlDelayedError *delayedError();
static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope,
@@ -146,6 +146,14 @@ public:
protected:
void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line);
+ void cancelPermanentGuards() const
+ {
+ if (m_permanentDependenciesRegistered) {
+ for (QQmlJavaScriptExpressionGuard *it = permanentGuards.first(); it; it = permanentGuards.next(it))
+ it->cancelNotify();
+ }
+ }
+
private:
friend class QQmlContextData;
friend class QQmlPropertyCapture;
@@ -158,10 +166,12 @@ private:
// activeGuards:flag2 - useSharedContext
QBiPointer<QObject, DeleteWatcher> m_scopeObject;
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards;
+ QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards;
QQmlContextData *m_context;
QQmlJavaScriptExpression **m_prevExpression;
QQmlJavaScriptExpression *m_nextExpression;
+ bool m_permanentDependenciesRegistered = false;
protected:
QV4::PersistentValue m_function;
@@ -178,10 +188,14 @@ public:
Q_ASSERT(errorString == 0);
}
- void captureProperty(QQmlNotifier *);
- void captureProperty(QObject *, int, int);
+ enum Duration {
+ OnlyOnce,
+ Permanently
+ };
- static void registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction);
+ static void registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope);
+ void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce);
+ void captureProperty(QObject *, int, int, Duration duration = OnlyOnce);
QQmlEngine *engine;
QQmlJavaScriptExpression *expression;
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
index d0b7fb4853..a719956483 100644
--- a/src/qml/qml/qqmllist.cpp
+++ b/src/qml/qml/qqmllist.cpp
@@ -143,16 +143,16 @@ QQmlListReference::QQmlListReference(QObject *object, const char *property, QQml
QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):0;
- int listType = p?p->listType(data->propType):QQmlMetaType::listType(data->propType);
+ int listType = p?p->listType(data->propType()):QQmlMetaType::listType(data->propType());
if (listType == -1) return;
d = new QQmlListReferencePrivate;
d->object = object;
d->elementType = p?p->rawMetaObjectForType(listType):QQmlMetaType::qmlType(listType)->baseMetaObject();
- d->propertyType = data->propType;
+ d->propertyType = data->propType();
void *args[] = { &d->property, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex, args);
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex(), args);
}
/*! \internal */
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 5c35866274..425a720867 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -54,6 +54,7 @@ DEFINE_OBJECT_VTABLE(QmlListWrapper);
Heap::QmlListWrapper::QmlListWrapper()
{
+ object.init();
QV4::Scope scope(internalClass->engine);
QV4::ScopedObject o(scope, this);
o->setArrayType(Heap::ArrayData::Custom);
@@ -61,6 +62,7 @@ Heap::QmlListWrapper::QmlListWrapper()
Heap::QmlListWrapper::~QmlListWrapper()
{
+ object.destroy();
}
ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, int propId, int propType)
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index 26e1e5faaf..1107b957c9 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -68,7 +68,7 @@ namespace Heap {
struct QmlListWrapper : Object {
QmlListWrapper();
~QmlListWrapper();
- QPointer<QObject> object;
+ QQmlQPointer<QObject> object;
QQmlListProperty<QObject> property;
int propertyType;
};
diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp
new file mode 100644
index 0000000000..88cf14cba0
--- /dev/null
+++ b/src/qml/qml/qqmlloggingcategory.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Pelagicore AG
+** 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 "qqmlloggingcategory_p.h"
+
+#include <QtQml/qqmlinfo.h>
+
+/*!
+ \qmltype LoggingCategory
+ \ingroup qml-utility-elements
+ \inqmlmodule QtQml
+ \brief Defines a logging category in QML
+ \since 5.8
+
+ A logging category can be passed to console.log() and friends as the first argument.
+ If supplied to to the logger the LoggingCategory's name will be used as Logging Category
+ otherwise the default logging category will be used.
+
+ \qml
+ import QtQuick 2.8
+
+ Item {
+ LoggingCategory {
+ id: category
+ name: "com.qt.category"
+ }
+
+ Component.onCompleted: {
+ console.log(category, "message");
+ }
+ }
+ \endqml
+
+ \note As the creation of objects is expensive, it is encouraged to put the needed
+ LoggingCategory definitions into a singleton and import this where needed.
+
+ \sa QLoggingCategory
+*/
+
+/*!
+ \qmlproperty string QtQml::LoggingCategory::name
+
+ Holds the name of the logging category.
+
+ \note This property needs to be set when declaring the LoggingCategory
+ and cannot be changed later.
+
+ \sa QLoggingCategory::name()
+*/
+
+QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent)
+ : QObject(parent)
+ , m_initialized(false)
+{
+}
+
+QQmlLoggingCategory::~QQmlLoggingCategory()
+{
+}
+
+QString QQmlLoggingCategory::name() const
+{
+ return QString::fromUtf8(m_name);
+}
+
+QLoggingCategory *QQmlLoggingCategory::category() const
+{
+ return m_category.data();
+}
+
+void QQmlLoggingCategory::classBegin()
+{
+}
+
+void QQmlLoggingCategory::componentComplete()
+{
+ m_initialized = true;
+ if (m_name.isNull())
+ qmlInfo(this) << QString(QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"));
+}
+
+void QQmlLoggingCategory::setName(const QString &name)
+{
+ if (m_initialized) {
+ qmlInfo(this) << QString(QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created"));
+ return;
+ }
+
+ m_name = name.toUtf8();
+ QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData()));
+ m_category.swap(category);
+}
diff --git a/src/qml/qml/ftw/qdeletewatcher_p.h b/src/qml/qml/qqmlloggingcategory_p.h
index d4c0c6dfb2..2b7f2f5b53 100644
--- a/src/qml/qml/ftw/qdeletewatcher_p.h
+++ b/src/qml/qml/qqmlloggingcategory_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QDELETEWATCHER_P_H
-#define QDELETEWATCHER_P_H
+#ifndef QQMLLOGGINGCATEGORY_P_H
+#define QQMLLOGGINGCATEGORY_P_H
//
// W A R N I N G
@@ -51,61 +51,39 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qloggingcategory.h>
+
+#include <QtQml/qqmlparserstatus.h>
QT_BEGIN_NAMESPACE
-class QDeleteWatchable
+class QQmlLoggingCategory : public QObject, public QQmlParserStatus
{
-public:
- inline QDeleteWatchable();
- inline ~QDeleteWatchable();
-private:
- friend class QDeleteWatcher;
- bool *_w;
-};
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
-class QDeleteWatcher {
-public:
- inline QDeleteWatcher(QDeleteWatchable *data);
- inline ~QDeleteWatcher();
- inline bool wasDeleted() const;
-private:
- void *operator new(size_t);
- bool *_w;
- bool _s;
- QDeleteWatchable *m_d;
-};
+ Q_PROPERTY(QString name READ name WRITE setName)
-QDeleteWatchable::QDeleteWatchable()
-: _w(0)
-{
-}
+public:
+ QQmlLoggingCategory(QObject *parent = 0);
+ virtual ~QQmlLoggingCategory();
-QDeleteWatchable::~QDeleteWatchable()
-{
- if (_w) *_w = true;
-}
+ QString name() const;
+ void setName(const QString &name);
-QDeleteWatcher::QDeleteWatcher(QDeleteWatchable *data)
-: _s(false), m_d(data)
-{
- if (!m_d->_w)
- m_d->_w = &_s;
- _w = m_d->_w;
-}
+ QLoggingCategory *category() const;
-QDeleteWatcher::~QDeleteWatcher()
-{
- if (false == *_w && &_s == m_d->_w)
- m_d->_w = 0;
-}
+ void classBegin() override;
+ void componentComplete() override;
-bool QDeleteWatcher::wasDeleted() const
-{
- return *_w;
-}
+private:
+ QByteArray m_name;
+ QScopedPointer<QLoggingCategory> m_category;
+ bool m_initialized;
+};
QT_END_NAMESPACE
-#endif // QDELETEWATCHER_P_H
+#endif // QQMLLOGGINGCATEGORY_H
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 1b3997baae..08acb330b1 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -44,7 +44,6 @@
#include <private/qqmlcustomparser_p.h>
#include <private/qhashedstring_p.h>
#include <private/qqmlimport_p.h>
-#include <private/qqmlcompiler_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qstringlist.h>
@@ -490,11 +489,11 @@ QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
Q_ASSERT(isComposite());
if (!engine)
return 0;
- QQmlTypeData *td = engine->typeLoader.getType(sourceUrl());
- if (!td || !td->isComplete())
+ QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt);
+ if (td.isNull() || !td->isComplete())
return 0;
- QQmlCompiledData *cd = td->compiledData();
- const QMetaObject *mo = cd->compilationUnit->rootPropertyCache()->firstCppMetaObject();
+ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
+ const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
return QQmlMetaType::qmlType(mo);
}
@@ -635,7 +634,7 @@ void QQmlTypePrivate::init() const
QMetaObject *mmo = builder.toMetaObject();
mmo->d.superdata = baseMetaObject;
if (!metaObjects.isEmpty())
- metaObjects.last().metaObject->d.superdata = mmo;
+ metaObjects.constLast().metaObject->d.superdata = mmo;
QQmlProxyMetaObject::ProxyData data = { mmo, t->d->extraData.cd->extFunc, 0, 0 };
metaObjects << data;
}
@@ -657,7 +656,7 @@ void QQmlTypePrivate::init() const
if (metaObjects.isEmpty())
mo = baseMetaObject;
else
- mo = metaObjects.first().metaObject;
+ mo = metaObjects.constFirst().metaObject;
for (int ii = 0; !containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
if (isPropertyRevisioned(mo, ii))
@@ -852,7 +851,7 @@ const QMetaObject *QQmlType::metaObject() const
if (d->metaObjects.isEmpty())
return d->baseMetaObject;
else
- return d->metaObjects.first().metaObject;
+ return d->metaObjects.constFirst().metaObject;
}
@@ -1445,11 +1444,11 @@ bool qmlProtectModule(const char *uri, int majVersion)
bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri, int majorVersion)
{
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeData *data = metaTypeData();
// Has any type previously been installed to this namespace?
QHashedString nameSpace(uri);
- foreach (const QQmlType *type, data->types)
+ for (const QQmlType *type : data->types)
if (type->module() == nameSpace && type->majorVersion() == majorVersion)
return true;
@@ -1862,7 +1861,7 @@ QQmlType *QQmlMetaType::qmlTypeFromIndex(int idx)
if (idx < 0 || idx >= data->types.count())
return 0;
- return data->types[idx];
+ return data->types.at(idx);
}
/*!
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index dcd35bccad..2218f277d6 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -69,41 +69,43 @@ struct ActiveOCRestorer
};
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext)
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *creationContext, void *activeVMEDataForRootContext)
: phase(Startup)
- , compiledData(compiledData)
- , resolvedTypes(compiledData->resolvedTypes)
- , propertyCaches(compiledData->compilationUnit->propertyCaches)
+ , compilationUnit(compilationUnit)
+ , resolvedTypes(compilationUnit->resolvedTypes)
+ , propertyCaches(&compilationUnit->propertyCaches)
+ , sharedState(new QQmlObjectCreatorSharedState)
+ , topLevelCreator(true)
, activeVMEDataForRootContext(activeVMEDataForRootContext)
{
init(parentContext);
- sharedState = new QQmlObjectCreatorSharedState;
- topLevelCreator = true;
sharedState->componentAttached = 0;
- sharedState->allCreatedBindings.allocate(compiledData->compilationUnit->totalBindingsCount);
- sharedState->allParserStatusCallbacks.allocate(compiledData->compilationUnit->totalParserStatusCount);
- sharedState->allCreatedObjects.allocate(compiledData->compilationUnit->totalObjectCount);
+ sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount);
+ sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount);
+ sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount);
sharedState->allJavaScriptObjects = 0;
sharedState->creationContext = creationContext;
sharedState->rootContext = 0;
- QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler;
- Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
- sharedState->profiler.init(profiler, compiledData->compilationUnit->totalParserStatusCount));
+ if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) {
+ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
+ sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount));
+ } else {
+ Q_UNUSED(profiler);
+ }
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState)
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
: phase(Startup)
- , compiledData(compiledData)
- , resolvedTypes(compiledData->resolvedTypes)
- , propertyCaches(compiledData->compilationUnit->propertyCaches)
+ , compilationUnit(compilationUnit)
+ , resolvedTypes(compilationUnit->resolvedTypes)
+ , propertyCaches(&compilationUnit->propertyCaches)
+ , sharedState(inheritedSharedState)
+ , topLevelCreator(false)
, activeVMEDataForRootContext(0)
{
init(parentContext);
-
- sharedState = inheritedSharedState;
- topLevelCreator = false;
}
void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
@@ -112,13 +114,14 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
engine = parentContext->engine;
v4 = QV8Engine::getV4(engine);
- if (!compiledData->isInitialized())
- compiledData->initialize(engine);
+ if (compilationUnit && !compilationUnit->engine)
+ compilationUnit->linkToEngine(v4);
- qmlUnit = compiledData->compilationUnit->data;
+ qmlUnit = compilationUnit->data;
context = 0;
_qobject = 0;
_scopeObject = 0;
+ _bindingTarget = 0;
_valueTypeProperty = 0;
_compiledObject = 0;
_compiledObjectIndex = -1;
@@ -166,9 +169,8 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
context = new QQmlContextData;
context->isInternal = true;
- context->imports = compiledData->compilationUnit->importCache;
- context->imports->addref();
- context->initFromTypeCompilationUnit(compiledData->compilationUnit, subComponentIndex);
+ context->imports = compilationUnit->importCache;
+ context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
context->setParent(parentContext);
if (!sharedState->rootContext) {
@@ -181,14 +183,14 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator);
if (topLevelCreator)
- sharedState->allJavaScriptObjects = scope.alloc(compiledData->compilationUnit->totalObjectCount);
+ sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount);
- if (subComponentIndex == -1 && compiledData->compilationUnit->dependentScripts.count()) {
- QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->compilationUnit->dependentScripts.count()));
+ if (subComponentIndex == -1 && compilationUnit->dependentScripts.count()) {
+ QV4::ScopedObject scripts(scope, v4->newArrayObject(compilationUnit->dependentScripts.count()));
context->importedScripts.set(v4, scripts);
QV4::ScopedValue v(scope);
- for (int i = 0; i < compiledData->compilationUnit->dependentScripts.count(); ++i) {
- QQmlScriptData *s = compiledData->compilationUnit->dependentScripts.at(i);
+ for (int i = 0; i < compilationUnit->dependentScripts.count(); ++i) {
+ QQmlScriptData *s = compilationUnit->dependentScripts.at(i);
scripts->putIndexed(i, (v = s->scriptValueForContext(context)));
}
} else if (sharedState->creationContext) {
@@ -199,10 +201,10 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
if (instance) {
QQmlData *ddata = QQmlData::get(instance);
Q_ASSERT(ddata);
- if (ddata->compiledData)
- ddata->compiledData->release();
- ddata->compiledData = compiledData;
- ddata->compiledData->addref();
+ if (ddata->compilationUnit)
+ ddata->compilationUnit->release();
+ ddata->compilationUnit = compilationUnit;
+ ddata->compilationUnit->addref();
}
if (topLevelCreator)
@@ -236,7 +238,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
Q_ASSERT(topLevelCreator);
Q_ASSERT(!sharedState->allJavaScriptObjects);
- sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->compilationUnit->totalObjectCount);
+ sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
@@ -275,14 +277,10 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
{
- QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
- int propertyWriteStatus = -1;
- void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
-
+ QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;
QV4::Scope scope(v4);
- int propertyType = property->propType;
+ int propertyType = property->propType();
if (property->isEnum()) {
if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) {
@@ -303,39 +301,35 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
double n = binding->valueAsNumber();
if (double(int(n)) == n) {
if (property->isVarProperty()) {
- _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromInt32(int(n)));
+ _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Primitive::fromInt32(int(n)));
} else {
int i = int(n);
QVariant value(i);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
} else {
if (property->isVarProperty()) {
- _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromDouble(n));
+ _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Primitive::fromDouble(n));
} else {
QVariant value(n);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
} else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
if (property->isVarProperty()) {
- _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromBoolean(binding->valueAsBoolean()));
+ _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Primitive::fromBoolean(binding->valueAsBoolean()));
} else {
QVariant value(binding->valueAsBoolean());
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
} else {
QString stringValue = binding->valueAsString(qmlUnit);
if (property->isVarProperty()) {
QV4::ScopedString s(scope, v4->newString(stringValue));
- _vmeMetaObject->setVMEProperty(property->coreIndex, s);
+ _vmeMetaObject->setVMEProperty(property->coreIndex(), s);
} else {
QVariant value = QQmlStringConverters::variantFromString(stringValue);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
}
@@ -343,22 +337,19 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QVariant::String: {
Q_ASSERT(binding->evaluatesToString());
QString value = binding->valueAsString(qmlUnit);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::StringList: {
Q_ASSERT(binding->evaluatesToString());
QStringList value(binding->valueAsString(qmlUnit));
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::ByteArray: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
QByteArray value(binding->valueAsString(qmlUnit).toUtf8());
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Url: {
@@ -366,20 +357,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QString string = binding->valueAsString(qmlUnit);
// Encoded dir-separators defeat QUrl processing - decode them first
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- QUrl value = string.isEmpty() ? QUrl() : compiledData->compilationUnit->url().resolved(QUrl(string));
+ QUrl value = string.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(string));
// Apply URL interceptor
if (engine->urlInterceptor())
value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::UInt: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
double d = binding->valueAsNumber();
uint value = uint(d);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
}
break;
@@ -387,23 +376,20 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
double d = binding->valueAsNumber();
int value = int(d);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
}
break;
case QMetaType::Float: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
float value = float(binding->valueAsNumber());
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Double: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
double value = binding->valueAsNumber();
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Color: {
@@ -411,9 +397,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
struct { void *data[4]; } buffer;
- if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
- argv[0] = reinterpret_cast<void *>(&buffer);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) {
+ property->writeProperty(_qobject, &buffer, propertyWriteFlags);
}
}
break;
@@ -422,16 +407,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = false;
QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Time: {
bool ok = false;
QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::DateTime: {
@@ -444,8 +427,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay));
}
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
#endif // QT_NO_DATESTRING
@@ -453,55 +435,59 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = false;
QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok).toPoint();
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::PointF: {
bool ok = false;
QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Size: {
bool ok = false;
QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok).toSize();
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::SizeF: {
bool ok = false;
QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Rect: {
bool ok = false;
QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok).toRect();
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::RectF: {
bool ok = false;
QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok);
Q_ASSERT(ok);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Bool: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
bool value = binding->valueAsBoolean();
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ }
+ break;
+ case QVariant::Vector2D: {
+ struct {
+ float xp;
+ float yp;
+ } vec;
+ bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec));
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+ property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
break;
case QVariant::Vector3D: {
@@ -513,8 +499,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &vec, sizeof(vec));
Q_ASSERT(ok);
Q_UNUSED(ok);
- argv[0] = reinterpret_cast<void *>(&vec);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
break;
case QVariant::Vector4D: {
@@ -527,8 +512,20 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(qmlUnit), &vec, sizeof(vec));
Q_ASSERT(ok);
Q_UNUSED(ok);
- argv[0] = reinterpret_cast<void *>(&vec);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &vec, propertyWriteFlags);
+ }
+ break;
+ case QVariant::Quaternion: {
+ struct {
+ float wp;
+ float xp;
+ float yp;
+ float zp;
+ } vec;
+ bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec));
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+ property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
break;
case QVariant::RegExp:
@@ -536,45 +533,40 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
default: {
// generate single literal value assignment to a list property if required
- if (property->propType == qMetaTypeId<QList<qreal> >()) {
+ if (property->propType() == qMetaTypeId<QList<qreal> >()) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
QList<qreal> value;
value.append(binding->valueAsNumber());
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType == qMetaTypeId<QList<int> >()) {
+ } else if (property->propType() == qMetaTypeId<QList<int> >()) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
double n = binding->valueAsNumber();
QList<int> value;
value.append(int(n));
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType == qMetaTypeId<QList<bool> >()) {
+ } else if (property->propType() == qMetaTypeId<QList<bool> >()) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
QList<bool> value;
value.append(binding->valueAsBoolean());
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
+ } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
QString urlString = binding->valueAsString(qmlUnit);
- QUrl u = urlString.isEmpty() ? QUrl() : compiledData->compilationUnit->url().resolved(QUrl(urlString));
+ QUrl u = urlString.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(urlString));
QList<QUrl> value;
value.append(u);
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType == qMetaTypeId<QList<QString> >()) {
+ } else if (property->propType() == qMetaTypeId<QList<QString> >()) {
Q_ASSERT(binding->evaluatesToString());
QList<QString> value;
value.append(binding->valueAsString(qmlUnit));
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType == qMetaTypeId<QJSValue>()) {
+ } else if (property->propType() == qMetaTypeId<QJSValue>()) {
QJSValue value;
if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
value = QJSValue(binding->valueAsBoolean());
@@ -587,25 +579,23 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
} else {
value = QJSValue(binding->valueAsString(qmlUnit));
}
- argv[0] = reinterpret_cast<void *>(&value);
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
}
// otherwise, try a custom type assignment
QString stringValue = binding->valueAsString(qmlUnit);
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType);
+ QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
Q_ASSERT(converter);
QVariant value = (*converter)(stringValue);
- QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex);
- if (value.isNull() || ((int)metaProperty.type() != property->propType && metaProperty.userType() != property->propType)) {
+ QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex());
+ if (value.isNull() || ((int)metaProperty.type() != property->propType() && metaProperty.userType() != property->propType())) {
recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
break;
}
- argv[0] = value.data();
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ property->writeProperty(_qobject, value.data(), propertyWriteFlags);
}
break;
}
@@ -627,12 +617,12 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
- const QV4::CompiledData::BindingPropertyData &propertyData = compiledData->compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
+ const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
if (_compiledObject->idNameIndex) {
const QQmlPropertyData *idProperty = propertyData.last();
Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id"));
- if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType == QMetaType::QString) {
+ if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType() == QMetaType::QString) {
QV4::CompiledData::Binding idBinding;
idBinding.propertyNameIndex = 0; // Not used
idBinding.flags = 0;
@@ -645,10 +635,10 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
// ### this is best done through type-compile-time binding skip lists.
if (_valueTypeProperty) {
- QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex);
+ QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
if (binding && !binding->isValueTypeProxy()) {
- QQmlPropertyPrivate::removeBinding(_bindingTarget, _valueTypeProperty->coreIndex);
+ QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
} else if (binding) {
QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding);
@@ -661,7 +651,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
QQmlPropertyData *property = binding->propertyNameIndex != 0 ? _propertyCache->property(stringAt(binding->propertyNameIndex), _qobject, context) : defaultProperty;
if (property)
- bindingSkipList |= (1 << property->coreIndex);
+ bindingSkipList |= (1 << property->coreIndex());
}
proxy->removeBindings(bindingSkipList);
@@ -687,10 +677,10 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
const QQmlPropertyData *property = propertyData.at(i);
if (property && property->isQList()) {
- if (property->coreIndex != currentListPropertyIndex) {
+ if (property->coreIndex() != currentListPropertyIndex) {
void *argv[1] = { (void*)&_currentList };
- QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv);
- currentListPropertyIndex = property->coreIndex;
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv);
+ currentListPropertyIndex = property->coreIndex();
}
} else if (_currentList.object) {
_currentList = QQmlListProperty<void>();
@@ -708,7 +698,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
{
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
- QQmlCompiledData::TypeReference *tr = resolvedTypes.value(binding->propertyNameIndex);
+ QV4::CompiledData::ResolvedTypeReference *tr = resolvedTypes.value(binding->propertyNameIndex);
Q_ASSERT(tr);
QQmlType *attachedType = tr->type;
if (!attachedType) {
@@ -726,7 +716,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
}
// ### resolve this at compile time
- if (property && property->propType == qMetaTypeId<QQmlScriptString>()) {
+ if (property && property->propType() == qMetaTypeId<QQmlScriptString>()) {
QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), 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;
@@ -735,11 +725,11 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
ss.d.data()->numberValue = binding->valueAsNumber();
- QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::RemoveBindingOnAliasWrite;
int propertyWriteStatus = -1;
void *argv[] = { &ss, 0, &propertyWriteStatus, &propertyWriteFlags };
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
return true;
}
@@ -762,20 +752,20 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
const QQmlPropertyData *valueTypeProperty = 0;
QObject *bindingTarget = _bindingTarget;
- if (QQmlValueTypeFactory::isValueType(property->propType)) {
- valueType = QQmlValueTypeFactory::valueType(property->propType);
+ if (QQmlValueTypeFactory::isValueType(property->propType())) {
+ valueType = QQmlValueTypeFactory::valueType(property->propType());
if (!valueType) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
return false;
}
- valueType->read(_qobject, property->coreIndex);
+ valueType->read(_qobject, property->coreIndex());
groupObject = valueType;
valueTypeProperty = property;
} else {
void *argv[1] = { &groupObject };
- QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv);
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv);
if (!groupObject) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
return false;
@@ -788,48 +778,49 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
if (valueType)
- valueType->write(_qobject, property->coreIndex, QQmlPropertyPrivate::BypassInterceptor);
+ valueType->write(_qobject, property->coreIndex(), QQmlPropertyData::BypassInterceptor);
return true;
}
}
- if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ if (_ddata->hasBindingBit(property->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
&& !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
&& !_valueTypeProperty)
- QQmlPropertyPrivate::removeBinding(_bindingTarget, property->coreIndex);
+ QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex()));
if (binding->type == QV4::CompiledData::Binding::Type_Script) {
- QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
QV4::Scope scope(v4);
QV4::ScopedContext qmlContext(scope, currentQmlContext());
QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction, /*createProto*/ false));
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
- int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex);
+ int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex());
QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
context, _scopeObject, function);
bs->takeExpression(expr);
} else {
- QQmlBinding *qmlBinding = new QQmlBinding(function, _scopeObject, context);
-
// When writing bindings to grouped properties implemented as value types,
// such as point.x: { someExpression; }, then the binding is installed on
// the point property (_qobjectForBindings) and after evaluating the expression,
// the result is written to a value type virtual property, that contains the sub-index
// of the "x" property.
- QQmlPropertyData targetCorePropertyData = *property;
- if (_valueTypeProperty)
- targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine);
+ QQmlBinding *qmlBinding;
+ if (_valueTypeProperty) {
+ qmlBinding = QQmlBinding::create(_valueTypeProperty, function, _scopeObject, context);
+ qmlBinding->setTarget(_bindingTarget, *_valueTypeProperty, property);
+ } else {
+ qmlBinding = QQmlBinding::create(property, function, _scopeObject, context);
+ qmlBinding->setTarget(_bindingTarget, *property, nullptr);
+ }
sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding));
- qmlBinding->setTarget(_bindingTarget, targetCorePropertyData);
-
- if (targetCorePropertyData.isAlias()) {
+ if (property->isAlias()) {
QQmlPropertyPrivate::setBinding(qmlBinding, QQmlPropertyPrivate::DontEnable);
} else {
qmlBinding->addToObject();
@@ -837,7 +828,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
if (!_valueTypeProperty) {
QQmlData *targetDeclarativeData = QQmlData::get(_bindingTarget);
Q_ASSERT(targetDeclarativeData);
- targetDeclarativeData->setPendingBindingBit(_bindingTarget, property->coreIndex);
+ targetDeclarativeData->setPendingBindingBit(_bindingTarget, property->coreIndex());
}
}
}
@@ -850,15 +841,16 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QQmlType *type = qmlTypeForObject(createdSubObject);
Q_ASSERT(type);
- QQmlPropertyData targetCorePropertyData = *property;
- if (_valueTypeProperty)
- targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine);
-
int valueSourceCast = type->propertyValueSourceCast();
if (valueSourceCast != -1) {
QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast);
QObject *target = createdSubObject->parent();
- vs->setTarget(QQmlPropertyPrivate::restore(target, targetCorePropertyData, context));
+ QQmlProperty prop;
+ if (_valueTypeProperty)
+ prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context);
+ else
+ prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context);
+ vs->setTarget(prop);
return true;
}
int valueInterceptorCast = type->propertyValueInterceptorCast();
@@ -866,25 +858,36 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(createdSubObject) + valueInterceptorCast);
QObject *target = createdSubObject->parent();
- if (targetCorePropertyData.isAlias()) {
- int propIndex;
- QQmlPropertyPrivate::findAliasTarget(target, targetCorePropertyData.coreIndex, &target, &propIndex);
+ QQmlPropertyIndex propertyIndex;
+ if (property->isAlias()) {
+ QQmlPropertyIndex originalIndex(property->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
+ QQmlPropertyIndex propIndex;
+ QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
QQmlData *data = QQmlData::get(target);
if (!data || !data->propertyCache) {
qWarning() << "can't resolve property alias for 'on' assignment";
return false;
}
- targetCorePropertyData = *data->propertyCache->property(propIndex);
- }
- QQmlProperty prop =
- QQmlPropertyPrivate::restore(target, targetCorePropertyData, context);
+ // we can't have aliasses on subproperties of value types, so:
+ QQmlPropertyData targetPropertyData = *data->propertyCache->property(propIndex.coreIndex());
+ auto prop = QQmlPropertyPrivate::restore(target, targetPropertyData, nullptr, context);
+ vi->setTarget(prop);
+ propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
+ } else {
+ QQmlProperty prop;
+ if (_valueTypeProperty)
+ prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context);
+ else
+ prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context);
+ vi->setTarget(prop);
+ propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
+ }
- vi->setTarget(prop);
QQmlInterceptorMetaObject *mo = QQmlInterceptorMetaObject::get(target);
if (!mo)
mo = new QQmlInterceptorMetaObject(target, QQmlData::get(target)->propertyCache);
- mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi);
+ mo->registerInterceptor(propertyIndex, vi);
return true;
}
return false;
@@ -902,7 +905,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
}
- QMetaMethod signalMethod = _qobject->metaObject()->method(property->coreIndex);
+ QMetaMethod signalMethod = _qobject->metaObject()->method(property->coreIndex());
if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
recordError(binding->valueLocation,
tr("Cannot connect mismatched signal/slot %1 %vs. %2")
@@ -911,33 +914,33 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
}
- QQmlPropertyPrivate::connect(_qobject, property->coreIndex, createdSubObject, method.methodIndex());
+ QQmlPropertyPrivate::connect(_qobject, property->coreIndex(), createdSubObject, method.methodIndex());
return true;
}
- QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::RemoveBindingOnAliasWrite;
int propertyWriteStatus = -1;
void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
- if (const char *iid = QQmlMetaType::interfaceIId(property->propType)) {
+ if (const char *iid = QQmlMetaType::interfaceIId(property->propType())) {
void *ptr = createdSubObject->qt_metacast(iid);
if (ptr) {
argv[0] = &ptr;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
} else {
recordError(binding->location, tr("Cannot assign object to interface property"));
return false;
}
- } else if (property->propType == QMetaType::QVariant) {
+ } else if (property->propType() == QMetaType::QVariant) {
if (property->isVarProperty()) {
QV4::Scope scope(v4);
QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(QV8Engine::getV4(engine), createdSubObject));
- _vmeMetaObject->setVMEProperty(property->coreIndex, wrappedObject);
+ _vmeMetaObject->setVMEProperty(property->coreIndex(), wrappedObject);
} else {
QVariant value = QVariant::fromValue(createdSubObject);
argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
}
} else if (property->isQList()) {
Q_ASSERT(_currentList.object);
@@ -945,7 +948,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
void *itemToAdd = createdSubObject;
const char *iid = 0;
- int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType);
+ int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType());
if (listItemType != -1)
iid = QQmlMetaType::interfaceIId(listItemType);
if (iid)
@@ -961,7 +964,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
} else {
// pointer compatibility was tested in QQmlPropertyValidator at type compile time
argv[0] = &createdSubObject;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
}
return true;
}
@@ -981,9 +984,9 @@ void QQmlObjectCreator::setupFunctions()
QV4::ScopedValue function(scope);
QV4::ScopedContext qmlContext(scope, currentQmlContext());
- const quint32 *functionIdx = _compiledObject->functionOffsetTable();
+ const QV4::CompiledData::LEUInt32 *functionIdx = _compiledObject->functionOffsetTable();
for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
- QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[*functionIdx];
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
const QString name = runtimeFunction->name()->toQString();
QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
@@ -991,14 +994,14 @@ void QQmlObjectCreator::setupFunctions()
continue;
function = QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction);
- _vmeMetaObject->setVmeMethod(property->coreIndex, function);
+ _vmeMetaObject->setVmeMethod(property->coreIndex(), function);
}
}
void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setUrl(compiledData->compilationUnit->url());
+ error.setUrl(compilationUnit->url());
error.setLine(location.line);
error.setColumn(location.column);
error.setDescription(description);
@@ -1035,26 +1038,34 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (obj->flags & QV4::CompiledData::Object::IsComponent) {
isComponent = true;
- QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
+ QQmlComponent *component = new QQmlComponent(engine, compilationUnit, index, parent);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compiledData, obj, QStringLiteral("<component>"), context->url()));
+ compilationUnit, obj, QStringLiteral("<component>"), context->url()));
QQmlComponentPrivate::get(component)->creationContext = context;
instance = component;
ddata = QQmlData::get(instance, /*create*/true);
} else {
- QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ QV4::CompiledData::ResolvedTypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
installPropertyCache = !typeRef->isFullyDynamicType;
QQmlType *type = typeRef->type;
if (type) {
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compiledData, obj, type->qmlTypeName(), context->url()));
- instance = type->create();
+ compilationUnit, obj, type->qmlTypeName(), context->url()));
+
+ void *ddataMemory = 0;
+ type->create(&instance, &ddataMemory, sizeof(QQmlData));
if (!instance) {
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
return 0;
}
+ {
+ QQmlData *ddata = new (ddataMemory) QQmlData;
+ ddata->ownMemory = false;
+ QObjectPrivate::get(instance)->declarativeData = ddata;
+ }
+
const int parserStatusCast = type->parserStatusCast();
if (parserStatusCast != -1)
parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
@@ -1069,17 +1080,17 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
sharedState->allCreatedObjects.push(instance);
} else {
- Q_ASSERT(typeRef->component);
+ Q_ASSERT(typeRef->compilationUnit);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compiledData, obj, typeRef->component->compilationUnit->fileName(),
+ compilationUnit, obj, typeRef->compilationUnit->fileName(),
context->url()));
- if (typeRef->component->compilationUnit->data->isSingleton())
+ if (typeRef->compilationUnit->data->isSingleton())
{
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
return 0;
}
- QQmlObjectCreator subCreator(context, typeRef->component, sharedState.data());
+ QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data());
instance = subCreator.create();
if (!instance) {
errors += subCreator.errors;
@@ -1127,7 +1138,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
customParser->engine = QQmlEnginePrivate::get(engine);
- customParser->imports = compiledData->compilationUnit->importCache;
+ customParser->imports = compilationUnit->importCache;
QList<const QV4::CompiledData::Binding *> bindings;
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
@@ -1137,7 +1148,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
bindings << binding;
}
}
- customParser->applyBindings(instance, compiledData->compilationUnit.data(), bindings);
+ customParser->applyBindings(instance, compilationUnit, bindings);
customParser->engine = 0;
customParser->imports = (QQmlTypeNameCache*)0;
@@ -1148,7 +1159,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
return instance;
}
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index).data();
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(index);
Q_ASSERT(!cache.isNull());
if (installPropertyCache) {
if (ddata->propertyCache)
@@ -1193,9 +1204,9 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
continue;
QQmlData *data = QQmlData::get(b->targetObject());
Q_ASSERT(data);
- data->clearPendingBindingBit(b->targetPropertyIndex());
- b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::DontRemoveBinding);
+ data->clearPendingBindingBit(b->targetPropertyIndex().coreIndex());
+ b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::DontRemoveBinding);
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
return 0;
@@ -1279,14 +1290,13 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
QV4::Scope valueScope(v4);
QV4::ScopedValue scopeObjectProtector(valueScope);
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(_compiledObjectIndex).data();
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(_compiledObjectIndex);
QQmlVMEMetaObject *vmeMetaObject = 0;
- const bool needVMEMetaObject = propertyCaches.at(_compiledObjectIndex).flag();
- if (needVMEMetaObject) {
+ if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) {
Q_ASSERT(!cache.isNull());
// install on _object
- vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, compiledData->compilationUnit, _compiledObjectIndex);
+ vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, compilationUnit, _compiledObjectIndex);
if (_ddata->propertyCache)
_ddata->propertyCache->release();
_ddata->propertyCache = cache;
@@ -1304,8 +1314,8 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) {
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
deferData->deferredIdx = _compiledObjectIndex;
- deferData->compiledData = compiledData;
- deferData->compiledData->addref();
+ deferData->compilationUnit = compilationUnit;
+ deferData->compilationUnit->addref();
deferData->context = context;
_ddata->deferredData = deferData;
}
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index f51cf3a2ca..e3312f9df5 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -53,7 +53,6 @@
#include <private/qqmlimport_p.h>
#include <private/qqmltypenamecache_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qqmltypecompiler_p.h>
#include <private/qfinitestack_p.h>
#include <private/qrecursionwatcher_p.h>
@@ -66,7 +65,6 @@ QT_BEGIN_NAMESPACE
class QQmlAbstractBinding;
struct QQmlTypeCompiler;
class QQmlInstantiationInterrupt;
-struct QQmlVmeProfiler;
struct QQmlObjectCreatorSharedState : public QSharedData
{
@@ -86,7 +84,7 @@ class QQmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
- QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext = 0);
+ QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *creationContext, void *activeVMEDataForRootContext = 0);
~QQmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = 0, QQmlInstantiationInterrupt *interrupt = 0);
@@ -104,7 +102,7 @@ public:
QFiniteStack<QPointer<QObject> > &allCreatedObjects() const { return sharedState->allCreatedObjects; }
private:
- QQmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState);
+ QQmlObjectCreator(QQmlContextData *contextData, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
void init(QQmlContextData *parentContext);
@@ -136,12 +134,12 @@ private:
QQmlEngine *engine;
QV4::ExecutionEngine *v4;
- QQmlCompiledData *compiledData;
+ QV4::CompiledData::CompilationUnit *compilationUnit;
const QV4::CompiledData::Unit *qmlUnit;
QQmlGuardedContextData parentContext;
QQmlContextData *context;
- const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
- const QQmlPropertyCacheVector &propertyCaches;
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
+ const QQmlPropertyCacheVector *propertyCaches;
QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
bool topLevelCreator;
void *activeVMEDataForRootContext;
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index 22c4072aec..49f02476a2 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -278,7 +278,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
propertyRead(propId);
*reinterpret_cast<QVariant *>(a[0]) = d->getData(propId);
} else if (c == QMetaObject::WriteProperty) {
- if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast<QVariant *>(a[0])) {
+ if (propId >= d->data.count() || d->data.at(propId).first != *reinterpret_cast<QVariant *>(a[0])) {
propertyWrite(propId);
QPair<QVariant, bool> &prop = d->getDataRef(propId);
prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0]));
diff --git a/src/qml/qml/qqmlopenmetaobject_p.h b/src/qml/qml/qqmlopenmetaobject_p.h
index f1562131fc..183baec941 100644
--- a/src/qml/qml/qqmlopenmetaobject_p.h
+++ b/src/qml/qml/qqmlopenmetaobject_p.h
@@ -122,8 +122,8 @@ public:
void emitPropertyNotification(const QByteArray &propertyName);
protected:
- virtual int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a);
- virtual int createProperty(const char *, const char *);
+ int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
+ int createProperty(const char *, const char *) override;
virtual void propertyRead(int);
virtual void propertyWrite(int);
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index df2ff05de1..c62fef7c3d 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -42,6 +42,7 @@
#include "qqml.h"
#include "qqmlbinding_p.h"
+#include "qqmlboundsignal_p.h"
#include "qqmlcontext.h"
#include "qqmlcontext_p.h"
#include "qqmlboundsignal_p.h"
@@ -50,7 +51,6 @@
#include "qqmldata_p.h"
#include "qqmlstringconverters_p.h"
#include "qqmllist_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlvmemetaobject_p.h"
#include "qqmlexpression_p.h"
#include "qqmlvaluetypeproxybinding_p.h"
@@ -291,9 +291,9 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
if (property->isFunction())
return; // Not an object property
- if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) {
+ if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType())) {
// We're now at a value type property
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType);
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType());
if (!valueTypeMetaObject) return; // Not a value type
int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData());
@@ -301,24 +301,21 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QMetaProperty vtProp = valueTypeMetaObject->property(idx);
- Q_ASSERT(QQmlPropertyData::flagsForProperty(vtProp) <= QQmlPropertyData::ValueTypeFlagMask);
Q_ASSERT(vtProp.userType() <= 0x0000FFFF);
Q_ASSERT(idx <= 0x0000FFFF);
object = currentObject;
core = *property;
- core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
- core.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp);
- core.valueTypePropType = vtProp.userType();
- core.valueTypeCoreIndex = idx;
+ valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp));
+ valueTypeData.setPropType(vtProp.userType());
+ valueTypeData.setCoreIndex(idx);
return;
} else {
if (!property->isQObject())
return; // Not an object property
- void *args[] = { &currentObject, 0 };
- QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
+ property->readProperty(currentObject, &currentObject);
if (!currentObject) return; // No value
}
@@ -358,9 +355,9 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
while (d && d->isFunction())
d = ddata->propertyCache->overrideData(d);
- if (d && d->notifyIndex != -1) {
+ if (d && d->notifyIndex() != -1) {
object = currentObject;
- core = *ddata->propertyCache->signal(d->notifyIndex);
+ core = *ddata->propertyCache->signal(d->notifyIndex());
return;
}
}
@@ -397,7 +394,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
int QQmlPropertyPrivate::signalIndex() const
{
Q_ASSERT(type() == QQmlProperty::SignalProperty);
- QMetaMethod m = object->metaObject()->method(core.coreIndex);
+ QMetaMethod m = object->metaObject()->method(core.coreIndex());
return QMetaObjectPrivate::signalIndex(m);
}
@@ -473,11 +470,11 @@ const char *QQmlProperty::propertyTypeName() const
if (!d)
return 0;
if (d->isValueType()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType);
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType());
Q_ASSERT(valueTypeMetaObject);
- return valueTypeMetaObject->property(d->core.valueTypeCoreIndex).typeName();
+ return valueTypeMetaObject->property(d->valueTypeData.coreIndex()).typeName();
} else if (d->object && type() & Property && d->core.isValid()) {
- return d->object->metaObject()->property(d->core.coreIndex).typeName();
+ return d->object->metaObject()->property(d->core.coreIndex()).typeName();
} else {
return 0;
}
@@ -494,11 +491,8 @@ bool QQmlProperty::operator==(const QQmlProperty &other) const
// category is intentially omitted here as it is generated
// from the other members
return d->object == other.d->object &&
- d->core.coreIndex == other.d->core.coreIndex &&
- d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() &&
- (!d->core.isValueTypeVirtual() ||
- (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex &&
- d->core.valueTypePropType == other.d->core.valueTypePropType));
+ d->core.coreIndex() == other.d->core.coreIndex() &&
+ d->valueTypeData.coreIndex() == other.d->valueTypeData.coreIndex();
}
/*!
@@ -512,16 +506,16 @@ int QQmlProperty::propertyType() const
bool QQmlPropertyPrivate::isValueType() const
{
- return core.isValueTypeVirtual();
+ return valueTypeData.isValid();
}
int QQmlPropertyPrivate::propertyType() const
{
uint type = this->type();
if (isValueType()) {
- return core.valueTypePropType;
+ return valueTypeData.propType();
} else if (type & QQmlProperty::Property) {
- return core.propType;
+ return core.propType();
} else {
return QVariant::Invalid;
}
@@ -610,7 +604,7 @@ bool QQmlProperty::isDesignable() const
if (!d)
return false;
if (type() & Property && d->core.isValid() && d->object)
- return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
+ return d->object->metaObject()->property(d->core.coreIndex()).isDesignable();
else
return false;
}
@@ -650,15 +644,11 @@ QString QQmlProperty::name() const
// ###
if (!d->object) {
} else if (d->isValueType()) {
- QString rv = d->core.name(d->object) + QLatin1Char('.');
-
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType);
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType());
Q_ASSERT(valueTypeMetaObject);
- const char *vtName = valueTypeMetaObject->property(d->core.valueTypeCoreIndex).name();
- rv += QString::fromUtf8(vtName);
-
- d->nameCache = rv;
+ const char *vtName = valueTypeMetaObject->property(d->valueTypeData.coreIndex()).name();
+ d->nameCache = d->core.name(d->object) + QLatin1Char('.') + QString::fromUtf8(vtName);
} else if (type() & SignalProperty) {
QString name = QLatin1String("on") + d->core.name(d->object);
name[2] = name.at(2).toUpper();
@@ -681,7 +671,7 @@ QMetaProperty QQmlProperty::property() const
if (!d)
return QMetaProperty();
if (type() & Property && d->core.isValid() && d->object)
- return d->object->metaObject()->property(d->core.coreIndex);
+ return d->object->metaObject()->property(d->core.coreIndex());
else
return QMetaProperty();
}
@@ -695,7 +685,7 @@ QMetaMethod QQmlProperty::method() const
if (!d)
return QMetaMethod();
if (type() & SignalProperty && d->object)
- return d->object->metaObject()->method(d->core.coreIndex);
+ return d->object->metaObject()->method(d->core.coreIndex());
else
return QMetaMethod();
}
@@ -710,7 +700,8 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that)
if (!that.d || !that.isProperty() || !that.d->object)
return 0;
- return binding(that.d->object, that.d->core.encodedIndex());
+ QQmlPropertyIndex thatIndex(that.d->core.coreIndex(), that.d->valueTypeData.coreIndex());
+ return binding(that.d->object, thatIndex);
}
/*!
@@ -742,10 +733,10 @@ QQmlPropertyPrivate::setBinding(const QQmlProperty &that, QQmlAbstractBinding *n
setBinding(newBinding);
}
-static void removeOldBinding(QObject *object, int index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None)
+static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None)
{
- int coreIndex;
- int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex);
+ int coreIndex = index.coreIndex();
+ int valueTypeIndex = index.valueTypeIndex();
QQmlData *data = QQmlData::get(object, false);
@@ -755,7 +746,8 @@ static void removeOldBinding(QObject *object, int index, QQmlPropertyPrivate::Bi
QQmlAbstractBinding::Ptr oldBinding;
oldBinding = data->bindings;
- while (oldBinding && oldBinding->targetPropertyIndex() != coreIndex)
+ while (oldBinding && (oldBinding->targetPropertyIndex().coreIndex() != coreIndex ||
+ oldBinding->targetPropertyIndex().hasValueTypeIndex()))
oldBinding = oldBinding->nextBinding();
if (!oldBinding)
@@ -777,12 +769,12 @@ void QQmlPropertyPrivate::removeBinding(QQmlAbstractBinding *b)
removeBinding(b->targetObject(), b->targetPropertyIndex());
}
-void QQmlPropertyPrivate::removeBinding(QObject *o, int index)
+void QQmlPropertyPrivate::removeBinding(QObject *o, QQmlPropertyIndex index)
{
Q_ASSERT(o);
QObject *target;
- int targetIndex;
+ QQmlPropertyIndex targetIndex;
findAliasTarget(o, index, &target, &targetIndex);
removeOldBinding(target, targetIndex);
}
@@ -792,11 +784,11 @@ void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that)
if (!that.d || !that.isProperty() || !that.d->object)
return;
- removeBinding(that.d->object, that.d->core.encodedIndex());
+ removeBinding(that.d->object, that.d->encodedIndex());
}
QQmlAbstractBinding *
-QQmlPropertyPrivate::binding(QObject *object, int index)
+QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index)
{
QQmlData *data = QQmlData::get(object);
if (!data)
@@ -804,19 +796,19 @@ QQmlPropertyPrivate::binding(QObject *object, int index)
findAliasTarget(object, index, &object, &index);
- int coreIndex;
- int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex);
+ const int coreIndex = index.coreIndex();
+ const int valueTypeIndex = index.valueTypeIndex();
if (!data->hasBindingBit(coreIndex))
return 0;
QQmlAbstractBinding *binding = data->bindings;
- while (binding && binding->targetPropertyIndex() != coreIndex)
+ while (binding && (binding->targetPropertyIndex().coreIndex() != coreIndex ||
+ binding->targetPropertyIndex().hasValueTypeIndex()))
binding = binding->nextBinding();
if (binding && valueTypeIndex != -1) {
if (binding->isValueTypeProxy()) {
- int index = QQmlPropertyData::encodeValueTypePropertyIndex(coreIndex, valueTypeIndex);
binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
}
}
@@ -824,13 +816,14 @@ QQmlPropertyPrivate::binding(QObject *object, int index)
return binding;
}
-void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
- QObject **targetObject, int *targetBindingIndex)
+void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bindingIndex,
+ QObject **targetObject,
+ QQmlPropertyIndex *targetBindingIndex)
{
QQmlData *data = QQmlData::get(object, false);
if (data) {
- int coreIndex;
- int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(bindingIndex, &coreIndex);
+ int coreIndex = bindingIndex.coreIndex();
+ int valueTypeIndex = bindingIndex.valueTypeIndex();
QQmlPropertyData *propertyData =
data->propertyCache?data->propertyCache->property(coreIndex):0;
@@ -842,11 +835,12 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
// This will either be a value type sub-reference or an alias to a value-type sub-reference not both
Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
- int aBindingIndex = aCoreIndex;
- if (aValueTypeIndex != -1)
- aBindingIndex = QQmlPropertyData::encodeValueTypePropertyIndex(aBindingIndex, aValueTypeIndex);
- else if (valueTypeIndex != -1)
- aBindingIndex = QQmlPropertyData::encodeValueTypePropertyIndex(aBindingIndex, valueTypeIndex);
+ QQmlPropertyIndex aBindingIndex(aCoreIndex);
+ if (aValueTypeIndex != -1) {
+ aBindingIndex = QQmlPropertyIndex(aCoreIndex, aValueTypeIndex);
+ } else if (valueTypeIndex != -1) {
+ aBindingIndex = QQmlPropertyIndex(aCoreIndex, valueTypeIndex);
+ }
findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
return;
@@ -859,16 +853,15 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
}
-void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, WriteFlags writeFlags)
+void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags)
{
Q_ASSERT(binding);
QObject *object = binding->targetObject();
- int index = binding->targetPropertyIndex();
+ const QQmlPropertyIndex index = binding->targetPropertyIndex();
#ifndef QT_NO_DEBUG
- int coreIndex;
- QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex);
+ int coreIndex = index.coreIndex();
QQmlData *data = QQmlData::get(object, true);
if (data->propertyCache) {
QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
@@ -1027,42 +1020,40 @@ QVariant QQmlPropertyPrivate::readValueProperty()
{
if (isValueType()) {
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType);
+ QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType());
Q_ASSERT(valueType);
- valueType->read(object, core.coreIndex);
- return valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
+ valueType->read(object, core.coreIndex());
+ return valueType->metaObject()->property(valueTypeData.coreIndex()).read(valueType);
} else if (core.isQList()) {
QQmlListProperty<QObject> prop;
- void *args[] = { &prop, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
- return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
+ core.readProperty(object, &prop);
+ return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType(), engine));
} else if (core.isQObject()) {
QObject *rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ core.readProperty(object, &rv);
return QVariant::fromValue(rv);
} else {
- if (!core.propType) // Unregistered type
- return object->metaObject()->property(core.coreIndex).read(object);
+ if (!core.propType()) // Unregistered type
+ return object->metaObject()->property(core.coreIndex()).read(object);
QVariant value;
int status = -1;
void *args[] = { 0, &value, &status };
- if (core.propType == QMetaType::QVariant) {
+ if (core.propType() == QMetaType::QVariant) {
args[0] = &value;
} else {
- value = QVariant(core.propType, (void*)0);
+ value = QVariant(core.propType(), (void*)0);
args[0] = value.data();
}
- QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
- if (core.propType != QMetaType::QVariant && args[0] != value.data())
- return QVariant((QVariant::Type)core.propType, args[0]);
+ core.readPropertyWithArgs(object, args);
+ if (core.propType() != QMetaType::QVariant && args[0] != value.data())
+ return QVariant((QVariant::Type)core.propType(), args[0]);
return value;
}
@@ -1148,40 +1139,30 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx,
return status;
}
-bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
+bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, QQmlPropertyData::WriteFlags flags)
{
- return writeValueProperty(object, core, value, effectiveContext(), flags);
+ return writeValueProperty(object, core, valueTypeData, value, effectiveContext(), flags);
}
bool
QQmlPropertyPrivate::writeValueProperty(QObject *object,
const QQmlPropertyData &core,
+ const QQmlPropertyData &valueTypeData,
const QVariant &value,
- QQmlContextData *context, WriteFlags flags)
+ QQmlContextData *context,QQmlPropertyData::WriteFlags flags)
{
// Remove any existing bindings on this property
- if (!(flags & DontRemoveBinding) && object)
- removeBinding(object, core.encodedIndex());
+ if (!(flags & QQmlPropertyData::DontRemoveBinding) && object)
+ removeBinding(object, encodedIndex(core, valueTypeData));
bool rv = false;
- if (core.isValueTypeVirtual()) {
-
- QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType);
- writeBack->read(object, core.coreIndex);
-
- QQmlPropertyData data = core;
- data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
- data.coreIndex = core.valueTypeCoreIndex;
- data.propType = core.valueTypePropType;
-
- rv = write(writeBack, data, value, context, flags);
-
- writeBack->write(object, core.coreIndex, flags);
-
+ if (valueTypeData.isValid()) {
+ QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType());
+ writeBack->read(object, core.coreIndex());
+ rv = write(writeBack, valueTypeData, value, context, flags);
+ writeBack->write(object, core.coreIndex(), flags);
} else {
-
rv = write(object, core, value, context, flags);
-
}
return rv;
@@ -1190,173 +1171,158 @@ QQmlPropertyPrivate::writeValueProperty(QObject *object,
bool QQmlPropertyPrivate::write(QObject *object,
const QQmlPropertyData &property,
const QVariant &value, QQmlContextData *context,
- WriteFlags flags)
+ QQmlPropertyData::WriteFlags flags)
{
- int coreIdx = property.coreIndex;
- int status = -1; //for dbus
+ const int propertyType = property.propType();
+ const int variantType = value.userType();
if (property.isEnum()) {
- QMetaProperty prop = object->metaObject()->property(property.coreIndex);
+ QMetaProperty prop = object->metaObject()->property(property.coreIndex());
QVariant v = value;
// Enum values come through the script engine as doubles
- if (value.userType() == QVariant::Double) {
+ if (variantType == QVariant::Double) {
double integral;
double fractional = std::modf(value.toDouble(), &integral);
if (qFuzzyIsNull(fractional))
v.convert(QVariant::Int);
}
- return writeEnumProperty(prop, coreIdx, object, v, flags);
+ return writeEnumProperty(prop, property.coreIndex(), object, v, flags);
}
- int propertyType = property.propType;
- int variantType = value.userType();
-
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
+ const bool isUrl = propertyType == QVariant::Url; // handled separately
+
+ // The cases below are in approximate order of likelyhood:
+ if (propertyType == variantType && !isUrl && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
+ return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
+ } else if (property.isQObject()) {
+ QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, variantType);
+ if (valMo.isNull())
+ return false;
+ QObject *o = *static_cast<QObject *const *>(value.constData());
+ QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
- if (propertyType == QVariant::Url) {
+ if (o)
+ valMo = o;
+ if (QQmlMetaObject::canConvert(valMo, propMo)) {
+ return property.writeProperty(object, &o, flags);
+ } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
+ // In the case of a null QObject, we assign the null if there is
+ // any change that the null variant type could be up or down cast to
+ // the property type.
+ return property.writeProperty(object, &o, flags);
+ } else {
+ return false;
+ }
+ } else if (value.canConvert(propertyType) && !isUrl && variantType != QVariant::String && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
+ // common cases:
+ switch (propertyType) {
+ case QMetaType::Bool: {
+ bool b = value.toBool();
+ return property.writeProperty(object, &b, flags);
+ }
+ case QMetaType::Int: {
+ int i = value.toInt();
+ return property.writeProperty(object, &i, flags);
+ }
+ case QMetaType::Double: {
+ double d = value.toDouble();
+ return property.writeProperty(object, &d, flags);
+ }
+ case QMetaType::Float: {
+ float f = value.toFloat();
+ return property.writeProperty(object, &f, flags);
+ }
+ case QMetaType::QString: {
+ QString s = value.toString();
+ return property.writeProperty(object, &s, flags);
+ }
+ default: { // "fallback":
+ QVariant v = value;
+ v.convert(propertyType);
+ return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
+ }
+ }
+ } else if (propertyType == qMetaTypeId<QVariant>()) {
+ return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
+ } else if (isUrl) {
QUrl u;
- bool found = false;
if (variantType == QVariant::Url) {
u = value.toUrl();
- found = true;
} else if (variantType == QVariant::ByteArray) {
QString input(QString::fromUtf8(value.toByteArray()));
// Encoded dir-separators defeat QUrl processing - decode them first
input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
u = QUrl(input);
- found = true;
} else if (variantType == QVariant::String) {
QString input(value.toString());
// Encoded dir-separators defeat QUrl processing - decode them first
input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
u = QUrl(input);
- found = true;
- }
-
- if (!found)
- return false;
-
- if (context && u.isRelative() && !u.isEmpty())
- u = context->resolvedUrl(u);
- int status = -1;
- void *argv[] = { &u, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
-
- } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
- QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
- int status = -1;
- void *argv[] = { &urlSeq, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
- } else if (variantType == propertyType) {
-
- void *a[] = { const_cast<void *>(value.constData()), 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
-
- } else if (qMetaTypeId<QVariant>() == propertyType) {
-
- void *a[] = { const_cast<QVariant *>(&value), 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
-
- } else if (property.isQObject()) {
-
- QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, value.userType());
-
- if (valMo.isNull())
- return false;
-
- QObject *o = *(QObject *const *)value.constData();
- QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
-
- if (o) valMo = o;
-
- if (QQmlMetaObject::canConvert(valMo, propMo)) {
- void *args[] = { &o, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
- } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
- // In the case of a null QObject, we assign the null if there is
- // any change that the null variant type could be up or down cast to
- // the property type.
- void *args[] = { &o, 0, &status, &flags };
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
} else {
return false;
}
+ if (context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
+ return property.writeProperty(object, &u, flags);
+ } else if (propertyType == qMetaTypeId<QList<QUrl>>()) {
+ QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl>>();
+ return property.writeProperty(object, &urlSeq, flags);
} else if (property.isQList()) {
-
QQmlMetaObject listType;
if (enginePriv) {
- listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
+ listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType()));
} else {
- QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
- if (!type) return false;
+ QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType()));
+ if (!type)
+ return false;
listType = type->baseMetaObject();
}
- if (listType.isNull()) return false;
+ if (listType.isNull())
+ return false;
QQmlListProperty<void> prop;
- void *args[] = { &prop, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
+ property.readProperty(object, &prop);
- if (!prop.clear) return false;
+ if (!prop.clear)
+ return false;
prop.clear(&prop);
- if (value.userType() == qMetaTypeId<QQmlListReference>()) {
+ if (variantType == qMetaTypeId<QQmlListReference>()) {
QQmlListReference qdlr = value.value<QQmlListReference>();
for (int ii = 0; ii < qdlr.count(); ++ii) {
QObject *o = qdlr.at(ii);
if (o && !QQmlMetaObject::canConvert(o, listType))
- o = 0;
- prop.append(&prop, (void *)o);
+ o = nullptr;
+ prop.append(&prop, o);
}
- } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
+ } else if (variantType == qMetaTypeId<QList<QObject *> >()) {
const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
for (int ii = 0; ii < list.count(); ++ii) {
QObject *o = list.at(ii);
if (o && !QQmlMetaObject::canConvert(o, listType))
- o = 0;
- prop.append(&prop, (void *)o);
+ o = nullptr;
+ prop.append(&prop, o);
}
} else {
QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
if (o && !QQmlMetaObject::canConvert(o, listType))
- o = 0;
- prop.append(&prop, (void *)o);
+ o = nullptr;
+ prop.append(&prop, o);
}
-
} else {
Q_ASSERT(variantType != propertyType);
bool ok = false;
QVariant v;
- if (variantType == QVariant::String) {
- const QString &str = value.toString();
- const bool targetIsChar = (propertyType == qMetaTypeId<QChar>()
- || propertyType == qMetaTypeId<char>()
- || propertyType == qMetaTypeId<unsigned char>());
- // If the string contains only one character and the target is a char, try converting it.
- if (targetIsChar) {
- if (str.size() != 1)
- return false; // We can only convert if the string contains exactly one character.
-
- const QChar &qChar = str.at(0);
- if (propertyType == qMetaTypeId<QChar>()) {
- v = qChar;
- ok = true;
- } else if (propertyType == qMetaTypeId<char>() || propertyType == qMetaTypeId<unsigned char>()) {
- const char c = qChar.toLatin1();
- v = c;
- ok = (qChar == c);
- }
- } else {
- v = QQmlStringConverters::variantFromString(str, propertyType, &ok);
- }
- }
+ if (variantType == QVariant::String)
+ v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
if (!ok) {
v = value;
@@ -1368,7 +1334,8 @@ bool QQmlPropertyPrivate::write(QObject *object,
// successful conversion.
Q_ASSERT(v.userType() == propertyType);
ok = true;
- } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
+ } else if (static_cast<uint>(propertyType) >= QVariant::UserType &&
+ variantType == QVariant::String) {
QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
if (con) {
v = con(value.toString());
@@ -1411,8 +1378,7 @@ bool QQmlPropertyPrivate::write(QObject *object,
}
if (ok) {
- void *a[] = { const_cast<void *>(v.constData()), 0, &status, &flags};
- QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+ return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
} else {
return false;
}
@@ -1428,10 +1394,9 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi
return metaType.metaObject();
if (engine)
return engine->rawMetaObjectForType(userType);
- QQmlType *type = QQmlMetaType::qmlType(userType);
- if (type)
+ if (QQmlType *type = QQmlMetaType::qmlType(userType))
return QQmlMetaObject(type->baseMetaObject());
- return QQmlMetaObject((QObject*)0);
+ return QQmlMetaObject();
}
/*!
@@ -1505,7 +1470,7 @@ bool QQmlProperty::reset() const
{
if (isResettable()) {
void *args[] = { 0 };
- QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
+ QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex(), args);
return true;
} else {
return false;
@@ -1513,7 +1478,7 @@ bool QQmlProperty::reset() const
}
bool QQmlPropertyPrivate::write(const QQmlProperty &that,
- const QVariant &value, WriteFlags flags)
+ const QVariant &value, QQmlPropertyData::WriteFlags flags)
{
if (!that.d)
return false;
@@ -1530,7 +1495,7 @@ bool QQmlPropertyPrivate::write(const QQmlProperty &that,
bool QQmlProperty::hasNotifySignal() const
{
if (type() & Property && d->object) {
- return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
+ return d->object->metaObject()->property(d->core.coreIndex()).hasNotifySignal();
}
return false;
}
@@ -1560,7 +1525,7 @@ bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
if (!(type() & Property) || !d->object)
return false;
- QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex());
if (prop.hasNotifySignal()) {
return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
} else {
@@ -1581,7 +1546,7 @@ bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
if (!(type() & Property) || !d->object)
return false;
- QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex());
if (prop.hasNotifySignal()) {
QByteArray signal('2' + prop.notifySignal().methodSignature());
return QObject::connect(d->object, signal.constData(), dest, slot);
@@ -1595,61 +1560,28 @@ bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
*/
int QQmlProperty::index() const
{
- return d ? d->core.coreIndex : -1;
+ return d ? d->core.coreIndex() : -1;
}
-int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
-{
- return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
-}
-
-/*!
- Returns the "property index" for use in bindings. The top 16 bits are the value type
- offset, and 0 otherwise. The bottom 16 bits are the regular property index.
-*/
-int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
+QQmlPropertyIndex QQmlPropertyPrivate::propertyIndex(const QQmlProperty &that)
{
- if (!that.d)
- return -1;
- return bindingIndex(that.d->core);
-}
-
-int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
-{
- int rv = that.coreIndex;
- if (rv != -1 && that.isValueTypeVirtual())
- rv = rv | (that.valueTypeCoreIndex << 16);
- return rv;
-}
-
-QQmlPropertyData
-QQmlPropertyPrivate::saveValueType(const QQmlPropertyData &base,
- const QMetaObject *subObject, int subIndex,
- QQmlEngine *)
-{
- QMetaProperty subProp = subObject->property(subIndex);
-
- QQmlPropertyData core = base;
- core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
- core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
- core.valueTypeCoreIndex = subIndex;
- core.valueTypePropType = subProp.userType();
-
- return core;
+ return that.d ? that.d->encodedIndex() : QQmlPropertyIndex();
}
QQmlProperty
QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
- QQmlContextData *ctxt)
+ const QQmlPropertyData *valueTypeData, QQmlContextData *ctxt)
{
QQmlProperty prop;
prop.d = new QQmlPropertyPrivate;
prop.d->object = object;
prop.d->context = ctxt;
- prop.d->engine = ctxt?ctxt->engine:0;
+ prop.d->engine = ctxt ? ctxt->engine : nullptr;
prop.d->core = data;
+ if (valueTypeData)
+ prop.d->valueTypeData = *valueTypeData;
return prop;
}
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 58fea9c239..2565ec0ce6 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -68,24 +68,23 @@ class QQmlJavaScriptExpression;
class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount
{
public:
- enum WriteFlag {
- BypassInterceptor = 0x01,
- DontRemoveBinding = 0x02,
- RemoveBindingOnAliasWrite = 0x04
- };
- Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
-
QQmlContextData *context;
QPointer<QQmlEngine> engine;
QPointer<QObject> object;
QQmlPropertyData core;
+ QQmlPropertyData valueTypeData;
bool isNameCached:1;
QString nameCache;
QQmlPropertyPrivate();
+ QQmlPropertyIndex encodedIndex() const
+ { return encodedIndex(core, valueTypeData); }
+ static QQmlPropertyIndex encodedIndex(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData)
+ { return QQmlPropertyIndex(core.coreIndex(), valueTypeData.coreIndex()); }
+
inline QQmlContextData *effectiveContext() const;
void initProperty(QObject *obj, const QString &name);
@@ -97,18 +96,18 @@ public:
QQmlProperty::PropertyTypeCategory propertyTypeCategory() const;
QVariant readValueProperty();
- bool writeValueProperty(const QVariant &, WriteFlags);
+ bool writeValueProperty(const QVariant &, QQmlPropertyData::WriteFlags);
static QQmlMetaObject rawMetaObjectForType(QQmlEnginePrivate *, int);
static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object,
const QVariant &value, int flags);
static bool writeValueProperty(QObject *,
- const QQmlPropertyData &,
+ const QQmlPropertyData &, const QQmlPropertyData &valueTypeData,
const QVariant &, QQmlContextData *,
- WriteFlags flags = 0);
+ QQmlPropertyData::WriteFlags flags = 0);
static bool write(QObject *, const QQmlPropertyData &, const QVariant &,
- QQmlContextData *, WriteFlags flags = 0);
- static void findAliasTarget(QObject *, int, QObject **, int *);
+ QQmlContextData *, QQmlPropertyData::WriteFlags flags = 0);
+ static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *);
enum BindingFlag {
None = 0,
@@ -116,19 +115,15 @@ public:
};
Q_DECLARE_FLAGS(BindingFlags, BindingFlag)
- static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, WriteFlags writeFlags = DontRemoveBinding);
+ static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, QQmlPropertyData::WriteFlags writeFlags = QQmlPropertyData::DontRemoveBinding);
static void removeBinding(const QQmlProperty &that);
- static void removeBinding(QObject *o, int index);
+ static void removeBinding(QObject *o, QQmlPropertyIndex index);
static void removeBinding(QQmlAbstractBinding *b);
- static QQmlAbstractBinding *binding(QObject *, int index);
+ static QQmlAbstractBinding *binding(QObject *, QQmlPropertyIndex index);
- static QQmlPropertyData saveValueType(const QQmlPropertyData &,
- const QMetaObject *, int,
- QQmlEngine *);
- static QQmlProperty restore(QObject *,
- const QQmlPropertyData &,
- QQmlContextData *);
+ static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *,
+ QQmlContextData *);
int signalIndex() const;
@@ -144,10 +139,8 @@ public:
QQmlBoundSignalExpression *);
static void takeSignalExpression(const QQmlProperty &that,
QQmlBoundSignalExpression *);
- static bool write(const QQmlProperty &that, const QVariant &, WriteFlags);
- static int valueTypeCoreIndex(const QQmlProperty &that);
- static int bindingIndex(const QQmlProperty &that);
- static int bindingIndex(const QQmlPropertyData &that);
+ static bool write(const QQmlProperty &that, const QVariant &, QQmlPropertyData::WriteFlags);
+ static QQmlPropertyIndex propertyIndex(const QQmlProperty &that);
static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &);
static bool connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
@@ -157,7 +150,6 @@ public:
static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context);
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::WriteFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags)
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 08d51ecfa1..337c37b5be 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -45,12 +45,12 @@
#include <private/qv8engine_p.h>
#include <private/qmetaobject_p.h>
-#include <private/qqmlaccessors_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <private/qv4value_p.h>
#include <QtCore/qdebug.h>
+#include <QtCore/QCryptographicHash>
#include <ctype.h> // for toupper
#include <limits.h>
@@ -85,51 +85,45 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
{
QQmlPropertyData::Flags flags;
- if (p.isConstant())
- flags |= QQmlPropertyData::IsConstant;
- if (p.isWritable())
- flags |= QQmlPropertyData::IsWritable;
- if (p.isResettable())
- flags |= QQmlPropertyData::IsResettable;
- if (p.isFinal())
- flags |= QQmlPropertyData::IsFinal;
+ flags.isConstant = p.isConstant();
+ flags.isWritable = p.isWritable();
+ flags.isResettable = p.isResettable();
+ flags.isFinal = p.isFinal();
+
if (p.isEnumType())
- flags |= QQmlPropertyData::IsEnumType;
+ flags.type = QQmlPropertyData::Flags::EnumType;
return flags;
}
// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
// load
-static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
+static void flagsForPropertyType(int propType, QQmlEngine *engine, QQmlPropertyData::Flags &flags)
{
Q_ASSERT(propType != -1);
- QQmlPropertyData::Flags flags;
-
if (propType == QMetaType::QObjectStar) {
- flags |= QQmlPropertyData::IsQObjectDerived;
+ flags.type = QQmlPropertyData::Flags::QObjectDerivedType;
} else if (propType == QMetaType::QVariant) {
- flags |= QQmlPropertyData::IsQVariant;
- } else if (propType < (int)QVariant::UserType) {
+ flags.type = QQmlPropertyData::Flags::QVariantType;
+ } else if (propType < static_cast<int>(QVariant::UserType)) {
+ // nothing to do
} else if (propType == qMetaTypeId<QQmlBinding *>()) {
- flags |= QQmlPropertyData::IsQmlBinding;
+ flags.type = QQmlPropertyData::Flags::QmlBindingType;
} else if (propType == qMetaTypeId<QJSValue>()) {
- flags |= QQmlPropertyData::IsQJSValue;
+ flags.type = QQmlPropertyData::Flags::QJSValueType;
} else if (propType == qMetaTypeId<QQmlV4Handle>()) {
- flags |= QQmlPropertyData::IsV4Handle;
+ flags.type = QQmlPropertyData::Flags::V4HandleType;
} else {
QQmlMetaType::TypeCategory cat =
engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
: QQmlMetaType::typeCategory(propType);
if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject)
- flags |= QQmlPropertyData::IsQObjectDerived;
+ flags.type = QQmlPropertyData::Flags::QObjectDerivedType;
else if (cat == QQmlMetaType::List)
- flags |= QQmlPropertyData::IsQList;
+ flags.type = QQmlPropertyData::Flags::QListType;
}
-
- return flags;
}
static int metaObjectSignalCount(const QMetaObject *metaObject)
@@ -143,95 +137,107 @@ static int metaObjectSignalCount(const QMetaObject *metaObject)
QQmlPropertyData::Flags
QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine)
{
- return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
+ auto flags = fastFlagsForProperty(p);
+ flagsForPropertyType(p.userType(), engine, flags);
+ return flags;
}
void QQmlPropertyData::lazyLoad(const QMetaProperty &p)
{
- coreIndex = p.propertyIndex();
- notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
+ setCoreIndex(p.propertyIndex());
+ setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
Q_ASSERT(p.revision() <= Q_INT16_MAX);
- revision = p.revision();
+ setRevision(p.revision());
- flags = fastFlagsForProperty(p);
+ setFlags(fastFlagsForProperty(p));
- int type = p.type();
+ int type = static_cast<int>(p.type());
if (type == QMetaType::QObjectStar) {
- propType = type;
- flags |= QQmlPropertyData::IsQObjectDerived;
+ setPropType(type);
+ _flags.type = Flags::QObjectDerivedType;
} else if (type == QMetaType::QVariant) {
- propType = type;
- flags |= QQmlPropertyData::IsQVariant;
+ setPropType(type);
+ _flags.type = Flags::QVariantType;
} else if (type == QVariant::UserType || type == -1) {
- propTypeName = p.typeName();
- flags |= QQmlPropertyData::NotFullyResolved;
+ _flags.notFullyResolved = true;
} else {
- propType = type;
+ setPropType(type);
}
}
void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
{
- propType = p.userType();
- coreIndex = p.propertyIndex();
- notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
- flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
+ setPropType(p.userType());
+ setCoreIndex(p.propertyIndex());
+ setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
+ setFlags(fastFlagsForProperty(p));
+ flagsForPropertyType(propType(), engine, _flags);
Q_ASSERT(p.revision() <= Q_INT16_MAX);
- revision = p.revision();
+ setRevision(p.revision());
}
void QQmlPropertyData::load(const QMetaMethod &m)
{
- coreIndex = m.methodIndex();
- arguments = 0;
- flags |= IsFunction;
+ setCoreIndex(m.methodIndex());
+ setArguments(nullptr);
+
+ setPropType(m.returnType());
+
+ _flags.type = Flags::FunctionType;
if (m.methodType() == QMetaMethod::Signal)
- flags |= IsSignal;
- propType = m.returnType();
+ _flags.isSignal = true;
+ else if (m.methodType() == QMetaMethod::Constructor) {
+ _flags.isConstructor = true;
+ setPropType(QMetaType::QObjectStar);
+ }
if (m.parameterCount()) {
- flags |= HasArguments;
+ _flags.hasArguments = true;
if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
- flags |= IsV4Function;
+ _flags.isV4Function = true;
}
}
if (m.attributes() & QMetaMethod::Cloned)
- flags |= IsCloned;
+ _flags.isCloned = true;
Q_ASSERT(m.revision() <= Q_INT16_MAX);
- revision = m.revision();
+ setRevision(m.revision());
}
void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
{
- coreIndex = m.methodIndex();
- arguments = 0;
- flags |= IsFunction;
+ setCoreIndex(m.methodIndex());
+ setPropType(QMetaType::Void);
+ setArguments(nullptr);
+ _flags.type = Flags::FunctionType;
if (m.methodType() == QMetaMethod::Signal)
- flags |= IsSignal;
- propType = QMetaType::Void;
+ _flags.isSignal = true;
+ else if (m.methodType() == QMetaMethod::Constructor) {
+ _flags.isConstructor = true;
+ setPropType(QMetaType::QObjectStar);
+ }
const char *returnType = m.typeName();
if (!returnType)
returnType = "\0";
if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
- propTypeName = returnType;
- flags |= NotFullyResolved;
+ _flags.notFullyResolved = true;
}
- if (m.parameterCount()) {
- flags |= HasArguments;
- if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
- flags |= IsV4Function;
+ const int paramCount = m.parameterCount();
+ if (paramCount) {
+ _flags.hasArguments = true;
+ if ((paramCount == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
+ _flags.isV4Function = true;
}
}
if (m.attributes() & QMetaMethod::Cloned)
- flags |= IsCloned;
+ _flags.isCloned = true;
Q_ASSERT(m.revision() <= Q_INT16_MAX);
- revision = m.revision();
+ setRevision(m.revision());
}
/*!
@@ -330,14 +336,14 @@ QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int meth
\a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
*/
-void QQmlPropertyCache::appendProperty(const QString &name,
- quint32 flags, int coreIndex, int propType, int notifyIndex)
+void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Flags flags,
+ int coreIndex, int propType, int notifyIndex)
{
QQmlPropertyData data;
- data.propType = propType;
- data.coreIndex = coreIndex;
- data.notifyIndex = notifyIndex;
- data.flags = flags;
+ data.setPropType(propType);
+ data.setCoreIndex(coreIndex);
+ data.setNotifyIndex(notifyIndex);
+ data.setFlags(flags);
QQmlPropertyData *old = findNamedProperty(name);
if (old)
@@ -349,24 +355,25 @@ void QQmlPropertyCache::appendProperty(const QString &name,
setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
}
-void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
- const int *types, const QList<QByteArray> &names)
+void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flags flags,
+ int coreIndex, const int *types,
+ const QList<QByteArray> &names)
{
QQmlPropertyData data;
- data.propType = QVariant::Invalid;
- data.coreIndex = coreIndex;
- data.flags = flags;
- data.arguments = 0;
+ data.setPropType(QVariant::Invalid);
+ data.setCoreIndex(coreIndex);
+ data.setFlags(flags);
+ data.setArguments(nullptr);
QQmlPropertyData handler = data;
- handler.flags |= QQmlPropertyData::IsSignalHandler;
+ handler._flags.isSignalHandler = true;
if (types) {
int argumentCount = *types;
QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
args->argumentsValid = true;
- data.arguments = args;
+ data.setArguments(args);
}
QQmlPropertyData *old = findNamedProperty(name);
@@ -380,28 +387,28 @@ void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int cor
signalHandlerIndexCache.append(handler);
QString handlerName = QLatin1String("on") + name;
- handlerName[2] = handlerName[2].toUpper();
+ handlerName[2] = handlerName.at(2).toUpper();
setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
}
-void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
- const QList<QByteArray> &names)
+void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags,
+ int coreIndex, const QList<QByteArray> &names)
{
int argumentCount = names.count();
QQmlPropertyData data;
- data.propType = QMetaType::QVariant;
- data.coreIndex = coreIndex;
+ data.setPropType(QMetaType::QVariant);
+ data.setCoreIndex(coreIndex);
QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
for (int ii = 0; ii < argumentCount; ++ii)
args->arguments[ii + 1] = QMetaType::QVariant;
args->argumentsValid = true;
- data.arguments = args;
+ data.setArguments(args);
- data.flags = flags;
+ data.setFlags(flags);
QQmlPropertyData *old = findNamedProperty(name);
if (old)
@@ -413,12 +420,6 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor
setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
}
-// Returns this property cache's metaObject. May be null if it hasn't been created yet.
-const QMetaObject *QQmlPropertyCache::metaObject() const
-{
- return _metaObject;
-}
-
// Returns this property cache's metaObject, creating it if necessary.
const QMetaObject *QQmlPropertyCache::createMetaObject()
{
@@ -434,22 +435,11 @@ const QMetaObject *QQmlPropertyCache::createMetaObject()
return _metaObject;
}
-// Returns the name of the default property for this cache
-QString QQmlPropertyCache::defaultPropertyName() const
-{
- return _defaultPropertyName;
-}
-
QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
return property(defaultPropertyName(), 0, 0);
}
-QQmlPropertyCache *QQmlPropertyCache::parent() const
-{
- return _parent;
-}
-
void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
{
if (_parent == newParent)
@@ -460,30 +450,21 @@ void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
_parent->addref();
}
-// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
-// QML
-const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
-{
- while (_parent && (_metaObject == 0 || _ownMetaObject))
- return _parent->firstCppMetaObject();
- return _metaObject;
-}
-
QQmlPropertyCache *
QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
- QQmlPropertyData::Flag propertyFlags,
- QQmlPropertyData::Flag methodFlags,
- QQmlPropertyData::Flag signalFlags)
+ QQmlPropertyData::Flags propertyFlags,
+ QQmlPropertyData::Flags methodFlags,
+ QQmlPropertyData::Flags signalFlags)
{
return copyAndAppend(metaObject, -1, propertyFlags, methodFlags, signalFlags);
}
QQmlPropertyCache *
QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
- int revision,
- QQmlPropertyData::Flag propertyFlags,
- QQmlPropertyData::Flag methodFlags,
- QQmlPropertyData::Flag signalFlags)
+ int revision,
+ QQmlPropertyData::Flags propertyFlags,
+ QQmlPropertyData::Flags methodFlags,
+ QQmlPropertyData::Flags signalFlags)
{
Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
@@ -500,10 +481,10 @@ QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
}
void QQmlPropertyCache::append(const QMetaObject *metaObject,
- int revision,
- QQmlPropertyData::Flag propertyFlags,
- QQmlPropertyData::Flag methodFlags,
- QQmlPropertyData::Flag signalFlags)
+ int revision,
+ QQmlPropertyData::Flags propertyFlags,
+ QQmlPropertyData::Flags methodFlags,
+ QQmlPropertyData::Flags signalFlags)
{
Q_UNUSED(revision);
@@ -518,34 +499,16 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
int signalCount = metaObjectSignalCount(metaObject);
int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
- QQmlAccessorProperties::Properties accessorProperties;
-
if (classInfoCount) {
int classInfoOffset = metaObject->classInfoOffset();
- bool hasFastProperty = false;
for (int ii = 0; ii < classInfoCount; ++ii) {
int idx = ii + classInfoOffset;
-
- if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
- hasFastProperty = true;
- } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
- _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
+ QMetaClassInfo mci = metaObject->classInfo(idx);
+ const char *name = mci.name();
+ if (0 == qstrcmp(name, "DefaultProperty")) {
+ _defaultPropertyName = QString::fromUtf8(mci.value());
}
}
-
- if (hasFastProperty) {
- accessorProperties = QQmlAccessorProperties::properties(metaObject);
- if (accessorProperties.count == 0)
- qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
- "installed property accessors", metaObject->className());
- } else {
-#ifndef QT_NO_DEBUG
- accessorProperties = QQmlAccessorProperties::properties(metaObject);
- if (accessorProperties.count != 0)
- qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
- "FastProperty class info", metaObject->className());
-#endif
- }
}
//Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
@@ -584,23 +547,21 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
QQmlPropertyData *sigdata = 0;
- data->lazyLoad(m);
-
- if (data->isSignal())
- data->flags |= signalFlags;
+ if (m.methodType() == QMetaMethod::Signal)
+ data->setFlags(signalFlags);
else
- data->flags |= methodFlags;
+ data->setFlags(methodFlags);
- if (!dynamicMetaObject)
- data->flags |= QQmlPropertyData::IsDirect;
+ data->lazyLoad(m);
+ data->_flags.isDirect = !dynamicMetaObject;
Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
- data->metaObjectOffset = allowedRevisionCache.count() - 1;
+ data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
if (data->isSignal()) {
sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
*sigdata = *data;
- sigdata->flags |= QQmlPropertyData::IsSignalHandler;
+ sigdata->_flags.isSignalHandler = true;
}
QQmlPropertyData *old = 0;
@@ -612,7 +573,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
setNamedProperty(methodName, ii, data, (old != 0));
if (data->isSignal()) {
- QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
+ QHashedString on(QLatin1String("on") % methodName.at(0).toUpper() % methodName.midRef(1));
setNamedProperty(on, ii, sigdata, (old != 0));
++signalHandlerIndex;
}
@@ -641,8 +602,8 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
if (old) {
// We only overload methods in the same class, exactly like C++
- if (old->isFunction() && old->coreIndex >= methodOffset)
- data->flags |= QQmlPropertyData::IsOverload;
+ if (old->isFunction() && old->coreIndex() >= methodOffset)
+ data->_flags.isOverload = true;
data->markAsOverrideOf(old);
}
@@ -669,14 +630,13 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
+ data->setFlags(propertyFlags);
data->lazyLoad(p);
- data->flags |= propertyFlags;
- if (!dynamicMetaObject)
- data->flags |= QQmlPropertyData::IsDirect;
+ data->_flags.isDirect = !dynamicMetaObject;
Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
- data->metaObjectOffset = allowedRevisionCache.count() - 1;
+ data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
QQmlPropertyData *old = 0;
@@ -692,29 +652,40 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
setNamedProperty(propName, ii, data, (old != 0));
}
- QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
-
- // Fast properties may not be overrides or revisioned
- Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
+ bool isGadget = true;
+ for (const QMetaObject *it = metaObject; it != nullptr; it = it->superClass()) {
+ if (it == &QObject::staticMetaObject)
+ isGadget = false;
+ }
- if (accessorProperty) {
- data->flags |= QQmlPropertyData::HasAccessors;
- data->accessors = accessorProperty->accessors;
- } else if (old) {
+ if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept
+ data->_flags.isDirect = false;
+ else
+ data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
+ if (old)
data->markAsOverrideOf(old);
- }
}
}
void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
{
Q_ASSERT(data->notFullyResolved());
-
- data->propType = QMetaType::type(data->propTypeName);
+ data->_flags.notFullyResolved = false;
+
+ const QMetaObject *mo = firstCppMetaObject();
+ if (data->isFunction()) {
+ auto metaMethod = mo->method(data->coreIndex());
+ const char *retTy = metaMethod.typeName();
+ if (!retTy)
+ retTy = "\0";
+ data->setPropType(QMetaType::type(retTy));
+ } else {
+ auto metaProperty = mo->property(data->coreIndex());
+ data->setPropType(QMetaType::type(metaProperty.typeName()));
+ }
if (!data->isFunction()) {
- if (data->propType == QMetaType::UnknownType) {
- const QMetaObject *mo = _metaObject;
+ if (data->propType() == QMetaType::UnknownType) {
QQmlPropertyCache *p = _parent;
while (p && (!mo || _ownMetaObject)) {
mo = p->_metaObject;
@@ -722,22 +693,20 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
}
int propOffset = mo->propertyOffset();
- if (mo && data->coreIndex < propOffset + mo->propertyCount()) {
- while (data->coreIndex < propOffset) {
+ if (mo && data->coreIndex() < propOffset + mo->propertyCount()) {
+ while (data->coreIndex() < propOffset) {
mo = mo->superClass();
propOffset = mo->propertyOffset();
}
int registerResult = -1;
void *argv[] = { &registerResult };
- mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex - propOffset, argv);
- data->propType = registerResult == -1 ? QMetaType::UnknownType : registerResult;
+ mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex() - propOffset, argv);
+ data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult);
}
}
- data->flags |= flagsForPropertyType(data->propType, engine->qmlEngine());
+ flagsForPropertyType(data->propType(), engine->qmlEngine(), data->_flags);
}
-
- data->flags &= ~QQmlPropertyData::NotFullyResolved;
}
void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject)
@@ -804,48 +773,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
}
}
-/*! \internal
- \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
- This is different from QMetaMethod::methodIndex().
-*/
-QQmlPropertyData *
-QQmlPropertyCache::signal(int index) const
-{
- if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
- return 0;
-
- if (index < signalHandlerIndexCacheStart)
- return _parent->signal(index);
-
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
- Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
- return ensureResolved(rv);
-}
-
-int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
-{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
- return index;
-
- if (index < methodIndexCacheStart)
- return _parent->methodIndexToSignalIndex(index);
-
- return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
-}
-
-QQmlPropertyData *
-QQmlPropertyCache::method(int index) const
-{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
- return 0;
-
- if (index < methodIndexCacheStart)
- return _parent->method(index);
-
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
- return ensureResolved(rv);
-}
-
QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
{
QQmlData *data = (object ? QQmlData::get(object) : 0);
@@ -862,11 +789,11 @@ inline bool contextHasNoExtensions(QQmlContextData *context)
return (!context->parent || !context->parent->imports);
}
-inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo)
+inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
{
- return (prop->isFunction() ? vmemo->methodCount()
- : prop->isSignalHandler() ? vmemo->signalCount()
- : vmemo->propertyCount());
+ return prop->isFunction() ? methodCount
+ : prop->isSignalHandler() ? signalCount
+ : propertyCount;
}
}
@@ -893,11 +820,15 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
}
if (vmemo) {
+ const int methodCount = vmemo->methodCount();
+ const int signalCount = vmemo->signalCount();
+ const int propertyCount = vmemo->propertyCount();
+
// Ensure that the property we resolve to is accessible from this meta-object
do {
const StringCache::mapped_type &property(it.value());
- if (property.first < maximumIndexForProperty(property.second, vmemo)) {
+ if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) {
// This property is available in the specified context
if (property.second->isFunction() || property.second->isSignalHandler()) {
// Prefer the earlier resolution
@@ -929,33 +860,25 @@ QString QQmlPropertyData::name(QObject *object) const
QString QQmlPropertyData::name(const QMetaObject *metaObject) const
{
- if (!metaObject || coreIndex == -1)
+ if (!metaObject || coreIndex() == -1)
return QString();
- if (flags & IsFunction) {
- QMetaMethod m = metaObject->method(coreIndex);
+ if (isFunction()) {
+ QMetaMethod m = metaObject->method(coreIndex());
return QString::fromUtf8(m.name().constData());
} else {
- QMetaProperty p = metaObject->property(coreIndex);
+ QMetaProperty p = metaObject->property(coreIndex());
return QString::fromUtf8(p.name());
}
}
void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
{
- overrideIndexIsProperty = !predecessor->isFunction();
- overrideIndex = predecessor->coreIndex;
-
- predecessor->flags |= QQmlPropertyData::IsOverridden;
-}
+ setOverrideIndexIsProperty(!predecessor->isFunction());
+ setOverrideIndex(predecessor->coreIndex());
-QStringList QQmlPropertyCache::propertyNames() const
-{
- QStringList keys;
- for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter)
- keys.append(iter.key());
- return keys;
+ predecessor->_flags.isOverridden = true;
}
struct StaticQtMetaObject : public QObject
@@ -1006,7 +929,6 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi
{
bool unnamedParameter = false;
const QSet<QString> &illegalNames = engine->v8Engine->illegalNames();
- QString error;
QString parameters;
for (int i = 0; i < parameterNameList.count(); ++i) {
@@ -1169,9 +1091,21 @@ QQmlPropertyCache::property(QJSEngine *engine, QObject *obj,
return qQmlPropertyCacheProperty<const QString &>(engine, obj, name, context, local);
}
+// these two functions are copied from qmetaobject.cpp
static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
+static inline const QByteArray stringData(const QMetaObject *mo, int index)
+{
+ Q_ASSERT(priv(mo->d.data)->revision >= 7);
+ const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };
+ Q_ASSERT(data.ptr->ref.isStatic());
+ Q_ASSERT(data.ptr->alloc == 0);
+ Q_ASSERT(data.ptr->capacityReserved == 0);
+ Q_ASSERT(data.ptr->size >= 0);
+ return data;
+}
+
bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
{
return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
@@ -1189,7 +1123,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
{
struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
const QPair<QString, QQmlPropertyData *> &rhs) {
- return lhs.second->coreIndex < rhs.second->coreIndex;
+ return lhs.second->coreIndex() < rhs.second->coreIndex();
} };
struct Insert { static void in(QQmlPropertyCache *This,
@@ -1200,7 +1134,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
return;
if (data->isFunction()) {
- if (data->coreIndex < This->methodIndexCacheStart)
+ if (data->coreIndex() < This->methodIndexCacheStart)
return;
QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
@@ -1210,7 +1144,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
data = This->overrideData(data);
if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
} else {
- if (data->coreIndex < This->propertyIndexCacheStart)
+ if (data->coreIndex() < This->propertyIndexCacheStart)
return;
QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
@@ -1241,11 +1175,11 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
QQmlPropertyData *data = properties.at(ii).second;
int notifierId = -1;
- if (data->notifyIndex != -1)
- notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
+ if (data->notifyIndex() != -1)
+ notifierId = data->notifyIndex() - signalHandlerIndexCacheStart;
QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
- QMetaType::typeName(data->propType),
+ QMetaType::typeName(data->propType()),
notifierId);
property.setReadable(true);
@@ -1257,14 +1191,16 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
QQmlPropertyData *data = methods.at(ii).second;
QByteArray returnType;
- if (data->propType != 0)
- returnType = QMetaType::typeName(data->propType);
+ if (data->propType() != 0)
+ returnType = QMetaType::typeName(data->propType());
- QByteArray signature = methods.at(ii).first.toUtf8() + '(';
+ QByteArray signature;
+ // '+=' reserves extra capacity. Follow-up appending will be probably free.
+ signature += methods.at(ii).first.toUtf8() + '(';
QQmlPropertyCacheMethodArguments *arguments = 0;
if (data->hasArguments()) {
- arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
+ arguments = (QQmlPropertyCacheMethodArguments *)data->arguments();
Q_ASSERT(arguments->argumentsValid);
for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
if (ii != 0) signature.append(',');
@@ -1291,13 +1227,221 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
if (!_defaultPropertyName.isEmpty()) {
QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0);
- if (dp && dp->coreIndex >= propertyIndexCacheStart) {
+ if (dp && dp->coreIndex() >= propertyIndexCacheStart) {
Q_ASSERT(!dp->isFunction());
builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
}
}
}
+namespace {
+template <typename StringVisitor, typename TypeInfoVisitor>
+int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount,
+ StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
+{
+ const int intsPerMethod = 5;
+
+ int fieldsForParameterData = 0;
+
+ bool hasRevisionedMethods = false;
+
+ for (int i = 0; i < methodCount; ++i) {
+ const int handle = methodOffset + i * intsPerMethod;
+
+ const uint flags = mo.d.data[handle + 4];
+ if (flags & MethodRevisioned)
+ hasRevisionedMethods = true;
+
+ visitString(mo.d.data[handle + 0]); // name
+ visitString(mo.d.data[handle + 3]); // tag
+
+ const int argc = mo.d.data[handle + 1];
+ const int paramIndex = mo.d.data[handle + 2];
+
+ fieldsForParameterData += argc * 2; // type and name
+ fieldsForParameterData += 1; // + return type
+
+ // return type + args
+ for (int i = 0; i < 1 + argc; ++i) {
+ // type name (maybe)
+ visitTypeInfo(mo.d.data[paramIndex + i]);
+
+ // parameter name
+ if (i > 0)
+ visitString(mo.d.data[paramIndex + argc + i]);
+ }
+ }
+
+ int fieldsForRevisions = 0;
+ if (hasRevisionedMethods)
+ fieldsForRevisions = methodCount;
+
+ return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData;
+}
+
+template <typename StringVisitor, typename TypeInfoVisitor>
+int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
+{
+ const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+ const int intsPerProperty = 3;
+
+ bool hasRevisionedProperties = false;
+ bool hasNotifySignals = false;
+
+ for (int i = 0; i < priv->propertyCount; ++i) {
+ const int handle = priv->propertyData + i * intsPerProperty;
+
+ const auto flags = mo.d.data[handle + 2];
+ if (flags & Revisioned) {
+ hasRevisionedProperties = true;
+ }
+ if (flags & Notify)
+ hasNotifySignals = true;
+
+ visitString(mo.d.data[handle]); // name
+ visitTypeInfo(mo.d.data[handle + 1]);
+ }
+
+ int fieldsForPropertyRevisions = 0;
+ if (hasRevisionedProperties)
+ fieldsForPropertyRevisions = priv->propertyCount;
+
+ int fieldsForNotifySignals = 0;
+ if (hasNotifySignals)
+ fieldsForNotifySignals = priv->propertyCount;
+
+ return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions
+ + fieldsForNotifySignals;
+}
+
+template <typename StringVisitor>
+int visitClassInfo(const QMetaObject &mo, StringVisitor visitString)
+{
+ const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+ const int intsPerClassInfo = 2;
+
+ for (int i = 0; i < priv->classInfoCount; ++i) {
+ const int handle = priv->classInfoData + i * intsPerClassInfo;
+
+ visitString(mo.d.data[handle]); // key
+ visitString(mo.d.data[handle + 1]); // value
+ }
+
+ return priv->classInfoCount * intsPerClassInfo;
+}
+
+template <typename StringVisitor>
+int visitEnumerations(const QMetaObject &mo, StringVisitor visitString)
+{
+ const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+ const int intsPerEnumerator = 4;
+
+ int fieldCount = priv->enumeratorCount * intsPerEnumerator;
+
+ for (int i = 0; i < priv->enumeratorCount; ++i) {
+ const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator;
+
+ const uint keyCount = enumeratorData[2];
+ fieldCount += keyCount * 2;
+
+ visitString(enumeratorData[0]); // name
+
+ const uint keyOffset = enumeratorData[3];
+
+ for (uint j = 0; j < keyCount; ++j) {
+ visitString(mo.d.data[keyOffset + 2 * j]);
+ }
+ }
+
+ return fieldCount;
+}
+
+template <typename StringVisitor>
+int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor)
+{
+ const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+
+ const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) {
+ if (typeInfo & IsUnresolvedType)
+ stringVisitor(typeInfo & TypeNameIndexMask);
+ };
+
+ int fieldCount = MetaObjectPrivateFieldCount;
+
+ fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor,
+ typeInfoVisitor);
+ fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor,
+ typeInfoVisitor);
+
+ fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor);
+ fieldCount += visitClassInfo(mo, stringVisitor);
+ fieldCount += visitEnumerations(mo, stringVisitor);
+
+ return fieldCount;
+}
+
+} // anonymous namespace
+
+bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount,
+ int *stringCount)
+{
+ const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
+ if (priv->revision != 7) {
+ return false;
+ }
+
+ uint highestStringIndex = 0;
+ const auto stringIndexVisitor = [&highestStringIndex](uint index) {
+ highestStringIndex = qMax(highestStringIndex, index);
+ };
+
+ *fieldCount = countMetaObjectFields(mo, stringIndexVisitor);
+ *stringCount = highestStringIndex + 1;
+
+ return true;
+}
+
+bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &mo)
+{
+ int fieldCount = 0;
+ int stringCount = 0;
+ if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) {
+ return false;
+ }
+
+ hash.addData(reinterpret_cast<const char *>(mo.d.data), fieldCount * sizeof(uint));
+ for (int i = 0; i < stringCount; ++i) {
+ hash.addData(stringData(&mo, i));
+ }
+
+ return true;
+}
+
+QByteArray QQmlPropertyCache::checksum(bool *ok)
+{
+ if (!_checksum.isEmpty()) {
+ *ok = true;
+ return _checksum;
+ }
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ if (_parent) {
+ hash.addData(_parent->checksum(ok));
+ if (!*ok)
+ return QByteArray();
+ }
+
+ if (!addToHash(hash, *createMetaObject())) {
+ *ok = false;
+ return QByteArray();
+ }
+
+ _checksum = hash.result();
+ *ok = !_checksum.isEmpty();
+ return _checksum;
+}
+
/*! \internal
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
@@ -1306,7 +1450,7 @@ QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
{
QQmlPropertyData *signalData = signal(index);
if (signalData && signalData->hasArguments()) {
- QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments;
+ QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments();
if (args && args->names)
return *args->names;
const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index);
@@ -1408,9 +1552,9 @@ QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const
{
- Q_ASSERT(!_m.isNull() && data.coreIndex >= 0);
+ Q_ASSERT(!_m.isNull() && data.coreIndex() >= 0);
- int type = data.propType;
+ int type = data.propType();
const char *propTypeName = 0;
@@ -1420,16 +1564,16 @@ int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *u
if (_m.isT1()) {
QQmlPropertyCache *c = _m.asT1();
- Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count());
+ Q_ASSERT(data.coreIndex() < c->methodIndexCacheStart + c->methodIndexCache.count());
- while (data.coreIndex < c->methodIndexCacheStart)
+ while (data.coreIndex() < c->methodIndexCacheStart)
c = c->_parent;
const QMetaObject *metaObject = c->createMetaObject();
Q_ASSERT(metaObject);
- m = metaObject->method(data.coreIndex);
+ m = metaObject->method(data.coreIndex());
} else {
- m = _m.asT2()->method(data.coreIndex);
+ m = _m.asT2()->method(data.coreIndex());
}
type = m.returnType();
@@ -1453,7 +1597,8 @@ int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *u
return type;
}
-int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &dummy, QByteArray *unknownTypeError) const
+int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const
{
Q_ASSERT(!_m.isNull() && index >= 0);
@@ -1468,19 +1613,19 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
- if (rv->arguments && static_cast<A *>(rv->arguments)->argumentsValid)
- return static_cast<A *>(rv->arguments)->arguments;
+ if (rv->arguments() && static_cast<A *>(rv->arguments())->argumentsValid)
+ return static_cast<A *>(rv->arguments())->arguments;
const QMetaObject *metaObject = c->createMetaObject();
Q_ASSERT(metaObject);
QMetaMethod m = metaObject->method(index);
int argc = m.parameterCount();
- if (!rv->arguments) {
+ if (!rv->arguments()) {
A *args = c->createArgumentsObject(argc, m.parameterNames());
- rv->arguments = args;
+ rv->setArguments(args);
}
- A *args = static_cast<A *>(rv->arguments);
+ A *args = static_cast<A *>(rv->arguments());
QList<QByteArray> argTypeNames; // Only loaded if needed
@@ -1504,43 +1649,57 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du
args->arguments[ii + 1] = type;
}
args->argumentsValid = true;
- return static_cast<A *>(rv->arguments)->arguments;
+ return static_cast<A *>(rv->arguments())->arguments;
} else {
QMetaMethod m = _m.asT2()->method(index);
- int argc = m.parameterCount();
- dummy.resize(argc + 1);
- dummy[0] = argc;
- QList<QByteArray> argTypeNames; // Only loaded if needed
+ return methodParameterTypes(m, argStorage, unknownTypeError);
- for (int ii = 0; ii < argc; ++ii) {
- int type = m.parameterType(ii);
- QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
- if (flags & QMetaType::IsEnumeration)
- type = QVariant::Int;
- else if (type == QMetaType::UnknownType ||
- (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
- type != qMetaTypeId<QJSValue>())) {
- //the UserType clause is to catch registered QFlags)
- if (argTypeNames.isEmpty())
- argTypeNames = m.parameterTypes();
- type = EnumType(_m.asT2(), argTypeNames.at(ii), type);
- }
- if (type == QMetaType::UnknownType) {
- if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
- return 0;
- }
- dummy[ii + 1] = type;
- }
+ }
+}
- return dummy.data();
+int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const
+{
+ Q_ASSERT(argStorage);
+
+ int argc = m.parameterCount();
+ argStorage->resize(argc + 1);
+ argStorage->operator[](0) = argc;
+ QList<QByteArray> argTypeNames; // Only loaded if needed
+
+ for (int ii = 0; ii < argc; ++ii) {
+ int type = m.parameterType(ii);
+ QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
+ if (flags & QMetaType::IsEnumeration)
+ type = QVariant::Int;
+ else if (type == QMetaType::UnknownType ||
+ (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
+ type != qMetaTypeId<QJSValue>())) {
+ //the UserType clause is to catch registered QFlags)
+ if (argTypeNames.isEmpty())
+ argTypeNames = m.parameterTypes();
+ type = EnumType(_m.asT2(), argTypeNames.at(ii), type);
+ }
+ if (type == QMetaType::UnknownType) {
+ if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
+ return 0;
+ }
+ argStorage->operator[](ii + 1) = type;
}
+
+ return argStorage->data();
}
void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const
{
- if (ptr.isT1())
+ if (ptr.isNull()) {
+ const QMetaObject *metaObject = _m.asT2();
+ metaObject->d.static_metacall(0, type, index, argv);
+ }
+ else if (ptr.isT1()) {
QMetaObject::metacall(ptr.asT1(), type, index, argv);
+ }
else {
const QMetaObject *metaObject = _m.asT1()->metaObject();
QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index);
@@ -1548,4 +1707,11 @@ void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv
}
}
+int *QQmlStaticMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy,
+ QByteArray *unknownTypeError) const
+{
+ QMetaMethod m = _m.asT2()->constructor(index);
+ return methodParameterTypes(m, dummy, unknownTypeError);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index b2171dd86b..c27ea796e0 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -55,6 +55,7 @@
#include <private/qflagpointer_p.h>
#include "qqmlcleanup_p.h"
#include "qqmlnotifier_p.h"
+#include <private/qqmlpropertyindex_p.h>
#include <private/qhashedstring_p.h>
#include <QtCore/qvarlengtharray.h>
@@ -62,17 +63,20 @@
#include <private/qv4value_p.h>
+#include <limits>
+
QT_BEGIN_NAMESPACE
+class QCryptographicHash;
class QMetaProperty;
class QQmlEngine;
class QJSEngine;
class QQmlPropertyData;
-class QQmlAccessors;
class QMetaObjectBuilder;
class QQmlPropertyCacheMethodArguments;
class QQmlVMEMetaObject;
-class QQmlPropertyCacheCreator;
+template <typename T> class QQmlPropertyCacheCreator;
+template <typename T> class QQmlPropertyCacheAliasCreator;
// We have this somewhat awful split between RawData and Data so that RawData can be
// used in unions. In normal code, you should always use Data which initializes RawData
@@ -80,151 +84,205 @@ class QQmlPropertyCacheCreator;
class QQmlPropertyRawData
{
public:
- enum Flag {
- NoFlags = 0x00000000,
- ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask
+ typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
+
+ struct Flags {
+ enum Types {
+ OtherType = 0,
+ FunctionType = 1, // Is an invokable
+ QObjectDerivedType = 2, // Property type is a QObject* derived type
+ EnumType = 3, // Property type is an enum
+ QListType = 4, // Property type is a QML list
+ QmlBindingType = 5, // Property type is a QQmlBinding*
+ QJSValueType = 6, // Property type is a QScriptValue
+ V4HandleType = 7, // Property type is a QQmlV4Handle
+ VarPropertyType = 8, // Property type is a "var" property of VMEMO
+ QVariantType = 9 // Property is a QVariant
+ };
+
+ // The _otherBits (which "pad" the Flags struct to align it nicely) are used
+ // to store the relative property index. It will only get used when said index fits. See
+ // trySetStaticMetaCallFunction for details.
+ // (Note: this padding is done here, because certain compilers have surprising behavior
+ // when an enum is declared in-between two bit fields.)
+ enum { BitsLeftInFlags = 10 };
+ unsigned _otherBits : BitsLeftInFlags; // align to 32 bits
// Can apply to all properties, except IsFunction
- IsConstant = 0x00000001, // Has CONST flag
- IsWritable = 0x00000002, // Has WRITE function
- IsResettable = 0x00000004, // Has RESET function
- IsAlias = 0x00000008, // Is a QML alias to another property
- IsFinal = 0x00000010, // Has FINAL flag
- IsOverridden = 0x00000020, // Is overridden by a extension property
- IsDirect = 0x00000040, // Exists on a C++ QMetaObject
- HasAccessors = 0x00000080, // Has property accessors
-
- // These are mutualy exclusive
- IsFunction = 0x00000100, // Is an invokable
- IsQObjectDerived = 0x00000200, // Property type is a QObject* derived type
- IsEnumType = 0x00000400, // Property type is an enum
- IsQList = 0x00000800, // Property type is a QML list
- IsQmlBinding = 0x00001000, // Property type is a QQmlBinding*
- IsQJSValue = 0x00002000, // Property type is a QScriptValue
- IsV4Handle = 0x00004000, // Property type is a QQmlV4Handle
- IsVarProperty = 0x00008000, // Property type is a "var" property of VMEMO
- IsValueTypeVirtual = 0x00010000, // Property is a value type "virtual" property
- IsQVariant = 0x00020000, // Property is a QVariant
+ unsigned isConstant : 1; // Has CONST flag
+ unsigned isWritable : 1; // Has WRITE function
+ unsigned isResettable : 1; // Has RESET function
+ unsigned isAlias : 1; // Is a QML alias to another property
+ unsigned isFinal : 1; // Has FINAL flag
+ unsigned isOverridden : 1; // Is overridden by a extension property
+ unsigned isDirect : 1; // Exists on a C++ QMetaObject
+
+ unsigned type : 4; // stores an entry of Types
// Apply only to IsFunctions
- IsVMEFunction = 0x00040000, // Function was added by QML
- HasArguments = 0x00080000, // Function takes arguments
- IsSignal = 0x00100000, // Function is a signal
- IsVMESignal = 0x00200000, // Signal was added by QML
- IsV4Function = 0x00400000, // Function takes QQmlV4Function* args
- IsSignalHandler = 0x00800000, // Function is a signal handler
- IsOverload = 0x01000000, // Function is an overload of another function
- IsCloned = 0x02000000, // The function was marked as cloned
+ unsigned isVMEFunction : 1; // Function was added by QML
+ unsigned hasArguments : 1; // Function takes arguments
+ unsigned isSignal : 1; // Function is a signal
+ unsigned isVMESignal : 1; // Signal was added by QML
+ unsigned isV4Function : 1; // Function takes QQmlV4Function* args
+ unsigned isSignalHandler : 1; // Function is a signal handler
+ unsigned isOverload : 1; // Function is an overload of another function
+ unsigned isCloned : 1; // The function was marked as cloned
+ unsigned isConstructor : 1; // The function was marked is a constructor
// Internal QQmlPropertyCache flags
- NotFullyResolved = 0x04000000, // True if the type data is to be lazily resolved
+ unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
+ unsigned overrideIndexIsProperty: 1;
- // Flags that are set based on the propType field
- PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue |
- IsV4Handle | IsQVariant,
+ inline Flags();
+ inline bool operator==(const Flags &other) const;
+ inline void copyPropertyTypeFlags(Flags from);
};
- Q_DECLARE_FLAGS(Flags, Flag)
-
- Flags getFlags() const { return Flag(flags); }
- void setFlags(Flags f) { flags = f; }
-
- bool isValid() const { return coreIndex != -1; }
-
- bool isConstant() const { return flags & IsConstant; }
- bool isWritable() const { return flags & IsWritable; }
- bool isResettable() const { return flags & IsResettable; }
- bool isAlias() const { return flags & IsAlias; }
- bool isFinal() const { return flags & IsFinal; }
- bool isOverridden() const { return flags & IsOverridden; }
- bool isDirect() const { return flags & IsDirect; }
- bool hasAccessors() const { return flags & HasAccessors; }
- bool isFunction() const { return flags & IsFunction; }
- bool isQObject() const { return flags & IsQObjectDerived; }
- bool isEnum() const { return flags & IsEnumType; }
- bool isQList() const { return flags & IsQList; }
- bool isQmlBinding() const { return flags & IsQmlBinding; }
- bool isQJSValue() const { return flags & IsQJSValue; }
- bool isV4Handle() const { return flags & IsV4Handle; }
- bool isVarProperty() const { return flags & IsVarProperty; }
- bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; }
- bool isQVariant() const { return flags & IsQVariant; }
- bool isVMEFunction() const { return flags & IsVMEFunction; }
- bool hasArguments() const { return flags & HasArguments; }
- bool isSignal() const { return flags & IsSignal; }
- bool isVMESignal() const { return flags & IsVMESignal; }
- bool isV4Function() const { return flags & IsV4Function; }
- bool isSignalHandler() const { return flags & IsSignalHandler; }
- bool isOverload() const { return flags & IsOverload; }
- bool isCloned() const { return flags & IsCloned; }
-
- bool hasOverride() const { return !(flags & IsValueTypeVirtual) &&
- !(flags & HasAccessors) &&
- overrideIndex >= 0; }
- bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; }
-
- bool isFullyResolved() const { return !(flags & NotFullyResolved); }
-
- // Returns -1 if not a value type virtual property
- inline int getValueTypeCoreIndex() const;
-
- // Returns the "encoded" index for use with bindings. Encoding is:
- // coreIndex | ((valueTypeCoreIndex + 1) << 16)
- inline int encodedIndex() const;
- static int encodeValueTypePropertyIndex(int coreIndex, int valueTypeCoreIndex)
- { return coreIndex | ((valueTypeCoreIndex + 1) << 16); }
- static int decodeValueTypePropertyIndex(int index, int *coreIndex = 0) {
- if (coreIndex) *coreIndex = index & 0xffff;
- return (index >> 16) - 1;
+
+ Flags flags() const { return _flags; }
+ void setFlags(Flags f)
+ {
+ unsigned otherBits = _flags._otherBits;
+ _flags = f;
+ _flags._otherBits = otherBits;
}
- union {
- int propType; // When !NotFullyResolved
- const char *propTypeName; // When NotFullyResolved
- };
- union {
- // The notify index is in the range returned by QObjectPrivate::signalIndex().
- // This is different from QMetaMethod::methodIndex().
- int notifyIndex; // When !IsFunction
- void *arguments; // When IsFunction && HasArguments
- };
+ bool isValid() const { return coreIndex() != -1; }
+
+ bool isConstant() const { return _flags.isConstant; }
+ bool isWritable() const { return _flags.isWritable; }
+ void setWritable(bool onoff) { _flags.isWritable = onoff; }
+ bool isResettable() const { return _flags.isResettable; }
+ bool isAlias() const { return _flags.isAlias; }
+ bool isFinal() const { return _flags.isFinal; }
+ bool isOverridden() const { return _flags.isOverridden; }
+ bool isDirect() const { return _flags.isDirect; }
+ bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
+ bool isFunction() const { return _flags.type == Flags::FunctionType; }
+ bool isQObject() const { return _flags.type == Flags::QObjectDerivedType; }
+ bool isEnum() const { return _flags.type == Flags::EnumType; }
+ bool isQList() const { return _flags.type == Flags::QListType; }
+ bool isQmlBinding() const { return _flags.type == Flags::QmlBindingType; }
+ bool isQJSValue() const { return _flags.type == Flags::QJSValueType; }
+ bool isV4Handle() const { return _flags.type == Flags::V4HandleType; }
+ bool isVarProperty() const { return _flags.type == Flags::VarPropertyType; }
+ bool isQVariant() const { return _flags.type == Flags::QVariantType; }
+ bool isVMEFunction() const { return _flags.isVMEFunction; }
+ bool hasArguments() const { return _flags.hasArguments; }
+ bool isSignal() const { return _flags.isSignal; }
+ bool isVMESignal() const { return _flags.isVMESignal; }
+ bool isV4Function() const { return _flags.isV4Function; }
+ bool isSignalHandler() const { return _flags.isSignalHandler; }
+ bool isOverload() const { return _flags.isOverload; }
+ void setOverload(bool onoff) { _flags.isOverload = onoff; }
+ bool isCloned() const { return _flags.isCloned; }
+ bool isConstructor() const { return _flags.isConstructor; }
+
+ bool hasOverride() const { return overrideIndex() >= 0; }
+ bool hasRevision() const { return revision() != 0; }
+
+ bool isFullyResolved() const { return !_flags.notFullyResolved; }
+
+ int propType() const { Q_ASSERT(isFullyResolved()); return _propType; }
+ void setPropType(int pt)
+ {
+ Q_ASSERT(pt >= 0);
+ Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
+ _propType = quint16(pt);
+ }
- union {
- struct { // When !HasAccessors
- qint16 revision;
- qint16 metaObjectOffset;
-
- union {
- struct { // When IsValueTypeVirtual
- quint16 valueTypeFlags; // flags of the access property on the value type proxy
- // object
- quint16 valueTypePropType; // The QVariant::Type of access property on the value
- // type proxy object
- quint16 valueTypeCoreIndex; // The prop index of the access property on the value
- // type proxy object
- };
-
- struct { // When !IsValueTypeVirtual
- uint overrideIndexIsProperty : 1;
- signed int overrideIndex : 31;
- };
- };
- };
- struct { // When HasAccessors
- QQmlAccessors *accessors;
- };
- };
- int coreIndex;
+ int notifyIndex() const { return _notifyIndex; }
+ void setNotifyIndex(int idx)
+ {
+ Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
+ _notifyIndex = qint16(idx);
+ }
+
+ bool overrideIndexIsProperty() const { return _flags.overrideIndexIsProperty; }
+ void setOverrideIndexIsProperty(bool onoff) { _flags.overrideIndexIsProperty = onoff; }
+
+ int overrideIndex() const { return _overrideIndex; }
+ void setOverrideIndex(int idx)
+ {
+ Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
+ _overrideIndex = qint16(idx);
+ }
+
+ int coreIndex() const { return _coreIndex; }
+ void setCoreIndex(int idx)
+ {
+ Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
+ _coreIndex = qint16(idx);
+ }
+
+ int revision() const { return _revision; }
+ void setRevision(int rev)
+ {
+ Q_ASSERT(rev >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(rev <= std::numeric_limits<qint16>::max());
+ _revision = qint16(rev);
+ }
+
+ QQmlPropertyCacheMethodArguments *arguments() const { return _arguments; }
+ void setArguments(QQmlPropertyCacheMethodArguments *args) { _arguments = args; }
+
+ int metaObjectOffset() const { return _metaObjectOffset; }
+ void setMetaObjectOffset(int off)
+ {
+ Q_ASSERT(off >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(off <= std::numeric_limits<qint16>::max());
+ _metaObjectOffset = qint16(off);
+ }
+
+ StaticMetaCallFunction staticMetaCallFunction() const { return _staticMetaCallFunction; }
+ void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
+ {
+ if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
+ _flags._otherBits = relativePropertyIndex;
+ _staticMetaCallFunction = f;
+ }
+ }
+ quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return _flags._otherBits; }
private:
+ Flags _flags;
+ qint16 _coreIndex;
+ quint16 _propType;
+
+ // The notify index is in the range returned by QObjectPrivate::signalIndex().
+ // This is different from QMetaMethod::methodIndex().
+ qint16 _notifyIndex;
+ qint16 _overrideIndex;
+
+ qint16 _revision;
+ qint16 _metaObjectOffset;
+
+ QQmlPropertyCacheMethodArguments *_arguments;
+ StaticMetaCallFunction _staticMetaCallFunction;
+
friend class QQmlPropertyData;
friend class QQmlPropertyCache;
- quint32 flags;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags)
+
+#if QT_POINTER_SIZE == 4
+Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 24);
+#else // QT_POINTER_SIZE == 8
+Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 32);
+#endif
class QQmlPropertyData : public QQmlPropertyRawData
{
public:
+ enum WriteFlag {
+ BypassInterceptor = 0x01,
+ DontRemoveBinding = 0x02,
+ RemoveBindingOnAliasWrite = 0x04
+ };
+ Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
+
inline QQmlPropertyData();
inline QQmlPropertyData(const QQmlPropertyRawData &);
@@ -238,11 +296,57 @@ public:
void markAsOverrideOf(QQmlPropertyData *predecessor);
+ inline void readProperty(QObject *target, void *property) const
+ {
+ void *args[] = { property, 0 };
+ readPropertyWithArgs(target, args);
+ }
+
+ inline void readPropertyWithArgs(QObject *target, void *args[]) const
+ {
+ if (hasStaticMetaCallFunction())
+ staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
+ else if (isDirect())
+ target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
+ else
+ QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
+ }
+
+ bool writeProperty(QObject *target, void *value, WriteFlags flags) const
+ {
+ int status = -1;
+ void *argv[] = { value, 0, &status, &flags };
+ if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
+ staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
+ else if (flags.testFlag(BypassInterceptor) && isDirect())
+ target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
+ else
+ QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
+ return true;
+ }
+
+ static Flags defaultSignalFlags()
+ {
+ Flags f;
+ f.isSignal = true;
+ f.type = Flags::FunctionType;
+ f.isVMESignal = true;
+ return f;
+ }
+
+ static Flags defaultSlotFlags()
+ {
+ Flags f;
+ f.type = Flags::FunctionType;
+ f.isVMEFunction = true;
+ return f;
+ }
+
private:
friend class QQmlPropertyCache;
void lazyLoad(const QMetaProperty &);
void lazyLoad(const QMetaMethod &);
- bool notFullyResolved() const { return flags & NotFullyResolved; }
+ bool notFullyResolved() const { return _flags.notFullyResolved; }
};
class QQmlPropertyCacheMethodArguments;
@@ -261,21 +365,21 @@ public:
QQmlPropertyCache *copy();
QQmlPropertyCache *copyAndAppend(const QMetaObject *,
- QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
- QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
- QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
+ QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
QQmlPropertyCache *copyAndAppend(const QMetaObject *, int revision,
- QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
- QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
- QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
+ QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
QQmlPropertyCache *copyAndReserve(int propertyCount,
int methodCount, int signalCount);
- void appendProperty(const QString &,
- quint32 flags, int coreIndex, int propType, int notifyIndex);
- void appendSignal(const QString &, quint32, int coreIndex, const int *types = 0,
- const QList<QByteArray> &names = QList<QByteArray>());
- void appendMethod(const QString &, quint32 flags, int coreIndex,
+ void appendProperty(const QString &, QQmlPropertyRawData::Flags flags, int coreIndex,
+ int propType, int notifyIndex);
+ void appendSignal(const QString &, QQmlPropertyRawData::Flags, int coreIndex,
+ const int *types = 0, const QList<QByteArray> &names = QList<QByteArray>());
+ void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
const QList<QByteArray> &names = QList<QByteArray>());
const QMetaObject *metaObject() const;
@@ -292,7 +396,6 @@ public:
QQmlPropertyData *method(int) const;
QQmlPropertyData *signal(int index) const;
int methodIndexToSignalIndex(int) const;
- QStringList propertyNames() const;
QString defaultPropertyName() const;
QQmlPropertyData *defaultProperty() const;
@@ -328,23 +431,29 @@ public:
void toMetaObjectBuilder(QMetaObjectBuilder &);
+ static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount);
+ static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo);
+
+ QByteArray checksum(bool *ok);
+
protected:
- virtual void destroy();
- virtual void clear();
+ void destroy() override;
+ void clear() override;
private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
- friend class QQmlPropertyCacheCreator;
+ template <typename T> friend class QQmlPropertyCacheCreator;
+ template <typename T> friend class QQmlPropertyCacheAliasCreator;
friend class QQmlComponentAndAliasResolver;
friend class QQmlMetaObject;
inline QQmlPropertyCache *copy(int reserve);
void append(const QMetaObject *, int revision,
- QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
- QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
- QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
+ QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyRawData::Flags(),
+ QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
QQmlPropertyCacheMethodArguments *createArgumentsObject(int count, const QList<QByteArray> &names);
@@ -396,6 +505,7 @@ private:
QByteArray _dynamicStringData;
QString _defaultPropertyName;
QQmlPropertyCacheMethodArguments *argumentsCache;
+ QByteArray _checksum;
};
// QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
@@ -408,6 +518,8 @@ class QQmlEnginePrivate;
class Q_QML_EXPORT QQmlMetaObject
{
public:
+ typedef QVarLengthArray<int, 9> ArgTypeStorage;
+
inline QQmlMetaObject();
inline QQmlMetaObject(QObject *);
inline QQmlMetaObject(const QMetaObject *);
@@ -427,7 +539,8 @@ public:
QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
- int *methodParameterTypes(int index, QVarLengthArray<int, 9> &dummy, QByteArray *unknownTypeError) const;
+ int *methodParameterTypes(int index, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const;
static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
@@ -437,6 +550,9 @@ public:
protected:
QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
+ int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const;
+
};
class QQmlObjectOrGadget: public QQmlMetaObject
@@ -455,45 +571,105 @@ public:
private:
QBiPointer<QObject, void> ptr;
+
+protected:
+ QQmlObjectOrGadget(const QMetaObject* metaObject)
+ : QQmlMetaObject(metaObject)
+ {}
+
};
-QQmlPropertyData::QQmlPropertyData()
+class QQmlStaticMetaObject : public QQmlObjectOrGadget {
+public:
+ QQmlStaticMetaObject(const QMetaObject* metaObject)
+ : QQmlObjectOrGadget(metaObject)
+ {}
+ int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
+};
+
+QQmlPropertyRawData::Flags::Flags()
+ : _otherBits(0)
+ , isConstant(false)
+ , isWritable(false)
+ , isResettable(false)
+ , isAlias(false)
+ , isFinal(false)
+ , isOverridden(false)
+ , isDirect(false)
+ , type(OtherType)
+ , isVMEFunction(false)
+ , hasArguments(false)
+ , isSignal(false)
+ , isVMESignal(false)
+ , isV4Function(false)
+ , isSignalHandler(false)
+ , isOverload(false)
+ , isCloned(false)
+ , isConstructor(false)
+ , notFullyResolved(false)
+ , overrideIndexIsProperty(false)
+{}
+
+bool QQmlPropertyRawData::Flags::operator==(const QQmlPropertyRawData::Flags &other) const
{
- propType = 0;
- coreIndex = -1;
- notifyIndex = -1;
- overrideIndexIsProperty = false;
- overrideIndex = -1;
- revision = 0;
- metaObjectOffset = -1;
- flags = 0;
+ return isConstant == other.isConstant &&
+ isWritable == other.isWritable &&
+ isResettable == other.isResettable &&
+ isAlias == other.isAlias &&
+ isFinal == other.isFinal &&
+ isOverridden == other.isOverridden &&
+ type == other.type &&
+ isVMEFunction == other.isVMEFunction &&
+ hasArguments == other.hasArguments &&
+ isSignal == other.isSignal &&
+ isVMESignal == other.isVMESignal &&
+ isV4Function == other.isV4Function &&
+ isSignalHandler == other.isSignalHandler &&
+ isOverload == other.isOverload &&
+ isCloned == other.isCloned &&
+ isConstructor == other.isConstructor &&
+ notFullyResolved == other.notFullyResolved &&
+ overrideIndexIsProperty == other.overrideIndexIsProperty;
}
-QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
+void QQmlPropertyRawData::Flags::copyPropertyTypeFlags(QQmlPropertyRawData::Flags from)
{
- *(static_cast<QQmlPropertyRawData *>(this)) = d;
+ switch (from.type) {
+ case QObjectDerivedType:
+ case EnumType:
+ case QListType:
+ case QmlBindingType:
+ case QJSValueType:
+ case V4HandleType:
+ case QVariantType:
+ type = from.type;
+ }
}
-bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
+QQmlPropertyData::QQmlPropertyData()
{
- return flags == other.flags &&
- propType == other.propType &&
- coreIndex == other.coreIndex &&
- notifyIndex == other.notifyIndex &&
- revision == other.revision &&
- (!isValueTypeVirtual() ||
- (valueTypeCoreIndex == other.valueTypeCoreIndex &&
- valueTypePropType == other.valueTypePropType));
+ setCoreIndex(-1);
+ setPropType(0);
+ setNotifyIndex(-1);
+ setOverrideIndex(-1);
+ setRevision(0);
+ setMetaObjectOffset(-1);
+ setArguments(nullptr);
+ trySetStaticMetaCallFunction(nullptr, 0);
}
-int QQmlPropertyRawData::getValueTypeCoreIndex() const
+QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
{
- return isValueTypeVirtual()?valueTypeCoreIndex:-1;
+ *(static_cast<QQmlPropertyRawData *>(this)) = d;
}
-int QQmlPropertyRawData::encodedIndex() const
+bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
{
- return isValueTypeVirtual()?QQmlPropertyData::encodeValueTypePropertyIndex(coreIndex, valueTypeCoreIndex):coreIndex;
+ return flags() == other.flags() &&
+ propType() == other.propType() &&
+ coreIndex() == other.coreIndex() &&
+ notifyIndex() == other.notifyIndex() &&
+ revision() == other.revision();
}
inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
@@ -504,6 +680,21 @@ inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p)
return p;
}
+// Returns this property cache's metaObject. May be null if it hasn't been created yet.
+inline const QMetaObject *QQmlPropertyCache::metaObject() const
+{
+ return _metaObject;
+}
+
+// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
+// QML
+inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
+{
+ while (_parent && (_metaObject == 0 || _ownMetaObject))
+ return _parent->firstCppMetaObject();
+ return _metaObject;
+}
+
inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
{
if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
@@ -516,22 +707,73 @@ inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
return ensureResolved(rv);
}
+inline QQmlPropertyData *QQmlPropertyCache::method(int index) const
+{
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ return 0;
+
+ if (index < methodIndexCacheStart)
+ return _parent->method(index);
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
+ return ensureResolved(rv);
+}
+
+/*! \internal
+ \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+ This is different from QMetaMethod::methodIndex().
+*/
+inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const
+{
+ if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
+ return 0;
+
+ if (index < signalHandlerIndexCacheStart)
+ return _parent->signal(index);
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
+ Q_ASSERT(rv->isSignal() || rv->coreIndex() == -1);
+ return ensureResolved(rv);
+}
+
+inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
+{
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ return index;
+
+ if (index < methodIndexCacheStart)
+ return _parent->methodIndexToSignalIndex(index);
+
+ return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
+}
+
+// Returns the name of the default property for this cache
+inline QString QQmlPropertyCache::defaultPropertyName() const
+{
+ return _defaultPropertyName;
+}
+
+inline QQmlPropertyCache *QQmlPropertyCache::parent() const
+{
+ return _parent;
+}
+
QQmlPropertyData *
QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
{
if (!data->hasOverride())
return 0;
- if (data->overrideIndexIsProperty)
- return property(data->overrideIndex);
+ if (data->overrideIndexIsProperty())
+ return property(data->overrideIndex());
else
- return method(data->overrideIndex);
+ return method(data->overrideIndex());
}
bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
{
- return (data->hasAccessors() || (data->metaObjectOffset == -1 && data->revision == 0)) ||
- (allowedRevisionCache[data->metaObjectOffset] >= data->revision);
+ return (data->metaObjectOffset() == -1 && data->revision() == 0) ||
+ (allowedRevisionCache[data->metaObjectOffset()] >= data->revision());
}
int QQmlPropertyCache::propertyCount() const
@@ -637,6 +879,51 @@ const QMetaObject *QQmlMetaObject::metaObject() const
else return _m.asT2();
}
+class QQmlPropertyCacheVector
+{
+public:
+ QQmlPropertyCacheVector() {}
+ QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other)
+ : data(std::move(other.data)) {}
+ QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) {
+ QVector<QFlagPointer<QQmlPropertyCache>> moved(std::move(other.data));
+ data.swap(moved);
+ return *this;
+ }
+
+ ~QQmlPropertyCacheVector() { clear(); }
+ void resize(int size) { return data.resize(size); }
+ int count() const { return data.count(); }
+ void clear()
+ {
+ for (int i = 0; i < data.count(); ++i) {
+ if (QQmlPropertyCache *cache = data.at(i).data())
+ cache->release();
+ }
+ data.clear();
+ }
+
+ void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); }
+ QQmlPropertyCache *at(int index) const { return data.at(index).data(); }
+ void set(int index, QQmlPropertyCache *replacement) {
+ if (QQmlPropertyCache *oldCache = data.at(index).data()) {
+ if (replacement == oldCache)
+ return;
+ oldCache->release();
+ }
+ data[index] = replacement;
+ replacement->addref();
+ }
+
+ void setNeedsVMEMetaObject(int index) { data[index].setFlag(); }
+ bool needsVMEMetaObject(int index) const { return data.at(index).flag(); }
+private:
+ Q_DISABLE_COPY(QQmlPropertyCacheVector)
+ QVector<QFlagPointer<QQmlPropertyCache>> data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
+
QT_END_NAMESPACE
#endif // QQMLPROPERTYCACHE_P_H
diff --git a/src/qml/qml/qqmlpropertyindex_p.h b/src/qml/qml/qqmlpropertyindex_p.h
new file mode 100644
index 0000000000..ebc1828efb
--- /dev/null
+++ b/src/qml/qml/qqmlpropertyindex_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTYINDEX_P_H
+#define QQMLPROPERTYINDEX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlPropertyIndex
+{
+ qint32 index;
+
+public:
+ QQmlPropertyIndex()
+ { index = -1; }
+
+ static QQmlPropertyIndex fromEncoded(qint32 encodedIndex)
+ {
+ QQmlPropertyIndex idx;
+ idx.index = encodedIndex;
+ return idx;
+ }
+
+ explicit QQmlPropertyIndex(int coreIndex)
+ { index = encode(coreIndex, -1); }
+
+ explicit QQmlPropertyIndex(int coreIndex, int valueTypeIndex)
+ : index(encode(coreIndex, valueTypeIndex))
+ {}
+
+ bool isValid() const
+ { return index != -1; }
+
+ int coreIndex() const
+ {
+ if (index == -1)
+ return -1;
+ return index & 0xffff;
+ }
+
+ int valueTypeIndex() const
+ {
+ if (index == -1)
+ return -1;
+ return (index >> 16) - 1;
+ }
+
+ bool hasValueTypeIndex() const
+ {
+ if (index == -1)
+ return false;
+ return index >> 16;
+ }
+
+ qint32 toEncoded() const
+ { return index; }
+
+ int intValue() const
+ { return index; }
+
+ bool operator==(const QQmlPropertyIndex &other) const
+ { return index == other.index; }
+
+ bool operator!=(const QQmlPropertyIndex &other) const
+ { return !operator==(other); }
+
+private:
+ static qint32 encode(int coreIndex, int valueTypeIndex)
+ {
+ Q_ASSERT(coreIndex >= -1);
+ Q_ASSERT(coreIndex <= 0xffff);
+ Q_ASSERT(valueTypeIndex >= -1);
+ Q_ASSERT(valueTypeIndex < 0xffff);
+
+ if (coreIndex == -1)
+ return -1;
+ else
+ return coreIndex | ((valueTypeIndex + 1) << 16);
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYINDEX_P_H
diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
index 0c10d13aea..a3d6b0c8c7 100644
--- a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
+++ b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
@@ -52,6 +52,7 @@
//
#include <private/qtqmlglobal_p.h>
+#include <private/qqmlpropertyindex_p.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
@@ -68,8 +69,7 @@ public:
private:
friend class QQmlInterceptorMetaObject;
- int m_coreIndex;
- int m_valueTypeCoreIndex;
+ QQmlPropertyIndex m_propertyIndex;
QQmlPropertyValueInterceptor *m_next;
};
diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp
index bbaab1e155..27e3c13ff8 100644
--- a/src/qml/qml/qqmlproxymetaobject.cpp
+++ b/src/qml/qml/qqmlproxymetaobject.cpp
@@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE
QQmlProxyMetaObject::QQmlProxyMetaObject(QObject *obj, QList<ProxyData> *mList)
: metaObjects(mList), proxies(0), parent(0), object(obj)
{
- *static_cast<QMetaObject *>(this) = *metaObjects->first().metaObject;
+ *static_cast<QMetaObject *>(this) = *metaObjects->constFirst().metaObject;
QObjectPrivate *op = QObjectPrivate::get(obj);
if (op->metaObject)
@@ -71,7 +71,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
if ((c == QMetaObject::ReadProperty ||
c == QMetaObject::WriteProperty) &&
- id >= metaObjects->last().propertyOffset) {
+ id >= metaObjects->constLast().propertyOffset) {
for (int ii = 0; ii < metaObjects->count(); ++ii) {
const ProxyData &data = metaObjects->at(ii);
@@ -107,7 +107,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
}
}
} else if (c == QMetaObject::InvokeMetaMethod &&
- id >= metaObjects->last().methodOffset) {
+ id >= metaObjects->constLast().methodOffset) {
QMetaMethod m = object->metaObject()->method(id);
if (m.methodType() == QMetaMethod::Signal) {
QMetaObject::activate(object, id, a);
diff --git a/src/qml/qml/qqmlproxymetaobject_p.h b/src/qml/qml/qqmlproxymetaobject_p.h
index 7083f88fa7..2b7a980361 100644
--- a/src/qml/qml/qqmlproxymetaobject_p.h
+++ b/src/qml/qml/qqmlproxymetaobject_p.h
@@ -74,10 +74,10 @@ public:
};
QQmlProxyMetaObject(QObject *, QList<ProxyData> *);
- virtual ~QQmlProxyMetaObject();
+ ~QQmlProxyMetaObject();
protected:
- virtual int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a);
+ int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
private:
QList<ProxyData> *metaObjects;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 4ec3dfe6a5..b576366abf 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -45,14 +45,17 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlthread_p.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlprofiler_p.h>
#include <private/qqmlmemoryprofiler_p.h>
#include <private/qqmltypecompiler_p.h>
+#include <private/qqmlpropertyvalidator_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qdeferredcleanup_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
+#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
#include <QtCore/qmutex.h>
#include <QtCore/qthread.h>
@@ -60,8 +63,11 @@
#include <QtCore/qdiriterator.h>
#include <QtQml/qqmlcomponent.h>
#include <QtCore/qwaitcondition.h>
+#include <QtCore/qloggingcategory.h>
#include <QtQml/qqmlextensioninterface.h>
+#include <functional>
+
#if defined (Q_OS_UNIX)
#include <sys/types.h>
#include <sys/stat.h>
@@ -98,6 +104,11 @@
#endif
DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
+DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE);
+DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE);
+
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
QT_BEGIN_NAMESPACE
@@ -155,7 +166,7 @@ public:
void initializeEngine(QQmlExtensionInterface *, const char *);
protected:
- virtual void shutdownThread();
+ void shutdownThread() override;
private:
void loadThread(QQmlDataBlob *b);
@@ -435,6 +446,39 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
tryDone();
}
+void QQmlDataBlob::setError(const QQmlCompileError &error)
+{
+ QQmlError e;
+ e.setColumn(error.location.column);
+ e.setLine(error.location.line);
+ e.setDescription(error.description);
+ e.setUrl(url());
+ setError(e);
+}
+
+void QQmlDataBlob::setError(const QVector<QQmlCompileError> &errors)
+{
+ QList<QQmlError> finalErrors;
+ finalErrors.reserve(errors.count());
+ for (const QQmlCompileError &error: errors) {
+ QQmlError e;
+ e.setColumn(error.location.column);
+ e.setLine(error.location.line);
+ e.setDescription(error.description);
+ e.setUrl(url());
+ finalErrors << e;
+ }
+ setError(finalErrors);
+}
+
+void QQmlDataBlob::setError(const QString &description)
+{
+ QQmlError e;
+ e.setDescription(description);
+ e.setUrl(finalUrl());
+ setError(e);
+}
+
/*!
Wait for \a blob to become complete or to error. If \a blob is already
complete or in error, or this blob is already complete, this has no effect.
@@ -1081,13 +1125,9 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
QML_MEMORY_SCOPE_URL(blob->m_url);
if (QQmlFile::isSynchronous(blob->m_url)) {
- QQmlFile file(m_engine, blob->m_url);
-
- if (file.isError()) {
- QQmlError error;
- error.setUrl(blob->m_url);
- error.setDescription(file.error());
- blob->setError(error);
+ const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url);
+ if (!QQml_isFileCaseCorrect(fileName)) {
+ blob->setError(QLatin1String("File name case mismatch"));
return;
}
@@ -1095,7 +1135,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
if (blob->m_data.isAsync())
m_thread->callDownloadProgressChanged(blob, 1.);
- setData(blob, &file);
+ setData(blob, fileName);
} else {
#ifndef QT_NO_NETWORK
@@ -1215,11 +1255,11 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
setData(blob, d);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file)
+void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
{
QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::Data d;
- d.d = file;
+ d.d = &fileName;
setData(blob, d);
}
@@ -1270,7 +1310,7 @@ void QQmlTypeLoader::shutdownThread()
}
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
- : QQmlDataBlob(url, type, loader), m_importCache(loader), m_isSingleton(false)
+ : QQmlDataBlob(url, type, loader), m_importCache(loader)
{
}
@@ -1324,7 +1364,8 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
- foreach (const QQmlDirParser::Script &script, qmldir->scripts()) {
+ const auto qmldirScripts = qmldir->scripts();
+ for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
addDependency(blob);
@@ -1371,7 +1412,8 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
- foreach (const QQmlDirParser::Script &script, qmldir->scripts()) {
+ const auto qmldirScripts = qmldir->scripts();
+ for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
addDependency(blob);
@@ -1412,13 +1454,10 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
bool incomplete = false;
- QUrl qmldirUrl;
- if (importQualifier.isEmpty()) {
- qmldirUrl = finalUrl().resolved(QUrl(importUri + QLatin1String("/qmldir")));
- if (!QQmlImports::isLocal(qmldirUrl)) {
- // This is a remote file; the import is currently incomplete
- incomplete = true;
- }
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(importUri + QLatin1String("/qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ // This is a remote file; the import is currently incomplete
+ incomplete = true;
}
if (!m_importCache.addFileImport(importDatabase, importUri, importQualifier, import->majorVersion,
@@ -1434,51 +1473,6 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
return true;
}
-bool QQmlTypeLoader::Blob::addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors)
-{
- Q_ASSERT(errors);
-
- if (pragma.type == QmlIR::Pragma::PragmaSingleton) {
- QUrl myUrl = finalUrl();
-
- QQmlType *ret = QQmlMetaType::qmlType(myUrl, true);
- if (!ret) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
- error.setUrl(myUrl);
- error.setLine(pragma.location.line);
- error.setColumn(pragma.location.column);
- errors->prepend(error);
- return false;
- }
-
- if (!ret->isCompositeSingleton()) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(ret->qmlTypeName()));
- error.setUrl(myUrl);
- error.setLine(pragma.location.line);
- error.setColumn(pragma.location.column);
- errors->prepend(error);
- return false;
- }
- // This flag is used for error checking when a qmldir file marks a type as
- // composite singleton, but there is no pragma Singleton defined in QML.
- m_isSingleton = true;
- } else {
- QQmlError error;
- error.setDescription(QLatin1String("Invalid pragma"));
- error.setUrl(finalUrl());
- error.setLine(pragma.location.line);
- error.setColumn(pragma.location.column);
- errors->prepend(error);
- return false;
- }
-
- return true;
-}
-
-
-
void QQmlTypeLoader::Blob::dependencyError(QQmlDataBlob *blob)
{
if (blob->type() == QQmlDataBlob::QmldirFile) {
@@ -1507,6 +1501,11 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
}
}
+bool QQmlTypeLoader::Blob::isDebugging() const
+{
+ return QV8Engine::getV4(typeLoader()->engine())->debugger() != 0;
+}
+
bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlError> *errors)
{
bool resolve = true;
@@ -1968,7 +1967,13 @@ void QQmlTypeLoader::trimCache()
QList<TypeCache::Iterator> unneededTypes;
for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter) {
QQmlTypeData *typeData = iter.value();
- if (typeData->m_compiledData && typeData->m_compiledData->count() == 1) {
+
+ const bool hasError = !typeData->m_compiledData && !typeData->m_errors.isEmpty();
+ const bool isNotReferenced = typeData->isComplete() && typeData->m_compiledData
+ && typeData->m_compiledData->count() == 1;
+ // typeData->m_compiledData may be set early on in the proccess of loading a file, so it's important
+ // to check the general loading status of the typeData before making any other decisions.
+ if (typeData->count() == 1 && (hasError || isNotReferenced)) {
// There are no live objects of this type
unneededTypes.append(iter);
}
@@ -1978,8 +1983,7 @@ void QQmlTypeLoader::trimCache()
break;
while (!unneededTypes.isEmpty()) {
- TypeCache::Iterator iter = unneededTypes.last();
- unneededTypes.removeLast();
+ TypeCache::Iterator iter = unneededTypes.takeLast();
iter.value()->release();
m_typeCache.erase(iter);
@@ -2009,7 +2013,7 @@ QQmlTypeData::TypeDataCallback::~TypeDataCallback()
QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
: QQmlTypeLoader::Blob(url, QmlFile, manager),
- m_typesResolved(false), m_compiledData(0), m_implicitImport(0), m_implicitImportLoaded(false)
+ m_typesResolved(false), m_implicitImportLoaded(false)
{
}
@@ -2022,14 +2026,11 @@ QQmlTypeData::~QQmlTypeData()
if (QQmlTypeData *tdata = m_compositeSingletons.at(ii).typeData)
tdata->release();
}
- for (QHash<int, TypeReference>::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
+ for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
it != end; ++it) {
if (QQmlTypeData *tdata = it->typeData)
tdata->release();
}
-
- if (m_compiledData)
- m_compiledData->release();
}
const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
@@ -2037,19 +2038,9 @@ const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() cons
return m_scripts;
}
-const QSet<QString> &QQmlTypeData::namespaces() const
-{
- return m_namespaces;
-}
-
-const QList<QQmlTypeData::TypeReference> &QQmlTypeData::compositeSingletons() const
-{
- return m_compositeSingletons;
-}
-
-QQmlCompiledData *QQmlTypeData::compiledData() const
+QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const
{
- return m_compiledData;
+ return m_compiledData.data();
}
void QQmlTypeData::registerCallback(TypeDataCallback *callback)
@@ -2065,10 +2056,115 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
Q_ASSERT(!m_callbacks.contains(callback));
}
+bool QQmlTypeData::tryLoadFromDiskCache()
+{
+ if (disableDiskCache() && !forceDiskCache())
+ return false;
+
+ if (isDebugging())
+ return false;
+
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
+ if (!v4)
+ return false;
+
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
+ {
+ QString error;
+ if (!unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) {
+ qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error;
+ return false;
+ }
+ }
+
+ m_compiledData = unit;
+
+ for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
+ m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ // For remote URLs, we don't delay the loading of the implicit import
+ // because the loading probably requires an asynchronous fetch of the
+ // qmldir (so we can't load it just in time).
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ if (!loadImplicitImport())
+ return false;
+
+ // find the implicit import
+ for (quint32 i = 0; i < m_compiledData->data->nImports; ++i) {
+ const QV4::CompiledData::Import *import = m_compiledData->data->importAt(i);
+ if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".")
+ && import->qualifierIndex == 0
+ && import->majorVersion == -1
+ && import->minorVersion == -1) {
+ QList<QQmlError> errors;
+ if (!fetchQmldir(qmldirUrl, import, 1, &errors)) {
+ setError(errors);
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ for (int i = 0, count = m_compiledData->data->nImports; i < count; ++i) {
+ const QV4::CompiledData::Import *import = m_compiledData->data->importAt(i);
+ QList<QQmlError> errors;
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ 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 false;
+ }
+ }
+
+ return true;
+}
+
+void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
+{
+ Q_ASSERT(m_compiledData);
+ m_compiledData->importCache = importCache;
+ m_compiledData->resolvedTypes = resolvedTypeCache;
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ {
+ QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(&m_compiledData->propertyCaches, engine, m_compiledData, &m_importCache);
+ QQmlCompileError error = propertyCacheCreator.buildMetaObjects();
+ if (error.isSet()) {
+ setError(error);
+ return;
+ }
+ }
+
+ QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> aliasCreator(&m_compiledData->propertyCaches, m_compiledData);
+ aliasCreator.appendAliasPropertiesToMetaObjects();
+}
+
void QQmlTypeData::done()
{
+ QDeferredCleanup cleanup([this]{
+ m_document.reset();
+ m_typeReferences.clear();
+ if (isError())
+ m_compiledData = nullptr;
+ });
+
+ if (isError())
+ return;
+
// Check all script dependencies for errors
- for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ for (int ii = 0; ii < m_scripts.count(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
@@ -2080,16 +2176,17 @@ void QQmlTypeData::done()
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
errors.prepend(error);
setError(errors);
+ return;
}
}
// Check all type dependencies for errors
- for (QHash<int, TypeReference>::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
- !isError() && it != end; ++it) {
+ for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
+ ++it) {
const TypeReference &type = *it;
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
if (type.typeData && type.typeData->isError()) {
- QString typeName = m_document->stringAt(it.key());
+ const QString typeName = stringAt(it.key());
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
@@ -2099,11 +2196,12 @@ void QQmlTypeData::done()
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
errors.prepend(error);
setError(errors);
+ return;
}
}
// Check all composite singleton type dependencies for errors
- for (int ii = 0; !isError() && ii < m_compositeSingletons.count(); ++ii) {
+ for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
const TypeReference &type = m_compositeSingletons.at(ii);
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
if (type.typeData && type.typeData->isError()) {
@@ -2117,27 +2215,101 @@ void QQmlTypeData::done()
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
errors.prepend(error);
setError(errors);
+ return;
}
}
- // If the type is CompositeSingleton but there was no pragma Singleton in the
- // QML file, lets report an error.
- QQmlType *type = QQmlMetaType::qmlType(url(), true);
- if (!isError() && type && type->isCompositeSingleton() && !m_isSingleton) {
- QString typeName = type->qmlTypeName();
+ QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
+ {
+ QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache);
+ if (error.isSet()) {
+ setError(error);
+ return;
+ }
+ }
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
- error.setUrl(finalUrl());
- setError(error);
+ QQmlEngine *const engine = typeLoader()->engine();
+
+ // verify if any dependencies changed if we're using a cache
+ if (m_document.isNull() && !m_compiledData->verifyChecksum(engine, resolvedTypeCache)) {
+ if (!loadFromSource())
+ return;
+ m_backupSourceCode.clear();
+ m_compiledData = nullptr;
}
- // Compile component
- if (!isError())
- compile();
+ if (!m_document.isNull()) {
+ // Compile component
+ compile(importCache, resolvedTypeCache);
+ } else {
+ createTypeAndPropertyCaches(importCache, resolvedTypeCache);
+ }
- m_document.reset();
- m_implicitImport = 0;
+ if (isError())
+ return;
+
+ {
+ QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
+ {
+ // Sanity check property bindings
+ QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
+ QVector<QQmlCompileError> errors = validator.validate();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ }
+
+ m_compiledData->finalize(enginePrivate);
+ }
+
+ {
+ QQmlType *type = QQmlMetaType::qmlType(finalUrl(), true);
+ if (m_compiledData && m_compiledData->data->flags & QV4::CompiledData::Unit::IsSingleton) {
+ if (!type) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
+ setError(error);
+ return;
+ } else if (!type->isCompositeSingleton()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type->qmlTypeName()));
+ setError(error);
+ return;
+ }
+ } else {
+ // If the type is CompositeSingleton but there was no pragma Singleton in the
+ // QML file, lets report an error.
+ if (type && type->isCompositeSingleton()) {
+ QString typeName = type->qmlTypeName();
+ setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
+ return;
+ }
+ }
+ }
+
+ {
+ // Collect imported scripts
+ m_compiledData->dependentScripts.reserve(m_scripts.count());
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
+
+ QStringRef qualifier(&script.qualifier);
+ QString enclosingNamespace;
+
+ const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
+ if (lastDotIndex != -1) {
+ enclosingNamespace = qualifier.left(lastDotIndex).toString();
+ qualifier = qualifier.mid(lastDotIndex+1);
+ }
+
+ m_compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ QQmlScriptData *scriptData = script.script->scriptData();
+ scriptData->addref();
+ m_compiledData->dependentScripts << scriptData;
+ }
+ }
}
void QQmlTypeData::completed()
@@ -2172,14 +2344,47 @@ bool QQmlTypeData::loadImplicitImport()
void QQmlTypeData::dataReceived(const Data &data)
{
- QString code = QString::fromUtf8(data.data(), data.size());
+ QString error;
+ m_backupSourceCode = data.readAll(&error, &m_sourceTimeStamp);
+ // if we failed to read the source code, process it _after_ we've tried
+ // to use the disk cache, in order to support scenarios where the source
+ // was removed deliberately.
+
+ if (tryLoadFromDiskCache())
+ return;
+
+ if (isError())
+ return;
+
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+
+ if (!loadFromSource())
+ return;
+
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ unit->loadIR(m_document.data(), unit);
+ continueLoadFromIR();
+}
+
+bool QQmlTypeData::loadFromSource()
+{
+ QString code = QString::fromUtf8(m_backupSourceCode);
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ m_document->jsModule.sourceTimeStamp = m_sourceTimeStamp;
QQmlEngine *qmlEngine = typeLoader()->engine();
- m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0));
QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames());
if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) {
QList<QQmlError> errors;
errors.reserve(compiler.errors.count());
- foreach (const QQmlJS::DiagnosticMessage &msg, compiler.errors) {
+ for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
QQmlError e;
e.setUrl(finalUrl());
e.setLine(msg.loc.startLine);
@@ -2188,23 +2393,14 @@ void QQmlTypeData::dataReceived(const Data &data)
errors << e;
}
setError(errors);
- return;
+ return false;
}
-
- continueLoadFromIR();
-}
-
-void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
-{
- QQmlEngine *qmlEngine = typeLoader()->engine();
- m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0));
- unit->loadIR(m_document.data(), unit);
- continueLoadFromIR();
+ return true;
}
void QQmlTypeData::continueLoadFromIR()
{
- m_document->collectTypeReferences();
+ m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
m_importCache.setBaseUrl(finalUrl(), finalUrlString());
// For remote URLs, we don't delay the loading of the implicit import
@@ -2217,14 +2413,14 @@ void QQmlTypeData::continueLoadFromIR()
return;
// This qmldir is for the implicit import
QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool();
- m_implicitImport = pool->New<QV4::CompiledData::Import>();
- m_implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
- m_implicitImport->qualifierIndex = 0; // empty string
- m_implicitImport->majorVersion = -1;
- m_implicitImport->minorVersion = -1;
+ auto implicitImport = pool->New<QV4::CompiledData::Import>();
+ implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
+ implicitImport->qualifierIndex = 0; // empty string
+ implicitImport->majorVersion = -1;
+ implicitImport->minorVersion = -1;
QList<QQmlError> errors;
- if (!fetchQmldir(qmldirUrl, m_implicitImport, 1, &errors)) {
+ if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
setError(errors);
return;
}
@@ -2245,14 +2441,6 @@ void QQmlTypeData::continueLoadFromIR()
return;
}
}
-
- foreach (QmlIR::Pragma *pragma, m_document->pragmas) {
- if (!addPragma(*pragma, &errors)) {
- Q_ASSERT(errors.size());
- setError(errors);
- return;
- }
- }
}
void QQmlTypeData::allDependenciesDone()
@@ -2297,40 +2485,54 @@ void QQmlTypeData::downloadProgressChanged(qreal p)
QString QQmlTypeData::stringAt(int index) const
{
+ if (m_compiledData)
+ return m_compiledData->stringAt(index);
return m_document->jsGenerator.stringTable.stringForIndex(index);
}
-void QQmlTypeData::compile()
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
- Q_ASSERT(m_compiledData == 0);
-
- m_compiledData = new QQmlCompiledData(typeLoader()->engine());
+ Q_ASSERT(m_compiledData.isNull());
- QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data());
- if (!compiler.compile()) {
+ QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
+ QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache);
+ m_compiledData = compiler.compile();
+ if (!m_compiledData) {
setError(compiler.compilationErrors());
- m_compiledData->release();
- m_compiledData = 0;
+ return;
+ }
+
+ const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode;
+ if (trySaveToDisk) {
+ QString errorString;
+ if (m_compiledData->saveToDisk(url(), &errorString)) {
+ QString error;
+ if (!m_compiledData->loadFromDisk(url(), enginePrivate->v4engine()->iselFactory.data(), &error)) {
+ // ignore error, keep using the in-memory compilation unit.
+ }
+ } else {
+ qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString;
+ }
}
}
void QQmlTypeData::resolveTypes()
{
// Add any imported scripts to our resolved set
- foreach (const QQmlImports::ScriptReference &script, m_importCache.resolvedScripts())
- {
+ const auto resolvedScripts = m_importCache.resolvedScripts();
+ for (const QQmlImports::ScriptReference &script : resolvedScripts) {
QQmlScriptBlob *blob = typeLoader()->getScript(script.location);
addDependency(blob);
ScriptReference ref;
//ref.location = ...
- ref.qualifier = script.nameSpace;
if (!script.qualifier.isEmpty())
{
- ref.qualifier.prepend(script.qualifier + QLatin1Char('.'));
-
+ ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace;
// Add a reference to the enclosing namespace
m_namespaces.insert(script.qualifier);
+ } else {
+ ref.qualifier = script.nameSpace;
}
ref.script = blob;
@@ -2338,14 +2540,16 @@ void QQmlTypeData::resolveTypes()
}
// Lets handle resolved composite singleton types
- foreach (const QQmlImports::CompositeSingletonReference &csRef, m_importCache.resolvedCompositeSingletons()) {
+ const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
+ for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
TypeReference ref;
- QString typeName = csRef.typeName;
-
+ QString typeName;
if (!csRef.prefix.isEmpty()) {
- typeName.prepend(csRef.prefix + QLatin1Char('.'));
+ typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName;
// Add a reference to the enclosing namespace
m_namespaces.insert(csRef.prefix);
+ } else {
+ typeName = csRef.typeName;
}
int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1;
@@ -2363,7 +2567,7 @@ void QQmlTypeData::resolveTypes()
}
}
- for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_document->typeReferences.constBegin(), end = m_document->typeReferences.constEnd();
+ for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
unresolvedRef != end; ++unresolvedRef) {
TypeReference ref; // resolved reference
@@ -2433,6 +2637,57 @@ void QQmlTypeData::resolveTypes()
}
}
+QQmlCompileError QQmlTypeData::buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const
+{
+ importCache->adopt(new QQmlTypeNameCache);
+
+ for (const QString &ns: m_namespaces)
+ (*importCache)->add(ns);
+
+ // Add any Composite Singletons that were used to the import cache
+ for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
+ (*importCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
+
+ m_importCache.populateCache(*importCache);
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
+ QScopedPointer<QV4::CompiledData::ResolvedTypeReference> ref(new QV4::CompiledData::ResolvedTypeReference);
+ QQmlType *qmlType = resolvedType->type;
+ if (resolvedType->typeData) {
+ if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) {
+ return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName()));
+ }
+ ref->compilationUnit = resolvedType->typeData->compilationUnit();
+ } else if (qmlType) {
+ ref->type = qmlType;
+ Q_ASSERT(ref->type);
+
+ if (resolvedType->needsCreation && !ref->type->isCreatable()) {
+ QString reason = ref->type->noCreationReason();
+ if (reason.isEmpty())
+ reason = tr("Element is not creatable.");
+ return QQmlCompileError(resolvedType->location, reason);
+ }
+
+ if (ref->type->containsRevisionedAttributes()) {
+ ref->typePropertyCache = engine->cache(ref->type,
+ resolvedType->minorVersion);
+ }
+ }
+ ref->majorVersion = resolvedType->majorVersion;
+ ref->minorVersion = resolvedType->minorVersion;
+ ref->doDynamicTypeCheck();
+ resolvedTypeCache->insert(resolvedType.key(), ref.take());
+ }
+ QQmlCompileError noError;
+ return noError;
+}
+
bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref)
{
QQmlImportNamespace *typeNamespace = 0;
@@ -2554,10 +2809,6 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
ctxt->importedScripts = effectiveCtxt->importedScripts;
}
- if (ctxt->imports) {
- ctxt->imports->addref();
- }
-
if (effectiveCtxt) {
ctxt->setParent(effectiveCtxt, true);
} else {
@@ -2640,15 +2891,34 @@ QQmlScriptData *QQmlScriptBlob::scriptData() const
struct EmptyCompilationUnit : public QV4::CompiledData::CompilationUnit
{
- virtual void linkBackendToEngine(QV4::ExecutionEngine *) {}
+ void linkBackendToEngine(QV4::ExecutionEngine *) override {}
};
void QQmlScriptBlob::dataReceived(const Data &data)
{
- QString source = QString::fromUtf8(data.data(), data.size());
-
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
- QmlIR::Document irUnit(v4->debugger != 0);
+
+ if (!disableDiskCache() || forceDiskCache()) {
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
+ QString error;
+ if (unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) {
+ initializeFromCompilationUnit(unit);
+ return;
+ } else {
+ qCDebug(DBG_DISK_CACHE()) << "Error loading" << url().toString() << "from disk cache:" << error;
+ }
+ }
+
+
+ QmlIR::Document irUnit(isDebugging());
+
+ QString error;
+ QString source = QString::fromUtf8(data.readAll(&error, &irUnit.jsModule.sourceTimeStamp));
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+
QmlIR::ScriptDirectivesCollector collector(&irUnit.jsParserEngine, &irUnit.jsGenerator);
QList<QQmlError> errors;
@@ -2665,14 +2935,22 @@ void QQmlScriptBlob::dataReceived(const Data &data)
irUnit.javaScriptCompilationUnit = unit;
irUnit.imports = collector.imports;
if (collector.hasPragmaLibrary)
- irUnit.unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary;
+ irUnit.jsModule.unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary;
QmlIR::QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit);
+ QV4::CompiledData::ResolvedTypeReferenceMap emptyDependencies;
+ QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit, m_typeLoader->engine(), emptyDependencies);
Q_ASSERT(!unit->data);
// The js unit owns the data and will free the qml unit.
unit->data = unitData;
+ if (!disableDiskCache() || forceDiskCache()) {
+ QString errorString;
+ if (!unit->saveToDisk(url(), &errorString)) {
+ qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->url().toString() << "to disk:" << errorString;
+ }
+ }
+
initializeFromCompilationUnit(unit);
}
@@ -2683,8 +2961,11 @@ void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *
void QQmlScriptBlob::done()
{
+ if (isError())
+ return;
+
// Check all script dependencies for errors
- for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ for (int ii = 0; ii < m_scripts.count(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
@@ -2696,17 +2977,15 @@ void QQmlScriptBlob::done()
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
errors.prepend(error);
setError(errors);
+ return;
}
}
- if (isError())
- return;
-
m_scriptData->importCache = new QQmlTypeNameCache();
QSet<QString> ns;
- for (int scriptIndex = 0; !isError() && scriptIndex < m_scripts.count(); ++scriptIndex) {
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
const ScriptReference &script = m_scripts.at(scriptIndex);
m_scriptData->scripts.append(script.script);
@@ -2800,7 +3079,12 @@ void QQmlQmldirData::setPriority(int priority)
void QQmlQmldirData::dataReceived(const Data &data)
{
- m_content = QString::fromUtf8(data.data(), data.size());
+ QString error;
+ m_content = QString::fromUtf8(data.readAll(&error));
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
}
void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *)
@@ -2808,6 +3092,30 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *
Q_UNIMPLEMENTED();
}
+QByteArray QQmlDataBlob::Data::readAll(QString *error, qint64 *sourceTimeStamp) const
+{
+ Q_ASSERT(!d.isNull());
+ error->clear();
+ if (d.isT1()) {
+ if (sourceTimeStamp)
+ *sourceTimeStamp = 0;
+ return *d.asT1();
+ }
+ QFile f(*d.asT2());
+ if (!f.open(QIODevice::ReadOnly)) {
+ *error = f.errorString();
+ return QByteArray();
+ }
+ if (sourceTimeStamp)
+ *sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch();
+ QByteArray data(f.size(), Qt::Uninitialized);
+ if (f.read(data.data(), data.length()) != data.length()) {
+ *error = f.errorString();
+ return QByteArray();
+ }
+ return data;
+}
+
QT_END_NAMESPACE
#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 12ab98e425..12c55e9179 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -77,11 +77,11 @@ class QQmlScriptData;
class QQmlScriptBlob;
class QQmlQmldirData;
class QQmlTypeLoader;
-class QQmlCompiledData;
class QQmlComponentPrivate;
class QQmlTypeData;
class QQmlTypeLoader;
class QQmlExtensionInterface;
+struct QQmlCompileError;
namespace QmlIR {
struct Document;
@@ -131,27 +131,23 @@ public:
class Data {
public:
- inline const char *data() const;
- inline int size() const;
-
- inline QByteArray asByteArray() const;
-
- inline bool isFile() const;
- inline QQmlFile *asFile() const;
-
+ QByteArray readAll(QString *error, qint64 *sourceTimeStamp = 0) const;
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
inline Data();
Data(const Data &);
Data &operator=(const Data &);
- QBiPointer<const QByteArray, QQmlFile> d;
+ QBiPointer<const QByteArray, const QString> d;
};
protected:
// Can be called from within callbacks
void setError(const QQmlError &);
void setError(const QList<QQmlError> &errors);
+ void setError(const QQmlCompileError &error);
+ void setError(const QVector<QQmlCompileError> &errors);
+ void setError(const QString &description);
void addDependency(QQmlDataBlob *);
// Callbacks made in load thread
@@ -237,7 +233,6 @@ public:
protected:
bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
- bool addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors);
bool fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors);
bool updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
@@ -247,14 +242,15 @@ public:
virtual void scriptImported(QQmlScriptBlob *, const QV4::CompiledData::Location &, const QString &, const QString &) {}
- virtual void dependencyError(QQmlDataBlob *);
- virtual void dependencyComplete(QQmlDataBlob *);
+ void dependencyError(QQmlDataBlob *) override;
+ void dependencyComplete(QQmlDataBlob *) override;
protected:
virtual QString stringAt(int) const { return QString(); }
+ bool isDebugging() const;
+
QQmlImports m_importCache;
- bool m_isSingleton;
QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
QList<QQmlQmldirData *> m_qmldirs;
};
@@ -341,7 +337,7 @@ private:
#endif
void setData(QQmlDataBlob *, const QByteArray &);
- void setData(QQmlDataBlob *, QQmlFile *);
+ void setData(QQmlDataBlob *, const QString &fileName);
void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
@@ -391,6 +387,7 @@ private:
class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
{
+ Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
public:
struct TypeReference
{
@@ -422,13 +419,9 @@ private:
public:
~QQmlTypeData();
- const QHash<int, TypeReference> &resolvedTypeRefs() const { return m_resolvedTypes; }
-
const QList<ScriptReference> &resolvedScripts() const;
- const QSet<QString> &namespaces() const;
- const QList<TypeReference> &compositeSingletons() const;
- QQmlCompiledData *compiledData() const;
+ QV4::CompiledData::CompilationUnit *compilationUnit() const;
// Used by QQmlComponent to get notifications
struct TypeDataCallback {
@@ -440,24 +433,37 @@ public:
void unregisterCallback(TypeDataCallback *);
protected:
- virtual void done();
- virtual void completed();
- virtual void dataReceived(const Data &);
- virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit);
- virtual void allDependenciesDone();
- virtual void downloadProgressChanged(qreal);
+ void done() override;
+ void completed() override;
+ void dataReceived(const Data &) override;
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override;
+ void allDependenciesDone() override;
+ void downloadProgressChanged(qreal) override;
- virtual QString stringAt(int index) const;
+ QString stringAt(int index) const override;
private:
+ bool tryLoadFromDiskCache();
+ bool loadFromSource();
void continueLoadFromIR();
void resolveTypes();
- void compile();
+ QQmlCompileError buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const;
+ void compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+ void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref);
- virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace);
+ void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+
+ qint64 m_sourceTimeStamp = 0;
+ QByteArray m_backupSourceCode; // used when cache verification fails.
QScopedPointer<QmlIR::Document> m_document;
+ QV4::CompiledData::TypeReferenceMap m_typeReferences;
QList<ScriptReference> m_scripts;
@@ -465,14 +471,15 @@ private:
QList<TypeReference> m_compositeSingletons;
// map from name index to resolved type
- QHash<int, TypeReference> m_resolvedTypes;
+ // While this could be a hash, a map is chosen here to provide a stable
+ // order, which is used to calculating a check-sum on dependent meta-objects.
+ QMap<int, TypeReference> m_resolvedTypes;
bool m_typesResolved:1;
- QQmlCompiledData *m_compiledData;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compiledData;
QList<TypeDataCallback *> m_callbacks;
- QV4::CompiledData::Import *m_implicitImport;
bool m_implicitImportLoaded;
bool loadImplicitImport();
};
@@ -502,7 +509,7 @@ public:
QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
protected:
- virtual void clear(); // From QQmlCleanup
+ void clear() override; // From QQmlCleanup
private:
friend class QQmlScriptBlob;
@@ -538,14 +545,14 @@ public:
QQmlScriptData *scriptData() const;
protected:
- virtual void dataReceived(const Data &);
- virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit);
- virtual void done();
+ void dataReceived(const Data &) override;
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override;
+ void done() override;
- virtual QString stringAt(int index) const;
+ QString stringAt(int index) const override;
private:
- virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace);
+ void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
void initializeFromCompilationUnit(QV4::CompiledData::CompilationUnit *unit);
QList<ScriptReference> m_scripts;
@@ -582,40 +589,7 @@ QQmlDataBlob::Data::Data()
{
}
-const char *QQmlDataBlob::Data::data() const
-{
- Q_ASSERT(!d.isNull());
- if (d.isT1()) return d.asT1()->constData();
- else return d.asT2()->data();
-}
-
-int QQmlDataBlob::Data::size() const
-{
- Q_ASSERT(!d.isNull());
-
- if (d.isT1()) return d.asT1()->size();
- else return d.asT2()->size();
-}
-
-bool QQmlDataBlob::Data::isFile() const
-{
- return d.isT2();
-}
-
-QByteArray QQmlDataBlob::Data::asByteArray() const
-{
- Q_ASSERT(!d.isNull());
-
- if (d.isT1()) return *d.asT1();
- else return d.asT2()->dataByteArray();
-}
-
-QQmlFile *QQmlDataBlob::Data::asFile() const
-{
- if (d.isT2()) return d.asT2();
- else return 0;
-}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 7892555f08..28c2588117 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -58,12 +58,14 @@ DEFINE_OBJECT_VTABLE(QmlTypeWrapper);
Heap::QmlTypeWrapper::QmlTypeWrapper()
: mode(IncludeEnums)
{
+ object.init();
}
Heap::QmlTypeWrapper::~QmlTypeWrapper()
{
if (typeNamespace)
typeNamespace->release();
+ object.destroy();
}
bool QmlTypeWrapper::isSingleton() const
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 8216526cb5..7c5105b184 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -74,7 +74,7 @@ struct QmlTypeWrapper : Object {
QmlTypeWrapper();
~QmlTypeWrapper();
TypeNameMode mode;
- QPointer<QObject> object;
+ QQmlQPointer<QObject> object;
QQmlType *type;
QQmlTypeNameCache *typeNamespace;
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index 44fd47244d..bcefad0ee3 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -88,6 +88,7 @@ bool QQmlValueTypeFactoryImpl::isValueType(int idx)
&& idx != QVariant::StringList
&& idx != QMetaType::QObjectStar
&& idx != QMetaType::VoidStar
+ && idx != QMetaType::Nullptr
&& idx != QMetaType::QVariant
&& idx != QMetaType::QLocale) {
return true;
@@ -219,7 +220,7 @@ void QQmlValueType::read(QObject *obj, int idx)
QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
}
-void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyPrivate::WriteFlags flags)
+void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags)
{
Q_ASSERT(gadgetPtr);
int status = -1;
@@ -259,7 +260,7 @@ int QQmlValueType::metaCall(QObject *, QMetaObject::Call type, int _id, void **a
QString QQmlPointFValueType::toString() const
{
- return QString(QLatin1String("QPointF(%1, %2)")).arg(v.x()).arg(v.y());
+ return QString::asprintf("QPointF(%g, %g)", v.x(), v.y());
}
qreal QQmlPointFValueType::x() const
@@ -306,7 +307,7 @@ void QQmlPointValueType::setY(int y)
QString QQmlSizeFValueType::toString() const
{
- return QString(QLatin1String("QSizeF(%1, %2)")).arg(v.width()).arg(v.height());
+ return QString::asprintf("QSizeF(%g, %g)", v.width(), v.height());
}
qreal QQmlSizeFValueType::width() const
@@ -352,7 +353,7 @@ void QQmlSizeValueType::setHeight(int h)
QString QQmlRectFValueType::toString() const
{
- return QString(QLatin1String("QRectF(%1, %2, %3, %4)")).arg(v.x()).arg(v.y()).arg(v.width()).arg(v.height());
+ return QString::asprintf("QRectF(%g, %g, %g, %g)", v.x(), v.y(), v.width(), v.height());
}
qreal QQmlRectFValueType::x() const
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 910d39cf0a..0502a5d665 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -69,14 +69,14 @@ public:
QQmlValueType(int userType, const QMetaObject *metaObject);
~QQmlValueType();
void read(QObject *, int);
- void write(QObject *, int, QQmlPropertyPrivate::WriteFlags flags);
+ void write(QObject *, int, QQmlPropertyData::WriteFlags flags);
QVariant value();
void setValue(const QVariant &);
// ---- dynamic meta object data interface
- virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *);
- virtual void objectDestroyed(QObject *);
- virtual int metaCall(QObject *obj, QMetaObject::Call type, int _id, void **argv);
+ QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override;
+ void objectDestroyed(QObject *) override;
+ int metaCall(QObject *obj, QMetaObject::Call type, int _id, void **argv) override;
// ----
private:
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
index 6858215a79..56f073121e 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp
+++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
@@ -41,7 +41,7 @@
QT_BEGIN_NAMESPACE
-QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index)
+QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex index)
: QQmlAbstractBinding(),
m_bindings(0)
{
@@ -58,7 +58,7 @@ QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding()
}
}
-void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
{
QQmlAbstractBinding *b = m_bindings.data();
while (b) {
@@ -72,7 +72,7 @@ bool QQmlValueTypeProxyBinding::isValueTypeProxy() const
return true;
}
-QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex)
+QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(QQmlPropertyIndex propertyIndex)
{
QQmlAbstractBinding *binding = m_bindings.data();
@@ -91,7 +91,7 @@ void QQmlValueTypeProxyBinding::removeBindings(quint32 mask)
QQmlAbstractBinding *lastBinding = 0;
while (binding) {
- int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(binding->targetPropertyIndex());
+ const int valueTypeIndex = binding->targetPropertyIndex().valueTypeIndex();
if (valueTypeIndex != -1 && (mask & (1 << valueTypeIndex))) {
QQmlAbstractBinding *remove = binding;
remove->setAddedToObject(false);
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
index de5acc2984..aa7abaa486 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h
+++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
@@ -58,13 +58,13 @@ QT_BEGIN_NAMESPACE
class QQmlValueTypeProxyBinding : public QQmlAbstractBinding
{
public:
- QQmlValueTypeProxyBinding(QObject *o, int coreIndex);
+ QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex coreIndex);
- QQmlAbstractBinding *binding(int targetPropertyIndex);
+ QQmlAbstractBinding *binding(QQmlPropertyIndex targetPropertyIndex);
void removeBindings(quint32 mask);
- virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags);
- virtual bool isValueTypeProxy() const;
+ void setEnabled(bool, QQmlPropertyData::WriteFlags) override;
+ bool isValueTypeProxy() const override;
protected:
~QQmlValueTypeProxyBinding();
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 5cb346a462..6b308374e6 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -63,8 +63,9 @@ namespace Heap {
struct QQmlValueTypeReference : QQmlValueTypeWrapper
{
- QQmlValueTypeReference() {}
- QPointer<QObject> object;
+ QQmlValueTypeReference() { object.init(); }
+ ~QQmlValueTypeReference() { object.destroy(); }
+ QQmlQPointer<QObject> object;
int property;
};
@@ -332,7 +333,8 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx)
if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->typeId, &convertResult, QMetaType::QString)) {
result = convertResult;
} else {
- result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)) + QLatin1Char('(');
+ result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId))
+ + QLatin1Char('(');
const QMetaObject *mo = w->d()->propertyCache->metaObject();
const int propCount = mo->propertyCount();
for (int i = 0; i < propCount; ++i) {
@@ -369,10 +371,10 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha
if (result->isFunction())
// calling a Q_INVOKABLE function of a value type
- return QV4::QObjectMethod::create(v4->rootContext(), r, result->coreIndex);
+ return QV4::QObjectMethod::create(v4->rootContext(), r, result->coreIndex());
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
- if (result->propType == metatype) { \
+ if (result->propType() == metatype) { \
cpptype v; \
void *args[] = { &v, 0 }; \
metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args); \
@@ -381,7 +383,7 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha
const QMetaObject *metaObject = r->d()->propertyCache->metaObject();
- int index = result->coreIndex;
+ int index = result->coreIndex();
QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index);
void *gadget = r->d()->gadgetPtr;
@@ -394,10 +396,10 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha
QVariant v;
void *args[] = { Q_NULLPTR, Q_NULLPTR };
- if (result->propType == QMetaType::QVariant) {
+ if (result->propType() == QMetaType::QVariant) {
args[0] = &v;
} else {
- v = QVariant(result->propType, static_cast<void *>(Q_NULLPTR));
+ v = QVariant(result->propType(), static_cast<void *>(Q_NULLPTR));
args[0] = v.data();
}
metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args);
@@ -431,8 +433,6 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
const QQmlPropertyData *pd = r->d()->propertyCache->property(name, 0, 0);
if (!pd)
return;
- QMetaProperty property = metaObject->property(pd->coreIndex);
- Q_ASSERT(property.isValid());
if (reference) {
QV4::ScopedFunctionObject f(scope, value);
@@ -448,27 +448,24 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QQmlContextData *context = v4->callingQmlContext();
QQmlPropertyData cacheData;
- cacheData.setFlags(QQmlPropertyData::IsWritable |
- QQmlPropertyData::IsValueTypeVirtual);
- cacheData.propType = writeBackPropertyType;
- cacheData.coreIndex = reference->d()->property;
- cacheData.valueTypeFlags = 0;
- cacheData.valueTypeCoreIndex = pd->coreIndex;
- cacheData.valueTypePropType = property.userType();
+ cacheData.setWritable(true);
+ cacheData.setPropType(writeBackPropertyType);
+ cacheData.setCoreIndex(reference->d()->property);
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
bindingFunction->initBindingLocation();
- QQmlBinding *newBinding = new QQmlBinding(value, reference->d()->object, context);
- newBinding->setTarget(reference->d()->object, cacheData);
+ QQmlBinding *newBinding = QQmlBinding::create(&cacheData, value, reference->d()->object, context);
+ newBinding->setTarget(reference->d()->object, cacheData, pd);
QQmlPropertyPrivate::setBinding(newBinding);
return;
} else {
- QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyData::encodeValueTypePropertyIndex(reference->d()->property, pd->coreIndex));
-
+ QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyIndex(reference->d()->property, pd->coreIndex()));
}
}
+ QMetaProperty property = metaObject->property(pd->coreIndex());
+ Q_ASSERT(property.isValid());
QVariant v = v4->toVariant(value, property.userType());
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 5f9fa69944..01c4f476d6 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -39,7 +39,6 @@
#include "qqmlvme_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlboundsignal_p.h"
#include "qqmlstringconverters_p.h"
#include <private/qmetaobjectbuilder_p.h>
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index ac9db5c046..99d63380ad 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -69,7 +69,6 @@ QT_BEGIN_NAMESPACE
class QObject;
class QJSValue;
class QQmlScriptData;
-class QQmlCompiledData;
class QQmlContextData;
namespace QQmlVMETypes {
@@ -84,10 +83,9 @@ namespace QQmlVMETypes {
struct State {
enum Flag { Deferred = 0x00000001 };
- State() : flags(0), context(0), compiledData(0), instructionStream(0) {}
+ State() : flags(0), context(0), instructionStream(0) {}
quint32 flags;
QQmlContextData *context;
- QQmlCompiledData *compiledData;
const char *instructionStream;
QBitField bindingSkipList;
};
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 8697a291e2..4f13b44fc0 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -159,14 +159,13 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
if (!targetDData)
return;
- int coreIndex;
- QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, &coreIndex);
+ int coreIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex).coreIndex();
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
if (!pd)
return;
- if (pd->notifyIndex != -1)
- connect(target, pd->notifyIndex, ctxt->engine);
+ if (pd->notifyIndex() != -1)
+ connect(target, pd->notifyIndex(), ctxt->engine);
}
metaObject.setFlag();
@@ -199,10 +198,9 @@ QQmlInterceptorMetaObject::~QQmlInterceptorMetaObject()
}
-void QQmlInterceptorMetaObject::registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor)
+void QQmlInterceptorMetaObject::registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor)
{
- interceptor->m_coreIndex = index;
- interceptor->m_valueTypeCoreIndex = valueIndex;
+ interceptor->m_propertyIndex = index;
interceptor->m_next = interceptors;
interceptors = interceptor;
}
@@ -220,14 +218,14 @@ int QQmlInterceptorMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id,
bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
{
if (c == QMetaObject::WriteProperty && interceptors &&
- !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyPrivate::BypassInterceptor)) {
+ !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)) {
for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
- if (vi->m_coreIndex != id)
+ if (vi->m_propertyIndex.coreIndex() != id)
continue;
- int valueIndex = vi->m_valueTypeCoreIndex;
- int type = QQmlData::get(object)->propertyCache->property(id)->propType;
+ const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
+ int type = QQmlData::get(object)->propertyCache->property(id)->propType();
if (type != QVariant::Invalid) {
if (valueIndex != -1) {
@@ -278,7 +276,7 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
bool updated = false;
if (newComponentValue != prevComponentValue) {
valueProp.write(valueType, prevComponentValue);
- valueType->write(object, id, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
+ valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
vi->write(newComponentValue);
updated = true;
@@ -319,8 +317,6 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
ctxt(QQmlData::get(obj, true)->outerContext),
aliasEndpoints(0), compilationUnit(qmlCompilationUnit), compiledObject(0)
{
- cache->addref();
-
QQmlData::get(obj)->hasVMEMetaObject = true;
if (compilationUnit && qmlObjectId >= 0) {
@@ -345,8 +341,6 @@ QQmlVMEMetaObject::~QQmlVMEMetaObject()
delete [] aliasEndpoints;
qDeleteAll(varObjectGuards);
-
- cache->release();
}
QV4::MemberData *QQmlVMEMetaObject::propertyAndMethodStorageAsMemberData()
@@ -614,6 +608,9 @@ QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id)
return v->d()->data.value<QRectF>();
}
+#if defined(Q_OS_WINRT) && defined(_M_ARM)
+#pragma optimize("", off)
+#endif
int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void **a)
{
Q_ASSERT(o == object);
@@ -634,7 +631,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= propOffset();
if (id < propertyCount) {
- const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(compiledObject->propertyTable()[id].type);
+ const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(qint32(compiledObject->propertyTable()[id].type));
bool needActivate = false;
if (t == QV4::CompiledData::Property::Var) {
@@ -849,6 +846,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (!ctxt) return -1;
+ while (aliasData->aliasToLocalAlias)
+ aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
+
QQmlContext *context = ctxt->asQQmlContext();
QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
@@ -867,16 +867,17 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (!targetDData)
return -1;
- int coreIndex;
- const int valueTypePropertyIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, &coreIndex);
+ QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
+ int coreIndex = encodedIndex.coreIndex();
+ const int valueTypePropertyIndex = encodedIndex.valueTypeIndex();
// Remove binding (if any) on write
if(c == QMetaObject::WriteProperty) {
int flags = *reinterpret_cast<int*>(a[3]);
- if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) {
+ if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
QQmlData *targetData = QQmlData::get(target);
if (targetData && targetData->hasBindingBit(coreIndex))
- QQmlPropertyPrivate::removeBinding(target, aliasData->encodedMetaPropertyIndex);
+ QQmlPropertyPrivate::removeBinding(target, encodedIndex);
}
}
@@ -885,7 +886,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
return -1;
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
// Value type property
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType);
+ QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType());
Q_ASSERT(valueType);
valueType->read(target, coreIndex);
@@ -934,10 +935,10 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
// are not rewritten correctly but this bug is deemed out-of-scope to fix for
// performance reasons; see QTBUG-24064) and thus compilation will have failed.
QQmlError e;
- e.setDescription(QString::fromLatin1("Exception occurred during compilation of "
- "function: %1")
- .arg(QString::fromUtf8(QMetaObject::method(_id)
- .methodSignature())));
+ e.setDescription(QLatin1String("Exception occurred during compilation of "
+ "function: ")
+ + QString::fromUtf8(QMetaObject::method(_id)
+ .methodSignature()));
ep->warning(e);
return -1; // The dynamic method with that id is not available.
}
@@ -949,15 +950,14 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
for (uint ii = 0; ii < parameterCount; ++ii)
callData->args[ii] = scope.engine->fromVariant(*(QVariant *)a[ii + 1]);
- QV4::ScopedValue result(scope);
- result = function->call(callData);
+ function->call(scope, callData);
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
if (error.isValid())
ep->warning(error);
if (a[0]) *(QVariant *)a[0] = QVariant();
} else {
- if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
+ if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(scope.result, 0);
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -972,6 +972,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
else
return object->qt_metacall(c, _id, a);
}
+#if defined(Q_OS_WINRT) && defined(_M_ARM)
+#pragma optimize("", on)
+#endif
QV4::ReturnedValue QQmlVMEMetaObject::method(int index)
{
@@ -1191,8 +1194,11 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
if (!*target)
return false;
- if (!aliasData->isObjectAlias())
- *valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, coreIndex);
+ if (!aliasData->isObjectAlias()) {
+ QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
+ *coreIndex = encodedIndex.coreIndex();
+ *valueTypeIndex = encodedIndex.valueTypeIndex();
+ }
return true;
}
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 75e7ed6cb1..031bfdfb9b 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -64,13 +64,15 @@
#include <private/qobject_p.h>
#include "qqmlguard_p.h"
-#include "qqmlcompiler_p.h"
#include "qqmlcontext_p.h"
+#include "qqmlpropertycache_p.h"
#include <private/qv8engine_p.h>
#include <private/qflagpointer_p.h>
+#include <private/qv4object_p.h>
#include <private/qv4value_p.h>
+#include <private/qqmlpropertyvalueinterceptor_p.h>
QT_BEGIN_NAMESPACE
@@ -95,7 +97,7 @@ public:
QQmlInterceptorMetaObject(QObject *obj, QQmlPropertyCache *cache);
~QQmlInterceptorMetaObject();
- void registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor);
+ void registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor);
static QQmlInterceptorMetaObject *get(QObject *obj);
@@ -104,13 +106,22 @@ public:
// Used by auto-tests for inspection
QQmlPropertyCache *propertyCache() const { return cache; }
+ bool intercepts(QQmlPropertyIndex propertyIndex) const
+ {
+ for (auto it = interceptors; it; it = it->m_next) {
+ if (it->m_propertyIndex == propertyIndex)
+ return true;
+ }
+ return false;
+ }
+
protected:
int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) Q_DECL_OVERRIDE;
bool intercept(QMetaObject::Call c, int id, void **a);
public:
QObject *object;
- QQmlPropertyCache *cache;
+ QQmlRefPointer<QQmlPropertyCache> cache;
QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent;
QQmlPropertyValueInterceptor *interceptors;
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index e9644839d1..dd517374a5 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -502,7 +502,7 @@ ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx)
if (r->d()->d->children.isEmpty())
return Encode::null();
else
- return Node::create(scope.engine, r->d()->d->children.first());
+ return Node::create(scope.engine, r->d()->d->children.constFirst());
}
ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx)
@@ -515,7 +515,7 @@ ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx)
if (r->d()->d->children.isEmpty())
return Encode::null();
else
- return Node::create(scope.engine, r->d()->d->children.last());
+ return Node::create(scope.engine, r->d()->d->children.constLast());
}
ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx)
@@ -715,7 +715,7 @@ ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx)
Scoped<Node> r(scope, ctx->thisObject().as<Node>());
if (!r) return Encode::undefined();
- return Encode(r->d()->d->data.trimmed().isEmpty());
+ return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
}
ReturnedValue Text::method_wholeText(CallContext *ctx)
@@ -817,7 +817,8 @@ ReturnedValue Document::load(ExecutionEngine *v4, const QByteArray &data)
}
nodeStack.append(node);
- foreach (const QXmlStreamAttribute &a, reader.attributes()) {
+ const auto attributes = reader.attributes();
+ for (const QXmlStreamAttribute &a : attributes) {
NodeImpl *attr = new NodeImpl;
attr->document = document;
attr->type = NodeImpl::Attr;
@@ -1016,8 +1017,8 @@ public:
ReturnedValue abort(Object *thisObject, QQmlContextData *context);
void addHeader(const QString &, const QString &);
- QString header(const QString &name);
- QString headers();
+ QString header(const QString &name) const;
+ QString headers() const;
QString responseBody();
const QByteArray & rawResponseBody() const;
@@ -1144,36 +1145,37 @@ void QQmlXMLHttpRequest::addHeader(const QString &name, const QString &value)
}
}
-QString QQmlXMLHttpRequest::header(const QString &name)
+QString QQmlXMLHttpRequest::header(const QString &name) const
{
- QByteArray utfname = name.toLower().toUtf8();
-
- foreach (const HeaderPair &header, m_headersList) {
- if (header.first == utfname)
- return QString::fromUtf8(header.second);
+ if (!m_headersList.isEmpty()) {
+ const QByteArray utfname = name.toLower().toUtf8();
+ for (const HeaderPair &header : m_headersList) {
+ if (header.first == utfname)
+ return QString::fromUtf8(header.second);
+ }
}
return QString();
}
-QString QQmlXMLHttpRequest::headers()
+QString QQmlXMLHttpRequest::headers() const
{
QString ret;
- foreach (const HeaderPair &header, m_headersList) {
+ for (const HeaderPair &header : m_headersList) {
if (ret.length())
ret.append(QLatin1String("\r\n"));
- ret = ret % QString::fromUtf8(header.first) % QLatin1String(": ")
- % QString::fromUtf8(header.second);
+ ret += QString::fromUtf8(header.first) + QLatin1String(": ")
+ + QString::fromUtf8(header.second);
}
return ret;
}
void QQmlXMLHttpRequest::fillHeadersList()
{
- QList<QByteArray> headerList = m_network->rawHeaderList();
+ const QList<QByteArray> headerList = m_network->rawHeaderList();
m_headersList.clear();
- foreach (const QByteArray &header, headerList) {
+ for (const QByteArray &header : headerList) {
HeaderPair pair (header.toLower(), m_network->rawHeader(header));
if (pair.first == "set-cookie" ||
pair.first == "set-cookie2")
@@ -1235,7 +1237,8 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
} else if (m_method == QLatin1String("DELETE")) {
m_network = networkAccessManager()->deleteResource(request);
} else if ((m_method == QLatin1String("OPTIONS")) ||
- m_method == QLatin1String("PROPFIND")) {
+ m_method == QLatin1String("PROPFIND") ||
+ m_method == QLatin1String("PATCH")) {
QBuffer *buffer = new QBuffer;
buffer->setData(m_data);
buffer->open(QIODevice::ReadOnly);
@@ -1430,7 +1433,7 @@ void QQmlXMLHttpRequest::finished()
void QQmlXMLHttpRequest::readEncoding()
{
- foreach (const HeaderPair &header, m_headersList) {
+ for (const HeaderPair &header : qAsConst(m_headersList)) {
if (header.first == "content-type") {
int separatorIdx = header.second.indexOf(';');
if (separatorIdx == -1) {
@@ -1559,7 +1562,7 @@ void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *cont
QV4::ScopedCallData callData(scope);
callData->thisObject = Encode::undefined();
- callback->call(callData);
+ callback->call(scope, callData);
if (scope.engine->hasException) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
@@ -1620,22 +1623,23 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
c->proto->mark(e);
FunctionObject::markObjects(that, e);
}
- static ReturnedValue construct(const Managed *that, QV4::CallData *)
+ static void construct(const Managed *that, Scope &scope, QV4::CallData *)
{
- Scope scope(static_cast<const QQmlXMLHttpRequestCtor *>(that)->engine());
Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>());
- if (!ctor)
- return scope.engine->throwTypeError();
+ if (!ctor) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager());
Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocObject<QQmlXMLHttpRequestWrapper>(r));
ScopedObject proto(scope, ctor->d()->proto);
w->setPrototype(proto);
- return w.asReturnedValue();
+ scope.result = w.asReturnedValue();
}
- static ReturnedValue call(const Managed *, QV4::CallData *) {
- return Primitive::undefinedValue().asReturnedValue();
+ static void call(const Managed *, Scope &scope, QV4::CallData *) {
+ scope.result = Primitive::undefinedValue();
}
void setupProto();
@@ -1735,7 +1739,8 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
method != QLatin1String("POST") &&
method != QLatin1String("DELETE") &&
method != QLatin1String("OPTIONS") &&
- method != QLatin1String("PROPFIND"))
+ method != QLatin1String("PROPFIND") &&
+ method != QLatin1String("PATCH"))
V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
// Argument 1 - URL
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 54c29b4b8a..222b61ae49 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -42,6 +42,7 @@
#include <QtQml/qqmlcomponent.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
+#include <private/qqmlloggingcategory_p.h>
#include <private/qqmlstringconverters_p.h>
#include <private/qqmllocale_p.h>
#include <private/qv8engine_p.h>
@@ -76,6 +77,8 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qloggingcategory.h>
+#include <QDebug>
+
QT_BEGIN_NAMESPACE
using namespace QV4;
@@ -137,6 +140,7 @@ Heap::QtObject::QtObject(QQmlEngine *qmlEngine)
o->defineDefaultProperty(QStringLiteral("darker"), QV4::QtObject::method_darker);
o->defineDefaultProperty(QStringLiteral("tint"), QV4::QtObject::method_tint);
o->defineDefaultProperty(QStringLiteral("quit"), QV4::QtObject::method_quit);
+ o->defineDefaultProperty(QStringLiteral("exit"), QV4::QtObject::method_exit);
o->defineDefaultProperty(QStringLiteral("createQmlObject"), QV4::QtObject::method_createQmlObject);
o->defineDefaultProperty(QStringLiteral("createComponent"), QV4::QtObject::method_createComponent);
}
@@ -992,6 +996,8 @@ This function causes the QQmlEngine::quit() signal to be emitted.
Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit;
to quit a C++ application when this method is called, connect the
QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
+
+\sa exit()
*/
ReturnedValue QtObject::method_quit(CallContext *ctx)
{
@@ -1000,6 +1006,28 @@ ReturnedValue QtObject::method_quit(CallContext *ctx)
}
/*!
+ \qmlmethod Qt::exit(int retCode)
+
+ This function causes the QQmlEngine::exit(int) signal to be emitted.
+ Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit
+ the specified return code. To exit from the event loop with a specified return code when this
+ method is called, a C++ application can connect the QQmlEngine::exit(int) signal
+ to the QCoreApplication::exit(int) slot.
+
+ \sa quit()
+*/
+ReturnedValue QtObject::method_exit(CallContext *ctx)
+{
+ if (ctx->argc() != 1)
+ V4THROW_ERROR("Qt.exit(): Invalid arguments");
+
+ int retCode = ctx->args()[0].toNumber();
+
+ QQmlEnginePrivate::get(ctx->engine()->qmlEngine())->sendExit(retCode);
+ return QV4::Encode::undefined();
+}
+
+/*!
\qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath)
Returns a new object created from the given \a string of QML which will have the specified \a parent,
@@ -1032,7 +1060,9 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
struct Error {
static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) {
Scope scope(v4);
- QString errorstr = QLatin1String("Qt.createQmlObject(): failed to create object: ");
+ QString errorstr;
+ // '+=' reserves extra capacity. Follow-up appending will be probably free.
+ errorstr += QLatin1String("Qt.createQmlObject(): failed to create object: ");
QV4::ScopedArrayObject qmlerrors(scope, v4->newArrayObject());
QV4::ScopedObject qmlerror(scope);
@@ -1274,8 +1304,8 @@ ReturnedValue QtObject::method_locale(CallContext *ctx)
Heap::QQmlBindingFunction::QQmlBindingFunction(const QV4::FunctionObject *originalFunction)
: QV4::Heap::FunctionObject(originalFunction->scope(), originalFunction->name())
- , originalFunction(originalFunction->d())
{
+ this->originalFunction = originalFunction->d();
}
void QQmlBindingFunction::initBindingLocation()
@@ -1285,11 +1315,10 @@ void QQmlBindingFunction::initBindingLocation()
d()->bindingLocation.line = frame.line;
}
-ReturnedValue QQmlBindingFunction::call(const Managed *that, CallData *callData)
+void QQmlBindingFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
- Scope scope(static_cast<const QQmlBindingFunction*>(that)->engine());
ScopedFunctionObject function(scope, static_cast<const QQmlBindingFunction*>(that)->d()->originalFunction);
- return function->call(callData);
+ function->call(scope, callData);
}
void QQmlBindingFunction::markObjects(Heap::Base *that, ExecutionEngine *e)
@@ -1465,28 +1494,42 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *ctx,
bool printStack = false)
{
+ QLoggingCategory *loggingCategory = 0;
QString result;
QV4::ExecutionEngine *v4 = ctx->d()->engine;
- for (int i = 0; i < ctx->argc(); ++i) {
- if (i != 0)
+ int start = 0;
+ if (ctx->argc() > 0) {
+ if (const QObjectWrapper* wrapper = ctx->args()[0].as<QObjectWrapper>()) {
+ if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) {
+ if (category->category())
+ loggingCategory = category->category();
+ else
+ V4THROW_ERROR("A QmlLoggingCatgory was provided without a valid name");
+ start = 1;
+ }
+ }
+ }
+
+
+ for (int i = start; i < ctx->argc(); ++i) {
+ if (i != start)
result.append(QLatin1Char(' '));
if (ctx->args()[i].as<ArrayObject>())
- result.append(QLatin1Char('[') + ctx->args()[i].toQStringNoThrow() + QLatin1Char(']'));
+ result += QLatin1Char('[') + ctx->args()[i].toQStringNoThrow() + QLatin1Char(']');
else
result.append(ctx->args()[i].toQStringNoThrow());
}
- if (printStack) {
- result.append(QLatin1Char('\n'));
- result.append(jsStack(v4));
- }
+ if (printStack)
+ result += QLatin1Char('\n') + jsStack(v4);
static QLoggingCategory qmlLoggingCategory("qml");
static QLoggingCategory jsLoggingCategory("js");
- QLoggingCategory *loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory;
+ if (!loggingCategory)
+ loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory;
QV4::StackFrame frame = v4->currentStackFrame();
const QByteArray baSource = frame.source.toUtf8();
const QByteArray baFunction = frame.function.toUtf8();
@@ -2001,18 +2044,19 @@ ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx)
/*!
\qmlmethod Qt::callLater(function)
\qmlmethod Qt::callLater(function, argument1, argument2, ...)
+\since 5.8
Use this function to eliminate redundant calls to a function or signal.
-The function passed as the first argument to \l{QML:Qt::callLater()}{Qt.callLater()}
+The function passed as the first argument to Qt.callLater()
will be called later, once the QML engine returns to the event loop.
When this function is called multiple times in quick succession with the
same function as its first argument, that function will be called only once.
For example:
-\snippet doc/src/snippets/qml/qtLater.qml 0
+\snippet qml/qtLater.qml 0
-Any additional arguments passed to \l{QML:Qt::callLater()}{Qt.callLater()} will
+Any additional arguments passed to Qt.callLater() will
be passed on to the function invoked. Note that if redundant calls
are eliminated, then only the last set of arguments will be passed to the
function.
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index 5404ab3616..8c0759679a 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -122,6 +122,7 @@ struct QtObject : Object
static ReturnedValue method_btoa(CallContext *ctx);
static ReturnedValue method_atob(CallContext *ctx);
static ReturnedValue method_quit(CallContext *ctx);
+ static ReturnedValue method_exit(CallContext *ctx);
static ReturnedValue method_resolvedUrl(CallContext *ctx);
static ReturnedValue method_createQmlObject(CallContext *ctx);
static ReturnedValue method_createComponent(CallContext *ctx);
@@ -188,7 +189,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject
void initBindingLocation(); // from caller stack trace
- static ReturnedValue call(const Managed *that, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index e08ff3b979..f15020f6c9 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -160,10 +160,9 @@ QV8Engine::~QV8Engine()
qDeleteAll(m_extensionData);
m_extensionData.clear();
-#if !defined(QT_NO_XMLSTREAMREADER) && defined(QT_NO_NETWORK)
qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData);
m_xmlHttpRequestData = 0;
-#endif
+
delete m_listModelData;
m_listModelData = 0;
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 3102da3f20..a545fe57ca 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -289,6 +289,7 @@ void QQmlBind::setValue(const QVariant &v)
/*!
\qmlproperty bool QtQml::Binding::delayed
+ \since 5.8
This property holds whether the binding should be delayed.
diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h
index 77939a40bc..c9dd14b58a 100644
--- a/src/qml/types/qqmlbind_p.h
+++ b/src/qml/types/qqmlbind_p.h
@@ -90,9 +90,9 @@ public:
void setDelayed(bool);
protected:
- virtual void setTarget(const QQmlProperty &);
- virtual void classBegin();
- virtual void componentComplete();
+ void setTarget(const QQmlProperty &) override;
+ void classBegin() override;
+ void componentComplete() override;
private:
void prepareEval();
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 6f7f13823e..1e9e0149dc 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -44,7 +44,6 @@
#include <private/qqmlboundsignal_p.h>
#include <qqmlcontext.h>
#include <private/qqmlcontext_p.h>
-#include <private/qqmlcompiler_p.h>
#include <qqmlinfo.h>
#include <QtCore/qdebug.h>
@@ -205,7 +204,7 @@ void QQmlConnections::setEnabled(bool enabled)
d->enabled = enabled;
- foreach (QQmlBoundSignal *s, d->boundsignals)
+ for (QQmlBoundSignal *s : qAsConst(d->boundsignals))
s->setEnabled(d->enabled);
emit enabledChanged();
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index d454affba8..580b6522de 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -91,15 +91,15 @@ Q_SIGNALS:
private:
void connectSignals();
- void classBegin();
- void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
};
class QQmlConnectionsParser : public QQmlCustomParser
{
public:
- virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
- virtual void applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
+ void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) override;
+ void applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
};
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index aee9fcd0a2..be4258cdfd 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -48,7 +48,6 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlincubator_p.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
@@ -92,17 +91,17 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
return scope->engine()->memoryManager->allocObject<DelegateModelGroupFunction>(scope, flag, code);
}
- static QV4::ReturnedValue call(const QV4::Managed *that, QV4::CallData *callData)
+ static void call(const QV4::Managed *that, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::ExecutionEngine *v4 = static_cast<const DelegateModelGroupFunction *>(that)->engine();
- QV4::Scope scope(v4);
QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<const DelegateModelGroupFunction *>(that));
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject);
- if (!o)
- return v4->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ if (!o) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return;
+ }
QV4::ScopedValue v(scope, callData->argument(0));
- return f->d()->code(o->d()->item, f->d()->flag, v);
+ scope.result = f->d()->code(o->d()->item, f->d()->flag, v);
}
};
@@ -1122,7 +1121,7 @@ void QQmlDelegateModelPrivate::itemsChanged(const QVector<Compositor::Change> &c
QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
- foreach (const Compositor::Change &change, changes) {
+ for (const Compositor::Change &change : changes) {
for (int i = 1; i < m_groupCount; ++i) {
if (change.inGroup(i)) {
translatedChanges[i].append(QQmlChangeSet::Change(change.index[i], change.count));
@@ -1171,7 +1170,7 @@ void QQmlDelegateModelPrivate::itemsInserted(
for (int i = 1; i < m_groupCount; ++i)
inserted[i] = 0;
- foreach (const Compositor::Insert &insert, inserts) {
+ for (const Compositor::Insert &insert : inserts) {
for (; cacheIndex < insert.cacheIndex; ++cacheIndex)
incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
@@ -1263,7 +1262,7 @@ void QQmlDelegateModelPrivate::itemsRemoved(
for (int i = 1; i < m_groupCount; ++i)
removed[i] = 0;
- foreach (const Compositor::Remove &remove, removes) {
+ for (const Compositor::Remove &remove : removes) {
for (; cacheIndex < remove.cacheIndex; ++cacheIndex)
incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
@@ -1314,9 +1313,23 @@ void QQmlDelegateModelPrivate::itemsRemoved(
}
} else {
if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- for (int i = 1; i < m_groupCount; ++i) {
- if (remove.inGroup(i))
- incubationTask->index[i] = remove.index[i];
+ if (!cacheItem->isObjectReferenced()) {
+ releaseIncubator(cacheItem->incubationTask);
+ cacheItem->incubationTask = 0;
+ if (cacheItem->object) {
+ QObject *object = cacheItem->object;
+ cacheItem->destroyObject();
+ if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
+ emitDestroyingPackage(package);
+ else
+ emitDestroyingItem(object);
+ }
+ cacheItem->scriptRef -= 1;
+ } else {
+ for (int i = 1; i < m_groupCount; ++i) {
+ if (remove.inGroup(i))
+ incubationTask->index[i] = remove.index[i];
+ }
}
}
if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
@@ -1620,7 +1633,7 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const
cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
// Must be before the new object is inserted into the cache or its indexes will be adjusted too.
- itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
+ itemsInserted(QVector<Compositor::Insert>(1, Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag)));
before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
m_cache.insert(before.cacheIndex, cacheItem);
@@ -1655,7 +1668,7 @@ void QQmlDelegateModelItemMetaType::initializeMetaObject()
int notifierId = 0;
for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
- QString propertyName = QStringLiteral("in") + groupNames.at(i);
+ QString propertyName = QLatin1String("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
QMetaPropertyBuilder propertyBuilder = builder.addProperty(
@@ -1663,7 +1676,7 @@ void QQmlDelegateModelItemMetaType::initializeMetaObject()
propertyBuilder.setWritable(true);
}
for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
- const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
+ const QString propertyName = groupNames.at(i) + QLatin1String("Index");
builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
QMetaPropertyBuilder propertyBuilder = builder.addProperty(
propertyName.toUtf8(), "int", notifierId);
@@ -1711,7 +1724,7 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
for (int i = 2; i < groupNames.count(); ++i) {
- QString propertyName = QStringLiteral("in") + groupNames.at(i);
+ QString propertyName = QLatin1String("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4->newString(propertyName);
p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_member)));
@@ -1719,7 +1732,7 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
for (int i = 2; i < groupNames.count(); ++i) {
- const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
+ const QString propertyName = groupNames.at(i) + QLatin1String("Index");
s = v4->newString(propertyName);
p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_index)));
p->setSetter(0);
@@ -1731,7 +1744,7 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
int QQmlDelegateModelItemMetaType::parseGroups(const QStringList &groups) const
{
int groupFlags = 0;
- foreach (const QString &groupName, groups) {
+ for (const QString &groupName : groups) {
int index = groupNames.indexOf(groupName);
if (index != -1)
groupFlags |= 2 << index;
@@ -1919,9 +1932,10 @@ void QQmlDelegateModelItem::incubateObject(
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
- incubatorPriv->compiledData = componentPriv->cc;
- incubatorPriv->compiledData->addref();
- incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->cc, componentPriv->creationContext));
+ incubatorPriv->compilationUnit = componentPriv->compilationUnit;
+ incubatorPriv->compilationUnit->addref();
+ incubatorPriv->enginePriv = enginePriv;
+ incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
incubatorPriv->subComponentToCreate = componentPriv->start;
enginePriv->incubate(*incubationTask, forContext);
@@ -2708,12 +2722,12 @@ void QQmlDelegateModelGroup::resolve(QQmlV4Function *args)
from += 1;
model->itemsMoved(
- QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
- QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
+ QVector<Compositor::Remove>(1, Compositor::Remove(fromIt, 1, unresolvedFlags, 0)),
+ QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, unresolvedFlags, 0)));
model->itemsInserted(
- QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
+ QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag)));
toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
- model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
+ model->itemsRemoved(QVector<Compositor::Remove>(1, Compositor::Remove(toIt, 1, resolvedFlags)));
model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
index 2986ec7ce5..186144d107 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qml/types/qqmldelegatemodel_p.h
@@ -90,10 +90,10 @@ class Q_QML_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public
public:
QQmlDelegateModel();
QQmlDelegateModel(QQmlContext *, QObject *parent=0);
- virtual ~QQmlDelegateModel();
+ ~QQmlDelegateModel();
- void classBegin();
- void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
QVariant model() const;
void setModel(const QVariant &);
@@ -107,15 +107,15 @@ public:
Q_INVOKABLE QVariant modelIndex(int idx) const;
Q_INVOKABLE QVariant parentModelIndex() const;
- int count() const;
- bool isValid() const { return delegate() != 0; }
- QObject *object(int index, bool asynchronous=false);
- ReleaseFlags release(QObject *object);
- void cancel(int index);
- virtual QString stringValue(int index, const QString &role);
- virtual void setWatchedRoles(const QList<QByteArray> &roles);
+ int count() const override;
+ bool isValid() const override { return delegate() != 0; }
+ QObject *object(int index, bool asynchronous = false) override;
+ ReleaseFlags release(QObject *object) override;
+ void cancel(int index) override;
+ QString stringValue(int index, const QString &role) override;
+ void setWatchedRoles(const QList<QByteArray> &roles) override;
- int indexOf(QObject *object, QObject *objectContext) const;
+ int indexOf(QObject *object, QObject *objectContext) const override;
QString filterGroup() const;
void setFilterGroup(const QString &group);
@@ -126,7 +126,7 @@ public:
QQmlListProperty<QQmlDelegateModelGroup> groups();
QObject *parts();
- bool event(QEvent *);
+ bool event(QEvent *) override;
static QQmlDelegateModelAttached *qmlAttachedProperties(QObject *obj);
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index bf9fd99f19..7031cf779c 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -190,8 +190,8 @@ public:
, incubating(0)
, vdm(l) {}
- virtual void statusChanged(Status);
- virtual void setInitialState(QObject *);
+ void statusChanged(Status) override;
+ void setInitialState(QObject *) override;
QQmlDelegateModelItem *incubating;
QQmlDelegateModelPrivate *vdm;
@@ -353,21 +353,21 @@ public:
void updateFilterGroup();
void updateFilterGroup(Compositor::Group group, const QQmlChangeSet &changeSet);
- int count() const;
- bool isValid() const;
- QObject *object(int index, bool asynchronous=false);
- ReleaseFlags release(QObject *item);
- QString stringValue(int index, const QString &role);
+ int count() const override;
+ bool isValid() const override;
+ QObject *object(int index, bool asynchronous = false) override;
+ ReleaseFlags release(QObject *item) override;
+ QString stringValue(int index, const QString &role) override;
QList<QByteArray> watchedRoles() const { return m_watchedRoles; }
- void setWatchedRoles(const QList<QByteArray> &roles);
+ void setWatchedRoles(const QList<QByteArray> &roles) override;
- int indexOf(QObject *item, QObject *objectContext) const;
+ int indexOf(QObject *item, QObject *objectContext) const override;
- void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset);
+ void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
- void createdPackage(int index, QQuickPackage *package);
- void initPackage(int index, QQuickPackage *package);
- void destroyingPackage(QQuickPackage *package);
+ void createdPackage(int index, QQuickPackage *package) override;
+ void initPackage(int index, QQuickPackage *package) override;
+ void destroyingPackage(QQuickPackage *package) override;
Q_SIGNALS:
void filterGroupChanged();
@@ -390,8 +390,8 @@ public:
QQmlDelegateModelPartsMetaObject(QObject *parent)
: QQmlOpenMetaObject(parent) {}
- virtual void propertyCreated(int, QMetaPropertyBuilder &);
- virtual QVariant initialValue(int);
+ void propertyCreated(int, QMetaPropertyBuilder &) override;
+ QVariant initialValue(int) override;
};
class QQmlDelegateModelParts : public QObject
@@ -411,8 +411,8 @@ public:
QQmlDelegateModelItemMetaType *metaType, QMetaObject *metaObject);
~QQmlDelegateModelAttachedMetaObject();
- void objectDestroyed(QObject *);
- int metaCall(QObject *, QMetaObject::Call, int _id, void **);
+ void objectDestroyed(QObject *) override;
+ int metaCall(QObject *, QMetaObject::Call, int _id, void **) override;
private:
QQmlDelegateModelItemMetaType * const metaType;
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp
index 0cec39790d..2de5875deb 100644
--- a/src/qml/types/qqmlinstantiator.cpp
+++ b/src/qml/types/qqmlinstantiator.cpp
@@ -155,7 +155,8 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo
int difference = 0;
QHash<int, QVector<QPointer<QObject> > > moved;
- foreach (const QQmlChangeSet::Change &remove, changeSet.removes()) {
+ const QVector<QQmlChangeSet::Change> &removes = changeSet.removes();
+ for (const QQmlChangeSet::Change &remove : removes) {
int index = qMin(remove.index, objects.count());
int count = qMin(remove.index + remove.count, objects.count()) - index;
if (remove.isMove()) {
@@ -174,7 +175,8 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo
difference -= remove.count;
}
- foreach (const QQmlChangeSet::Change &insert, changeSet.inserts()) {
+ const QVector<QQmlChangeSet::Change> &inserts = changeSet.inserts();
+ for (const QQmlChangeSet::Change &insert : inserts) {
int index = qMin(insert.index, objects.count());
if (insert.isMove()) {
QVector<QPointer<QObject> > movedObjects = moved.value(insert.moveId);
diff --git a/src/qml/types/qqmlinstantiator_p.h b/src/qml/types/qqmlinstantiator_p.h
index dff69ee6b3..ee18daa48c 100644
--- a/src/qml/types/qqmlinstantiator_p.h
+++ b/src/qml/types/qqmlinstantiator_p.h
@@ -72,7 +72,7 @@ class Q_AUTOTEST_EXPORT QQmlInstantiator : public QObject, public QQmlParserStat
public:
QQmlInstantiator(QObject *parent = 0);
- virtual ~QQmlInstantiator();
+ ~QQmlInstantiator();
bool isActive() const;
void setActive(bool newVal);
@@ -92,8 +92,8 @@ public:
Q_INVOKABLE QObject *objectAt(int index) const;
- void classBegin();
- void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
Q_SIGNALS:
void modelChanged();
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 69066d1c69..c27c6ac26d 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -42,7 +42,6 @@
#include <private/qqmlopenmetaobject_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmljsengine_p.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlengine_p.h>
@@ -399,6 +398,8 @@ void ListModel::updateCacheIndices()
QVariant ListModel::getProperty(int elementIndex, int roleIndex, const QQmlListModel *owner, QV4::ExecutionEngine *eng)
{
+ if (roleIndex >= m_layout->roleCount())
+ return QVariant();
ListElement *e = elements[elementIndex];
const ListLayout::Role &r = m_layout->getExistingRole(roleIndex);
return e->getProperty(r, owner, eng);
@@ -599,11 +600,8 @@ int ListModel::setOrCreateProperty(int elementIndex, const QString &key, const Q
ModelNodeMetaObject *cache = e->objectCache();
- if (roleIndex != -1 && cache) {
- QVector<int> roles;
- roles << roleIndex;
- cache->updateValues(roles);
- }
+ if (roleIndex != -1 && cache)
+ cache->updateValues(QVector<int>(1, roleIndex));
}
}
@@ -1301,11 +1299,8 @@ void ModelNodeMetaObject::propertyWritten(int index)
QV4::ScopedValue v(scope, scope.engine->fromVariant(value));
int roleIndex = m_model->m_listModel->setExistingProperty(m_elementIndex, propName, v, scope.engine);
- if (roleIndex != -1) {
- QVector<int> roles;
- roles << roleIndex;
- m_model->emitItemsChanged(m_elementIndex, 1, roles);
- }
+ if (roleIndex != -1)
+ m_model->emitItemsChanged(m_elementIndex, 1, QVector<int>(1, roleIndex));
}
namespace QV4 {
@@ -1318,11 +1313,8 @@ void ModelObject::put(Managed *m, String *name, const Value &value)
const int elementIndex = that->d()->m_elementIndex;
const QString propName = name->toQString();
int roleIndex = that->d()->m_model->m_listModel->setExistingProperty(elementIndex, propName, value, eng);
- if (roleIndex != -1) {
- QVector<int> roles;
- roles << roleIndex;
- that->d()->m_model->emitItemsChanged(elementIndex, 1, roles);
- }
+ if (roleIndex != -1)
+ that->d()->m_model->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
ModelNodeMetaObject *mo = ModelNodeMetaObject::get(that->object());
if (mo->initialized())
@@ -1504,14 +1496,10 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
}
int elementIndex = parentModel->m_modelObjects.indexOf(m_owner);
- int roleIndex = parentModel->m_roles.indexOf(QString::fromLatin1(name(index).constData()));
-
- if (elementIndex != -1 && roleIndex != -1) {
-
- QVector<int> roles;
- roles << roleIndex;
-
- parentModel->emitItemsChanged(elementIndex, 1, roles);
+ if (elementIndex != -1) {
+ int roleIndex = parentModel->m_roles.indexOf(QString::fromLatin1(name(index).constData()));
+ if (roleIndex != -1)
+ parentModel->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
}
}
@@ -1880,14 +1868,14 @@ bool QQmlListModel::setData(const QModelIndex &index, const QVariant &value, int
if (m_dynamicRoles) {
const QByteArray property = m_roles.at(role).toUtf8();
if (m_modelObjects[row]->setValue(property, value)) {
- emitItemsChanged(row, 1, QVector<int>() << role);
+ emitItemsChanged(row, 1, QVector<int>(1, role));
return true;
}
} else {
const ListLayout::Role &r = m_listModel->getExistingRole(role);
const int roleIndex = m_listModel->setOrCreateProperty(row, r.name, value);
if (roleIndex != -1) {
- emitItemsChanged(row, 1, QVector<int>() << role);
+ emitItemsChanged(row, 1, QVector<int>(1, role));
return true;
}
}
@@ -2355,20 +2343,12 @@ void QQmlListModel::setProperty(int index, const QString& property, const QVaria
roleIndex = m_roles.count();
m_roles.append(property);
}
- if (m_modelObjects[index]->setValue(property.toUtf8(), value)) {
- QVector<int> roles;
- roles << roleIndex;
- emitItemsChanged(index, 1, roles);
- }
+ if (m_modelObjects[index]->setValue(property.toUtf8(), value))
+ emitItemsChanged(index, 1, QVector<int>(1, roleIndex));
} else {
int roleIndex = m_listModel->setOrCreateProperty(index, property, value);
- if (roleIndex != -1) {
-
- QVector<int> roles;
- roles << roleIndex;
-
- emitItemsChanged(index, 1, roles);
- }
+ if (roleIndex != -1)
+ emitItemsChanged(index, 1, QVector<int>(1, roleIndex));
}
}
@@ -2497,7 +2477,7 @@ void QQmlListModelParser::verifyBindings(const QV4::CompiledData::Unit *qmlUnit,
{
listElementTypeName = QString(); // unknown
- foreach (const QV4::CompiledData::Binding *binding, bindings) {
+ for (const QV4::CompiledData::Binding *binding : bindings) {
QString propName = qmlUnit->stringAt(binding->propertyNameIndex);
if (!propName.isEmpty()) { // isn't default property
error(binding, QQmlListModel::tr("ListModel: undefined property '%1'").arg(propName));
@@ -2518,7 +2498,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, QV4::CompiledData::Compila
bool setRoles = false;
- foreach (const QV4::CompiledData::Binding *binding, bindings) {
+ for (const QV4::CompiledData::Binding *binding : bindings) {
if (binding->type != QV4::CompiledData::Binding::Type_Object)
continue;
setRoles |= applyProperty(qmlUnit, binding, rv->m_listModel, /*outter element index*/-1);
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index 220b0e54b5..29b392f71e 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -85,11 +85,11 @@ public:
QQmlListModel(QObject *parent=0);
~QQmlListModel();
- QModelIndex index(int row, int column, const QModelIndex &parent) const;
- int rowCount(const QModelIndex &parent) const;
- QVariant data(const QModelIndex &index, int role) const;
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
- QHash<int,QByteArray> roleNames() const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const override;
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+ QHash<int,QByteArray> roleNames() const override;
QVariant data(int index, int role) const;
int count() const;
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index d3ff032ae9..f99b717c40 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -71,8 +71,8 @@ public:
bool m_enabled;
protected:
- void propertyWrite(int index);
- void propertyWritten(int index);
+ void propertyWrite(int index) override;
+ void propertyWritten(int index) override;
private:
DynamicRoleModelNode *m_owner;
@@ -88,7 +88,7 @@ public:
void updateValues(const QVariantMap &object, QVector<int> &roles);
- QVariant getValue(const QString &name)
+ QVariant getValue(const QString &name) const
{
return m_meta->value(name.toUtf8());
}
@@ -124,7 +124,7 @@ public:
ModelNodeMetaObject(QObject *object, QQmlListModel *model, int elementIndex);
~ModelNodeMetaObject();
- virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *object);
+ QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *object) override;
static ModelNodeMetaObject *get(QObject *obj);
@@ -138,7 +138,7 @@ public:
bool initialized() const { return m_initialized; }
protected:
- void propertyWritten(int index);
+ void propertyWritten(int index) override;
private:
using QQmlOpenMetaObject::setValue;
diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h
index 1a891c0f25..5a39651bf7 100644
--- a/src/qml/types/qqmllistmodelworkeragent_p.h
+++ b/src/qml/types/qqmllistmodelworkeragent_p.h
@@ -108,7 +108,7 @@ public:
void modelDestroyed();
protected:
- virtual bool event(QEvent *);
+ bool event(QEvent *) override;
private:
friend class QQuickWorkerScriptEnginePrivate;
diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp
index 8c8005fb69..695043b592 100644
--- a/src/qml/types/qqmlobjectmodel.cpp
+++ b/src/qml/types/qqmlobjectmodel.cpp
@@ -154,7 +154,7 @@ public:
void clear() {
Q_Q(QQmlObjectModel);
- foreach (const Item &child, children)
+ for (const Item &child : qAsConst(children))
emit q->destroyingItem(child.item);
remove(0, children.count());
}
diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h
index 97a56344d4..fc4c03874f 100644
--- a/src/qml/types/qqmlobjectmodel_p.h
+++ b/src/qml/types/qqmlobjectmodel_p.h
@@ -109,16 +109,16 @@ class Q_QML_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel
public:
QQmlObjectModel(QObject *parent=0);
- virtual ~QQmlObjectModel() {}
+ ~QQmlObjectModel() {}
- virtual int count() const;
- virtual bool isValid() const;
- virtual QObject *object(int index, bool asynchronous=false);
- virtual ReleaseFlags release(QObject *object);
- virtual QString stringValue(int index, const QString &role);
- virtual void setWatchedRoles(const QList<QByteArray> &) {}
+ int count() const override;
+ bool isValid() const override;
+ QObject *object(int index, bool asynchronous = false) override;
+ ReleaseFlags release(QObject *object) override;
+ QString stringValue(int index, const QString &role) override;
+ void setWatchedRoles(const QList<QByteArray> &) override {}
- virtual int indexOf(QObject *object, QObject *objectContext) const;
+ int indexOf(QObject *object, QObject *objectContext) const override;
QQmlListProperty<QObject> children();
diff --git a/src/qml/types/qqmltimer.cpp b/src/qml/types/qqmltimer.cpp
index 889274b43e..7efdac4c22 100644
--- a/src/qml/types/qqmltimer.cpp
+++ b/src/qml/types/qqmltimer.cpp
@@ -60,8 +60,8 @@ public:
: interval(1000), running(false), repeating(false), triggeredOnStart(false)
, classBegun(false), componentComplete(false), firstTick(true), awaitingTick(false) {}
- virtual void animationFinished(QAbstractAnimationJob *);
- virtual void animationCurrentLoopChanged(QAbstractAnimationJob *) { maybeTick(); }
+ void animationFinished(QAbstractAnimationJob *) override;
+ void animationCurrentLoopChanged(QAbstractAnimationJob *) override { maybeTick(); }
void maybeTick() {
Q_Q(QQmlTimer);
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index 7ea2f098bf..7739dad2a6 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -87,10 +87,10 @@ public:
void setTriggeredOnStart(bool triggeredOnStart);
protected:
- void classBegin();
- void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
- bool event(QEvent *);
+ bool event(QEvent *) override;
public Q_SLOTS:
void start();
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index bc15b2fd9b..b77675df0e 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -145,7 +145,7 @@ public:
void init();
#ifndef QT_NO_NETWORK
- virtual QNetworkAccessManager *networkAccessManager();
+ QNetworkAccessManager *networkAccessManager() override;
#endif
QQuickWorkerScriptEnginePrivate *p;
@@ -192,7 +192,7 @@ signals:
void stopThread();
protected:
- virtual bool event(QEvent *);
+ bool event(QEvent *) override;
private:
void processMessage(int, const QByteArray &);
@@ -251,7 +251,8 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
QV4::ScopedCallData callData(scope, 1);
callData->args[0] = function;
callData->thisObject = global();
- createsend.set(scope.engine, createsendconstructor->call(callData));
+ createsendconstructor->call(scope, callData);
+ createsend.set(scope.engine, scope.result.asReturnedValue());
}
// Requires handle and context scope
@@ -264,14 +265,13 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, createsend.value());
- QV4::ScopedValue v(scope);
QV4::ScopedCallData callData(scope, 1);
callData->args[0] = QV4::Primitive::fromInt32(id);
callData->thisObject = global();
- v = f->call(callData);
+ f->call(scope, callData);
if (scope.hasException())
- v = scope.engine->catchException();
- return v->asReturnedValue();
+ scope.result = scope.engine->catchException();
+ return scope.result.asReturnedValue();
}
#ifndef QT_NO_NETWORK
@@ -380,7 +380,7 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d
callData->thisObject = workerEngine->global();
callData->args[0] = qmlContext->d()->qml; // ###
callData->args[1] = value;
- f->call(callData);
+ f->call(scope, callData);
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
reportScriptException(script, error);
diff --git a/src/qml/types/qquickworkerscript_p.h b/src/qml/types/qquickworkerscript_p.h
index de6f3dc324..dce3acc3e1 100644
--- a/src/qml/types/qquickworkerscript_p.h
+++ b/src/qml/types/qquickworkerscript_p.h
@@ -68,7 +68,7 @@ class QQuickWorkerScriptEngine : public QThread
Q_OBJECT
public:
QQuickWorkerScriptEngine(QQmlEngine *parent = 0);
- virtual ~QQuickWorkerScriptEngine();
+ ~QQuickWorkerScriptEngine();
int registerWorkerScript(QQuickWorkerScript *);
void removeWorkerScript(int);
@@ -76,7 +76,7 @@ public:
void sendMessage(int, const QByteArray &);
protected:
- virtual void run();
+ void run() override;
private:
QQuickWorkerScriptEnginePrivate *d;
@@ -92,7 +92,7 @@ class Q_AUTOTEST_EXPORT QQuickWorkerScript : public QObject, public QQmlParserSt
Q_INTERFACES(QQmlParserStatus)
public:
QQuickWorkerScript(QObject *parent = 0);
- virtual ~QQuickWorkerScript();
+ ~QQuickWorkerScript();
QUrl source() const;
void setSource(const QUrl &);
@@ -105,9 +105,9 @@ Q_SIGNALS:
void message(const QQmlV4Handle &messageObject);
protected:
- virtual void classBegin();
- virtual void componentComplete();
- virtual bool event(QEvent *);
+ void classBegin() override;
+ void componentComplete() override;
+ bool event(QEvent *) override;
private:
QQuickWorkerScriptEngine *engine();
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index 5fc2444b7c..b9d312d41f 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -146,7 +146,7 @@ public:
bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
QList<int> roleIds;
- foreach (const QByteArray &r, watchedRoles) {
+ for (const QByteArray &r : watchedRoles) {
QHash<QByteArray, int>::const_iterator it = roleNames.find(r);
if (it != roleNames.end())
roleIds << it.value();
@@ -190,7 +190,7 @@ public:
VDMModelDelegateDataType *dataType = const_cast<VDMModelDelegateDataType *>(this);
dataType->watchedRoleIds.clear();
- foreach (const QByteArray &oldRole, oldRoles)
+ for (const QByteArray &oldRole : oldRoles)
dataType->watchedRoles.removeOne(oldRole);
dataType->watchedRoles += newRoles;
}
diff --git a/src/qml/util/qqmlchangeset.cpp b/src/qml/util/qqmlchangeset.cpp
index 088ac5e8c0..79e3332331 100644
--- a/src/qml/util/qqmlchangeset.cpp
+++ b/src/qml/util/qqmlchangeset.cpp
@@ -558,9 +558,15 @@ void QQmlChangeSet::change(QVector<Change> *changes)
QDebug operator <<(QDebug debug, const QQmlChangeSet &set)
{
debug.nospace() << "QQmlChangeSet(";
- foreach (const QQmlChangeSet::Change &remove, set.removes()) debug << remove;
- foreach (const QQmlChangeSet::Change &insert, set.inserts()) debug << insert;
- foreach (const QQmlChangeSet::Change &change, set.changes()) debug << change;
+ const QVector<QQmlChangeSet::Change> &removes = set.removes();
+ for (const QQmlChangeSet::Change &remove : removes)
+ debug << remove;
+ const QVector<QQmlChangeSet::Change> &inserts = set.inserts();
+ for (const QQmlChangeSet::Change &insert : inserts)
+ debug << insert;
+ const QVector<QQmlChangeSet::Change> &changes = set.changes();
+ for (const QQmlChangeSet::Change &change : changes)
+ debug << change;
return debug.nospace() << ')';
}
diff --git a/src/qml/util/qqmllistcompositor.cpp b/src/qml/util/qqmllistcompositor.cpp
index 4cfdf77b2a..05a4eaac39 100644
--- a/src/qml/util/qqmllistcompositor.cpp
+++ b/src/qml/util/qqmllistcompositor.cpp
@@ -964,7 +964,7 @@ void QQmlListCompositor::listItemsInserted(
it.incrementIndexes(it->count);
continue;
}
- foreach (const QQmlChangeSet::Change &insertion, insertions) {
+ for (const QQmlChangeSet::Change &insertion : insertions) {
int offset = insertion.index - it->index;
if ((offset > 0 && offset < it->count)
|| (offset == 0 && it->prepend())
@@ -1301,7 +1301,7 @@ void QQmlListCompositor::listItemsChanged(
} else if (!it->inGroup()) {
continue;
}
- foreach (const QQmlChangeSet::Change &change, changes) {
+ for (const QQmlChangeSet::Change &change : changes) {
const int offset = change.index - it->index;
if (offset + change.count > 0 && offset < it->count) {
const int changeOffset = qMax(0, offset);
diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp
index 69d3fc25e1..6e6554f2c3 100644
--- a/src/qml/util/qqmlpropertymap.cpp
+++ b/src/qml/util/qqmlpropertymap.cpp
@@ -54,10 +54,10 @@ public:
QQmlPropertyMapMetaObject(QQmlPropertyMap *obj, QQmlPropertyMapPrivate *objPriv, const QMetaObject *staticMetaObject);
protected:
- virtual QVariant propertyWriteValue(int, const QVariant &);
- virtual void propertyWritten(int index);
- virtual void propertyCreated(int, QMetaPropertyBuilder &);
- virtual int createProperty(const char *, const char *);
+ QVariant propertyWriteValue(int, const QVariant &) override;
+ void propertyWritten(int index) override;
+ void propertyCreated(int, QMetaPropertyBuilder &) override;
+ int createProperty(const char *, const char *) override;
const QString &propertyName(int index);
diff --git a/src/qmldebug/qqmldebugconnection.cpp b/src/qmldebug/qqmldebugconnection.cpp
index 35a540bff8..b5db71557f 100644
--- a/src/qmldebug/qqmldebugconnection.cpp
+++ b/src/qmldebug/qqmldebugconnection.cpp
@@ -77,7 +77,7 @@ public:
QStringList removedPlugins;
void advertisePlugins();
- void connectDeviceSignals();
+ void createProtocol();
void flush();
};
@@ -159,7 +159,7 @@ void QQmlDebugConnection::protocolReadyRead()
if (!validHello) {
qWarning("QQmlDebugConnection: Invalid hello message");
- QObject::disconnect(d->protocol, SIGNAL(protocolReadyRead()), this, SLOT(protocolReadyRead()));
+ close();
return;
}
d->gotHello = true;
@@ -254,7 +254,7 @@ QQmlDebugConnection::QQmlDebugConnection(QObject *parent) :
QObject(*(new QQmlDebugConnectionPrivate), parent)
{
Q_D(QQmlDebugConnection);
- connect(&d->handshakeTimer, SIGNAL(timeout()), this, SLOT(handshakeTimeout()));
+ connect(&d->handshakeTimer, &QTimer::timeout, this, &QQmlDebugConnection::handshakeTimeout);
}
QQmlDebugConnection::~QQmlDebugConnection()
@@ -374,8 +374,9 @@ bool QQmlDebugConnection::sendMessage(const QString &name, const QByteArray &mes
void QQmlDebugConnectionPrivate::flush()
{
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(device);
- if (socket)
+ if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(device))
+ socket->flush();
+ else if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(device))
socket->flush();
}
@@ -386,12 +387,12 @@ void QQmlDebugConnection::connectToHost(const QString &hostName, quint16 port)
close();
QTcpSocket *socket = new QTcpSocket(this);
d->device = socket;
- d->connectDeviceSignals();
- connect(socket, SIGNAL(connected()), this, SLOT(socketConnected()));
- connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
- this, SIGNAL(socketError(QAbstractSocket::SocketError)));
- connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
- this, SIGNAL(socketStateChanged(QAbstractSocket::SocketState)));
+ d->createProtocol();
+ connect(socket, &QAbstractSocket::disconnected, this, &QQmlDebugConnection::socketDisconnected);
+ connect(socket, &QAbstractSocket::connected, this, &QQmlDebugConnection::socketConnected);
+ connect(socket, static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(
+ &QAbstractSocket::error), this, &QQmlDebugConnection::socketError);
+ connect(socket, &QAbstractSocket::stateChanged, this, &QQmlDebugConnection::socketStateChanged);
socket->connectToHost(hostName, port);
}
@@ -404,7 +405,8 @@ void QQmlDebugConnection::startLocalServer(const QString &fileName)
d->server->deleteLater();
d->server = new QLocalServer(this);
// QueuedConnection so that waitForNewConnection() returns true.
- connect(d->server, SIGNAL(newConnection()), this, SLOT(newConnection()), Qt::QueuedConnection);
+ connect(d->server, &QLocalServer::newConnection,
+ this, &QQmlDebugConnection::newConnection, Qt::QueuedConnection);
d->server->listen(fileName);
}
@@ -414,17 +416,12 @@ class LocalSocketSignalTranslator : public QObject
public:
LocalSocketSignalTranslator(QLocalSocket *parent) : QObject(parent)
{
- connect(parent, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)),
- this, SLOT(onStateChanged(QLocalSocket::LocalSocketState)));
- connect(parent, SIGNAL(error(QLocalSocket::LocalSocketError)),
- this, SLOT(onError(QLocalSocket::LocalSocketError)));
+ connect(parent, &QLocalSocket::stateChanged,
+ this, &LocalSocketSignalTranslator::onStateChanged);
+ connect(parent, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(
+ &QLocalSocket::error), this, &LocalSocketSignalTranslator::onError);
}
-signals:
- void socketError(QAbstractSocket::SocketError error);
- void socketStateChanged(QAbstractSocket::SocketState state);
-
-public slots:
void onError(QLocalSocket::LocalSocketError error)
{
emit socketError(static_cast<QAbstractSocket::SocketError>(error));
@@ -434,6 +431,10 @@ public slots:
{
emit socketStateChanged(static_cast<QAbstractSocket::SocketState>(state));
}
+
+signals:
+ void socketError(QAbstractSocket::SocketError error);
+ void socketStateChanged(QAbstractSocket::SocketState state);
};
void QQmlDebugConnection::newConnection()
@@ -443,23 +444,24 @@ void QQmlDebugConnection::newConnection()
QLocalSocket *socket = d->server->nextPendingConnection();
d->server->close();
d->device = socket;
- d->connectDeviceSignals();
+ d->createProtocol();
+ connect(socket, &QLocalSocket::disconnected, this, &QQmlDebugConnection::socketDisconnected);
LocalSocketSignalTranslator *translator = new LocalSocketSignalTranslator(socket);
- QObject::connect(translator, SIGNAL(socketError(QAbstractSocket::SocketError)),
- this, SIGNAL(socketError(QAbstractSocket::SocketError)));
- QObject::connect(translator, SIGNAL(socketStateChanged(QAbstractSocket::SocketState)),
- this, SIGNAL(socketStateChanged(QAbstractSocket::SocketState)));
+ connect(translator, &LocalSocketSignalTranslator::socketError,
+ this, &QQmlDebugConnection::socketError);
+ connect(translator, &LocalSocketSignalTranslator::socketStateChanged,
+ this, &QQmlDebugConnection::socketStateChanged);
socketConnected();
}
-void QQmlDebugConnectionPrivate::connectDeviceSignals()
+void QQmlDebugConnectionPrivate::createProtocol()
{
Q_Q(QQmlDebugConnection);
delete protocol;
protocol = new QPacketProtocol(device, q);
- QObject::connect(protocol, SIGNAL(readyRead()), q, SLOT(protocolReadyRead()));
- QObject::connect(device, SIGNAL(disconnected()), q, SLOT(socketDisconnected()));
+ QObject::connect(protocol, &QPacketProtocol::readyRead,
+ q, &QQmlDebugConnection::protocolReadyRead);
}
QT_END_NAMESPACE
diff --git a/src/qmldebug/qqmldebugconnection_p.h b/src/qmldebug/qqmldebugconnection_p.h
index 40753fc998..be425b6cbf 100644
--- a/src/qmldebug/qqmldebugconnection_p.h
+++ b/src/qmldebug/qqmldebugconnection_p.h
@@ -92,7 +92,7 @@ signals:
void socketError(QAbstractSocket::SocketError socketError);
void socketStateChanged(QAbstractSocket::SocketState socketState);
-private Q_SLOTS:
+private:
void newConnection();
void socketConnected();
void socketDisconnected();
diff --git a/src/qmldebug/qqmlprofilerclient_p.h b/src/qmldebug/qqmlprofilerclient_p.h
index 832c05fef7..b4054ed0d9 100644
--- a/src/qmldebug/qqmlprofilerclient_p.h
+++ b/src/qmldebug/qqmlprofilerclient_p.h
@@ -67,8 +67,6 @@ class QQmlProfilerClient : public QQmlDebugClient
public:
QQmlProfilerClient(QQmlDebugConnection *connection);
void setFeatures(quint64 features);
-
-public slots:
void sendRecordingStatus(bool record, int engineId = -1, quint32 flushInterval = 0);
protected:
diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro
index 42224e9751..9852861334 100644
--- a/src/qmltest/qmltest.pro
+++ b/src/qmltest/qmltest.pro
@@ -1,6 +1,6 @@
TARGET = QtQuickTest
-DEFINES += QT_NO_URL_CAST_FROM_STRING
+DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_FOREACH
QT = core testlib-private
QT_PRIVATE = quick qml-private gui core-private
@@ -30,6 +30,6 @@ HEADERS += \
$$PWD/quicktestresult_p.h \
$$PWD/qtestoptions_p.h
-DEFINES += QT_QML_DEBUG_NO_WARNING
+!contains(QT_CONFIG, no-qml-debug): DEFINES += QT_QML_DEBUG_NO_WARNING
load(qt_module)
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index bc26a19033..0e348eee11 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -144,7 +144,7 @@ void handleCompileErrors(const QFileInfo &fi, QQuickView *view)
QTextStream str(&message);
str << "\n " << QDir::toNativeSeparators(fi.absoluteFilePath()) << " produced "
<< errors.size() << " error(s):\n";
- foreach (const QQmlError &e, errors) {
+ for (const QQmlError &e : errors) {
str << " ";
if (e.url().isLocalFile()) {
str << QDir::toNativeSeparators(e.url().toLocalFile());
@@ -158,11 +158,12 @@ void handleCompileErrors(const QFileInfo &fi, QQuickView *view)
str << " Working directory: " << QDir::toNativeSeparators(QDir::current().absolutePath()) << '\n';
if (QQmlEngine *engine = view->engine()) {
str << " View: " << view->metaObject()->className() << ", import paths:\n";
- foreach (const QString &i, engine->importPathList())
+ const auto importPaths = engine->importPathList();
+ for (const QString &i : importPaths)
str << " '" << QDir::toNativeSeparators(i) << "'\n";
const QStringList pluginPaths = engine->pluginPathList();
str << " Plugin paths:\n";
- foreach (const QString &p, pluginPaths)
+ for (const QString &p : pluginPaths)
str << " '" << QDir::toNativeSeparators(p) << "'\n";
}
qWarning("%s", qPrintable(message));
@@ -338,11 +339,11 @@ int quick_test_main(int argc, char **argv, const char *name, const char *sourceD
&eventLoop, SLOT(quit()));
view->rootContext()->setContextProperty
(QLatin1String("qtest"), QTestRootObject::instance()); // Deprecated. Use QTestRootObject from Qt.test.qtestroot instead
- foreach (const QString &path, imports)
+ for (const QString &path : qAsConst(imports))
view->engine()->addImportPath(path);
- foreach (const QString &path, pluginPaths)
+ for (const QString &path : qAsConst(pluginPaths))
view->engine()->addPluginPath(path);
- foreach (const QString &file, files) {
+ for (const QString &file : qAsConst(files)) {
const QFileInfo fi(file);
if (!fi.exists())
continue;
diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp
index b83aaa1ea5..966a60671d 100644
--- a/src/qmltest/quicktestevent.cpp
+++ b/src/qmltest/quicktestevent.cpp
@@ -45,6 +45,10 @@
QT_BEGIN_NAMESPACE
+namespace QTest {
+ extern int Q_TESTLIB_EXPORT defaultMouseDelay();
+}
+
QuickTestEvent::QuickTestEvent(QObject *parent)
: QObject(parent)
{
@@ -54,6 +58,11 @@ QuickTestEvent::~QuickTestEvent()
{
}
+int QuickTestEvent::defaultMouseDelay() const
+{
+ return QTest::defaultMouseDelay();
+}
+
bool QuickTestEvent::keyPress(int key, int modifiers, int delay)
{
QWindow *window = activeWindow();
@@ -111,10 +120,6 @@ bool QuickTestEvent::keyClickChar(const QString &character, int modifiers, int d
return true;
}
-namespace QTest {
- extern int Q_TESTLIB_EXPORT defaultMouseDelay();
-};
-
namespace QtQuickTest
{
enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDoubleClick, MouseMove, MouseDoubleClickSequence };
@@ -312,6 +317,10 @@ bool QuickTestEvent::mouseMove
QWindow *QuickTestEvent::eventWindow(QObject *item)
{
+ QWindow * window = qobject_cast<QWindow *>(item);
+ if (window)
+ return window;
+
QQuickItem *quickItem = qobject_cast<QQuickItem *>(item);
if (quickItem)
return quickItem->window();
diff --git a/src/qmltest/quicktestevent_p.h b/src/qmltest/quicktestevent_p.h
index 02b8b2c46b..1adf8f3317 100644
--- a/src/qmltest/quicktestevent_p.h
+++ b/src/qmltest/quicktestevent_p.h
@@ -59,9 +59,11 @@ QT_BEGIN_NAMESPACE
class Q_QUICK_TEST_EXPORT QuickTestEvent : public QObject
{
Q_OBJECT
+ Q_PROPERTY(int defaultMouseDelay READ defaultMouseDelay FINAL)
public:
QuickTestEvent(QObject *parent = 0);
~QuickTestEvent();
+ int defaultMouseDelay() const;
public Q_SLOTS:
bool keyPress(int key, int modifiers, int delay);
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
index 0a820b79db..d311e7810e 100644
--- a/src/qmltest/quicktestresult.cpp
+++ b/src/qmltest/quicktestresult.cpp
@@ -248,7 +248,7 @@ void QuickTestResult::setDataTag(const QString &tag)
if (!tag.isEmpty()) {
QTestData *data = &(QTest::newRow(tag.toUtf8().constData()));
QTestResult::setCurrentTestData(data);
- QTestPrivate::checkBlackLists((testCaseName() + QStringLiteral("::") + functionName()).toUtf8().constData(), tag.toUtf8().constData());
+ QTestPrivate::checkBlackLists((testCaseName() + QLatin1String("::") + functionName()).toUtf8().constData(), tag.toUtf8().constData());
emit dataTagChanged();
} else {
QTestResult::setCurrentTestData(0);
@@ -519,7 +519,7 @@ void QuickTestResult::stringify(QQmlV4Function *args)
if (result.isEmpty()) {
QString tmp = value->toQStringNoThrow();
if (value->as<QV4::ArrayObject>())
- result.append(QString::fromLatin1("[%1]").arg(tmp));
+ result += QLatin1Char('[') + tmp + QLatin1Char(']');
else
result.append(tmp);
}
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index a56d098717..58eab508ad 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -160,9 +160,9 @@ int QAccessibleQuickItem::indexOfChild(const QAccessibleInterface *iface) const
static void unignoredChildren(QQuickItem *item, QList<QQuickItem *> *items, bool paintOrder)
{
- QList<QQuickItem*> childItems = paintOrder ? QQuickItemPrivate::get(item)->paintOrderChildItems()
+ const QList<QQuickItem*> childItems = paintOrder ? QQuickItemPrivate::get(item)->paintOrderChildItems()
: item->childItems();
- Q_FOREACH (QQuickItem *child, childItems) {
+ for (QQuickItem *child : childItems) {
if (QQuickItemPrivate::get(child)->isAccessible) {
items->append(child);
} else {
@@ -273,8 +273,8 @@ void QAccessibleQuickItem::doAction(const QString &actionName)
return;
// Look for and call the accessible[actionName]Action() function on the item.
// This allows for overriding the default action handling.
- const QByteArray functionName = QByteArrayLiteral("accessible") + actionName.toLatin1() + QByteArrayLiteral("Action");
- if (object()->metaObject()->indexOfMethod(QByteArray(functionName + QByteArrayLiteral("()"))) != -1) {
+ const QByteArray functionName = "accessible" + actionName.toLatin1() + "Action";
+ if (object()->metaObject()->indexOfMethod(QByteArray(functionName + "()")) != -1) {
QMetaObject::invokeMethod(object(), functionName);
return;
}
diff --git a/src/quick/accessible/qaccessiblequickview_p.h b/src/quick/accessible/qaccessiblequickview_p.h
index 457e8b456b..e9c150ac22 100644
--- a/src/quick/accessible/qaccessiblequickview_p.h
+++ b/src/quick/accessible/qaccessiblequickview_p.h
@@ -63,20 +63,20 @@ class QAccessibleQuickWindow : public QAccessibleObject
public:
QAccessibleQuickWindow(QQuickWindow *object);
- QAccessibleInterface *parent() const;
- QAccessibleInterface *child(int index) const;
+ QAccessibleInterface *parent() const override;
+ QAccessibleInterface *child(int index) const override;
- QAccessible::Role role() const;
- QAccessible::State state() const;
- QRect rect() const;
+ QAccessible::Role role() const override;
+ QAccessible::State state() const override;
+ QRect rect() const override;
- int childCount() const;
- int indexOfChild(const QAccessibleInterface *iface) const;
- QString text(QAccessible::Text text) const;
- QAccessibleInterface *childAt(int x, int y) const;
+ int childCount() const override;
+ int indexOfChild(const QAccessibleInterface *iface) const override;
+ QString text(QAccessible::Text text) const override;
+ QAccessibleInterface *childAt(int x, int y) const override;
private:
- QQuickWindow *window() const { return static_cast<QQuickWindow*>(object()); }
+ QQuickWindow *window() const override { return static_cast<QQuickWindow*>(object()); }
QList<QQuickItem *> rootItems() const;
};
diff --git a/src/quick/designer/qqmldesignermetaobject.cpp b/src/quick/designer/qqmldesignermetaobject.cpp
index 23a29d5831..5e897218c5 100644
--- a/src/quick/designer/qqmldesignermetaobject.cpp
+++ b/src/quick/designer/qqmldesignermetaobject.cpp
@@ -120,13 +120,7 @@ void QQmlDesignerMetaObject::init(QObject *object, QQmlEngine *engine)
QObjectPrivate *op = QObjectPrivate::get(object);
op->metaObject = this;
- m_cache = QQmlEnginePrivate::get(engine)->cache(this);
-
- if (m_cache != cache) {
- m_cache->addref();
- cache->release();
- cache = m_cache;
- }
+ cache = QQmlEnginePrivate::get(engine)->cache(this);
nodeInstanceMetaObjectList.insert(this, true);
hasAssignedMetaObjectData = true;
@@ -135,8 +129,7 @@ void QQmlDesignerMetaObject::init(QObject *object, QQmlEngine *engine)
QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine)
: QQmlVMEMetaObject(object, cacheForObject(object, engine), /*qml compilation unit*/nullptr, /*qmlObjectId*/-1),
m_context(engine->contextForObject(object)),
- m_data(new MetaPropertyData),
- m_cache(0)
+ m_data(new MetaPropertyData)
{
init(object, engine);
@@ -146,8 +139,8 @@ QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engi
cache->setParent(ddata->propertyCache);
cache->invalidate(engine, this);
ddata->propertyCache->release();
- ddata->propertyCache = m_cache;
- m_cache->addref();
+ ddata->propertyCache = cache;
+ ddata->propertyCache->addref();
}
}
@@ -168,9 +161,9 @@ void QQmlDesignerMetaObject::createNewDynamicProperty(const QString &name)
Q_UNUSED(id);
//Updating cache
- QQmlPropertyCache *oldParent = m_cache->parent();
+ QQmlPropertyCache *oldParent = cache->parent();
QQmlEnginePrivate::get(m_context->engine())->cache(this)->invalidate(m_context->engine(), this);
- m_cache->setParent(oldParent);
+ cache->setParent(oldParent);
QQmlProperty property(myObject(), name, m_context);
Q_ASSERT(property.isValid());
diff --git a/src/quick/designer/qqmldesignermetaobject_p.h b/src/quick/designer/qqmldesignermetaobject_p.h
index a5402ccbc4..3c02c0d3f5 100644
--- a/src/quick/designer/qqmldesignermetaobject_p.h
+++ b/src/quick/designer/qqmldesignermetaobject_p.h
@@ -74,7 +74,7 @@ protected:
void createNewDynamicProperty(const QString &name);
int openMetaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a);
- int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a);
+ int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
void notifyPropertyChange(int id);
void setValue(int id, const QVariant &value);
QVariant propertyWriteValue(int, const QVariant &);
@@ -101,7 +101,6 @@ private:
QQmlOpenMetaObjectType *m_type;
QScopedPointer<MetaPropertyData> m_data;
//QAbstractDynamicMetaObject *m_parent;
- QQmlPropertyCache *m_cache;
friend class QQuickDesignerSupportProperties;
};
diff --git a/src/quick/designer/qquickdesignercustomobjectdata.cpp b/src/quick/designer/qquickdesignercustomobjectdata.cpp
index 93e7b6133f..e37254d165 100644
--- a/src/quick/designer/qquickdesignercustomobjectdata.cpp
+++ b/src/quick/designer/qquickdesignercustomobjectdata.cpp
@@ -145,10 +145,10 @@ void QQuickDesignerCustomObjectData::keepBindingFromGettingDeleted(QObject *obje
void QQuickDesignerCustomObjectData::populateResetHashes()
{
- QQuickDesignerSupport::PropertyNameList propertyNameList =
+ const QQuickDesignerSupport::PropertyNameList propertyNameList =
QQuickDesignerSupportProperties::propertyNameListForWritableProperties(object());
- Q_FOREACH (const QQuickDesignerSupport::PropertyName &propertyName, propertyNameList) {
+ for (const QQuickDesignerSupport::PropertyName &propertyName : propertyNameList) {
QQmlProperty property(object(), QString::fromUtf8(propertyName), QQmlEngine::contextForObject(object()));
QQmlAbstractBinding::Ptr binding = QQmlAbstractBinding::Ptr(QQmlPropertyPrivate::binding(property));
@@ -194,7 +194,7 @@ void QQuickDesignerCustomObjectData::doResetProperty(QQmlContext *context, const
#endif
if (qmlBinding)
qmlBinding->setTarget(property);
- QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding);
if (qmlBinding)
qmlBinding->update();
@@ -257,11 +257,12 @@ void QQuickDesignerCustomObjectData::setPropertyBinding(QQmlContext *context,
return;
if (property.isProperty()) {
- QQmlBinding *binding = new QQmlBinding(expression, object(), context);
+ QQmlBinding *binding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core,
+ expression, object(), context);
binding->setTarget(property);
binding->setNotifyOnValueChanged(true);
- QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding);
//Refcounting is taking take care of deletion
binding->update();
if (binding->hasError()) {
diff --git a/src/quick/designer/qquickdesignersupport.cpp b/src/quick/designer/qquickdesignersupport.cpp
index f063cd3a81..44be12bb78 100644
--- a/src/quick/designer/qquickdesignersupport.cpp
+++ b/src/quick/designer/qquickdesignersupport.cpp
@@ -236,7 +236,8 @@ bool QQuickDesignerSupport::isAnchoredTo(QQuickItem *fromItem, QQuickItem *toIte
bool QQuickDesignerSupport::areChildrenAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem)
{
- Q_FOREACH (QQuickItem *childItem, fromItem->childItems()) {
+ const auto childItems = fromItem->childItems();
+ for (QQuickItem *childItem : childItems) {
if (childItem) {
if (isAnchoredTo(childItem, toItem))
return true;
@@ -392,10 +393,10 @@ void QQuickDesignerSupport::emitComponentCompleteSignalForAttachedProperty(QQuic
QList<QObject*> QQuickDesignerSupport::statesForItem(QQuickItem *item)
{
QList<QObject*> objectList;
- QList<QQuickState *> stateList = QQuickItemPrivate::get(item)->_states()->states();
+ const QList<QQuickState *> stateList = QQuickItemPrivate::get(item)->_states()->states();
objectList.reserve(stateList.size());
- Q_FOREACH (QQuickState* state, stateList)
+ for (QQuickState* state : stateList)
objectList.append(state);
return objectList;
diff --git a/src/quick/designer/qquickdesignersupportitems.cpp b/src/quick/designer/qquickdesignersupportitems.cpp
index 544ca04754..2003b484ad 100644
--- a/src/quick/designer/qquickdesignersupportitems.cpp
+++ b/src/quick/designer/qquickdesignersupportitems.cpp
@@ -118,16 +118,16 @@ static void allSubObjects(QObject *object, QObjectList &objectList)
}
// search recursive in object children list
- Q_FOREACH (QObject *childObject, object->children()) {
+ for (QObject *childObject : object->children()) {
allSubObjects(childObject, objectList);
}
// search recursive in quick item childItems list
QQuickItem *quickItem = qobject_cast<QQuickItem*>(object);
if (quickItem) {
- Q_FOREACH (QQuickItem *childItem, quickItem->childItems()) {
+ const auto childItems = quickItem->childItems();
+ for (QQuickItem *childItem : childItems)
allSubObjects(childItem, objectList);
- }
}
}
@@ -135,7 +135,7 @@ void QQuickDesignerSupportItems::tweakObjects(QObject *object)
{
QObjectList objectList;
allSubObjects(object, objectList);
- Q_FOREACH (QObject* childObject, objectList) {
+ for (QObject* childObject : qAsConst(objectList)) {
stopAnimation(childObject);
if (fixResourcePathsForObjectCallBack)
fixResourcePathsForObjectCallBack(childObject);
@@ -254,7 +254,8 @@ QObject *QQuickDesignerSupportItems::createComponent(const QUrl &componentUrl, Q
if (component.isError()) {
qWarning() << "Error in:" << Q_FUNC_INFO << componentUrl;
- Q_FOREACH (const QQmlError &error, component.errors())
+ const auto errors = component.errors();
+ for (const QQmlError &error : errors)
qWarning() << error;
}
return object;
@@ -282,7 +283,8 @@ void QQuickDesignerSupportItems::disableNativeTextRendering(QQuickItem *item)
void QQuickDesignerSupportItems::disableTextCursor(QQuickItem *item)
{
- Q_FOREACH (QQuickItem *childItem, item->childItems())
+ const auto childItems = item->childItems();
+ for (QQuickItem *childItem : childItems)
disableTextCursor(childItem);
QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(item);
diff --git a/src/quick/designer/qquickdesignerwindowmanager_p.h b/src/quick/designer/qquickdesignerwindowmanager_p.h
index a50f8aa49f..209d703d0a 100644
--- a/src/quick/designer/qquickdesignerwindowmanager_p.h
+++ b/src/quick/designer/qquickdesignerwindowmanager_p.h
@@ -75,24 +75,24 @@ class QQuickDesignerWindowManager : public QSGRenderLoop
public:
QQuickDesignerWindowManager();
- void show(QQuickWindow *window);
- void hide(QQuickWindow *window);
+ void show(QQuickWindow *window) override;
+ void hide(QQuickWindow *window) override;
- void windowDestroyed(QQuickWindow *window);
+ void windowDestroyed(QQuickWindow *window) override;
void makeOpenGLContext(QQuickWindow *window);
- void exposureChanged(QQuickWindow *window);
- QImage grab(QQuickWindow *window);
+ void exposureChanged(QQuickWindow *window) override;
+ QImage grab(QQuickWindow *window) override;
- void maybeUpdate(QQuickWindow *window);
- void update(QQuickWindow *window); // identical for this implementation.
+ void maybeUpdate(QQuickWindow *window) override;
+ void update(QQuickWindow *window) override; // identical for this implementation.
- void releaseResources(QQuickWindow *) { }
+ void releaseResources(QQuickWindow *) override { }
- QAnimationDriver *animationDriver() const { return 0; }
+ QAnimationDriver *animationDriver() const override { return nullptr; }
- QSGContext *sceneGraphContext() const;
- QSGRenderContext *createRenderContext(QSGContext *) const { return m_renderContext.data(); }
+ QSGContext *sceneGraphContext() const override;
+ QSGRenderContext *createRenderContext(QSGContext *) const override { return m_renderContext.data(); }
static void createOpenGLContext(QQuickWindow *window);
diff --git a/src/quick/doc/snippets/qml/localstorage/dbtransaction.js b/src/quick/doc/snippets/qml/localstorage/dbtransaction.js
new file mode 100644
index 0000000000..07d8a5618b
--- /dev/null
+++ b/src/quick/doc/snippets/qml/localstorage/dbtransaction.js
@@ -0,0 +1,68 @@
+ /****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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]
+db.transaction(
+ try {
+ function(tx) {
+ tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ]);
+ }
+ } catch (err) {
+ console.log("Error inserting into table Greeting");
+ }
+)
+//![0]
+
+//![1]
+db.transaction(
+ function(tx) {
+ var results = tx.executeSql('SELECT salutation FROM Greeting WHERE salutee=?;', 'world');
+ }
+ console.log("We greeted in this most respectful way: " + results.rows.item(0).value);
+)
+//![1]
+//![2]
+var db = LocalStorage.openDatabaseSync("QQmlExampleDB", "", "The Example QML SQL!", 1000000);
+if (db.version == '0.1') {
+ db.changeVersion('0.1', '0.2', function(tx) {
+ tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ]);
+ }
+});
+//![2]
diff --git a/src/quick/doc/src/concepts/input/focus.qdoc b/src/quick/doc/src/concepts/input/focus.qdoc
index db84961d20..ec4e4ca2d9 100644
--- a/src/quick/doc/src/concepts/input/focus.qdoc
+++ b/src/quick/doc/src/concepts/input/focus.qdoc
@@ -117,7 +117,7 @@ the focus, but it cannot control the focus when it is imported or reused.
Likewise, the \c window component does not have the ability to know if its
imported components are requesting the focus.
-To solve this problem, the QML introduces a concept known as a \e {focus scope}.
+To solve this problem, QML introduces a concept known as a \e {focus scope}.
For existing Qt users, a focus scope is like an automatic focus proxy.
A focus scope is created by declaring the \l FocusScope type.
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
index 1b6e7dc539..20a6d131f5 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
@@ -84,7 +84,7 @@
stretches horizontally. The azure rectangle can be resized from 50x150 to 300x150, and the plum
rectangle can be resized from 100x100 to ∞x100.
- \snippet windowconstraints.qml rowlayout
+ \snippet qml/windowconstraints.qml rowlayout
\image rowlayout-minimum.png "RowLayout at its minimum"
diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
index cb281a2d4a..a764402c2f 100644
--- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
+++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
@@ -156,6 +156,111 @@ with list models of QAbstractItemModel type:
\li \l DelegateModel::parentModelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex
\endlist
+\section2 SQL Models
+
+Qt provides C++ classes that support SQL data models. These classes work
+transparently on the underlying SQL data, reducing the need to run SQL
+queries for basic SQL operations such as create, insert, or update.
+For more details about these classes, see \l{Using the SQL Model Classes}.
+
+Although the C++ classes provide complete feature sets to operate on SQL
+data, they do not provide data access to QML. So you must implement a
+C++ custom data model as a subclass of one of these classes, and expose it
+to QML either as a type or context property.
+
+\section3 Read-only Data Model
+
+The custom model must reimplement the following methods to enable read-only
+access to the data from QML:
+
+\list
+\li \l{QAbstractItemModel::}{roleNames}() to expose the role names to the
+ QML frontend. For example, the following version returns the selected
+ table's field names as role names:
+ \code
+ QHash<int, QByteArray> SqlQueryModel::roleNames() const
+ {
+ QHash<int, QByteArray> roles;
+ // record() returns an empty QSqlRecord
+ for (int i = 0; i < this->record().count(); i ++) {
+ roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
+ }
+ return roles;
+ }
+ \endcode
+\li \l{QSqlQueryModel::}{data}() to expose SQL data to the QML frontend.
+ For example, the following implementation returns data for the given
+ model index:
+ \code
+ QVariant SqlQueryModel::data(const QModelIndex &index, int role) const
+ {
+ QVariant value;
+
+ if (index.isValid()) {
+ if (role < Qt::UserRole) {
+ value = QSqlQueryModel::data(index, role);
+ } else {
+ int columnIdx = role - Qt::UserRole - 1;
+ QModelIndex modelIndex = this->index(index.row(), columnIdx);
+ value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
+ }
+ }
+ return value;
+ }
+ \endcode
+\endlist
+
+The QSqlQueryModel class is good enough to implement a custom read-only
+model that represents data in an SQL database. The
+\l{Qt Quick Controls 2 - Chat Tutorial}{chat tutorial} example
+demonstrates this very well by implementing a custom model to fetch the
+contact details from an SQLite database.
+
+\section3 Editable Data Model
+
+Besides the \c roleNames() and \c data(), the editable models must reimplement
+the \l{QSqlTableModel::}{setData} method to save changes to existing SQL data.
+The following version of the method checks if the given model index is valid
+and the \c role is equal to \l Qt::EditRole, before calling the parent class
+version:
+
+\code
+bool SqlEditableModel::setData(const QModelIndex &item, const QVariant &value, int role)
+{
+ if (item.isValid() && role == Qt::EditRole) {
+ QSqlTableModel::setData(item, value,role);
+ emit dataChanged(item, item);
+ return true;
+ }
+ return false;
+
+}
+\endcode
+
+\note It is important to emit the \l{QAbstractItemModel::}{dataChanged}()
+signal after saving the changes.
+
+Unlike the C++ item views such as QListView or QTableView, the \c setData()
+method must be explicitly invoked from QML whenever appropriate. For example,
+on the \l[QML]{TextField::}{editingFinished}() or \l[QML]{TextField::}{accepted}()
+signal of \l[QtQuickControls]{TextField}. Depending on the
+\l{QSqlTableModel::}{EditStrategy} used by the model, the changes are either
+queued for submission later or submitted immediately.
+
+You can also insert new data into the model by calling
+\l {QSqlTableModel::insertRecord}(). In the following example snippet,
+a QSqlRecord is populated with book details and appended to the
+model:
+
+\code
+ ...
+ QSqlRecord newRecord = record();
+ newRecord.setValue("author", "John Grisham");
+ newRecord.setValue("booktitle", "The Litigators");
+ insertRecord(rowCount(), newRecord);
+ ...
+\endcode
+
\section2 Exposing C++ Data Models to QML
The above examples use QQmlContext::setContextProperty() to set
diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
index d7d2fea281..9ce26e1bb8 100644
--- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
@@ -31,33 +31,88 @@
\section1 Scene Graph Adaptations in Qt Quick
-Originally Qt Quick only had one available renderer for parsing the
-scene graph and rendering the results to a render target. This renderer
-is now the default OpenGL Renderer which supports rendering either using
-the OpenGL ES 2.0 or OpenGL 2.0 APIs. The Qt Quick APIs are designed
-with the assumption that these two APIs are always available. It is
-however possible now to use other graphics API's to render Qt Quick
+Originally Qt Quick only had one available renderer for parsing the scene graph
+and rendering the results to a render target. This renderer is now the default
+OpenGL Renderer which supports rendering either using the OpenGL ES 2.0 or
+OpenGL 2.0 (with framebuffer object extensions) APIs. The Qt Quick APIs have
+originally been designed with the assumption that OpenGL is always available.
+However, it is now possible to use other graphics API's to render Qt Quick
scenes using the scene graph APIs.
+\section1 Switching between the adaptation used by the application
+
+The default of the OpenGL, or - in Qt builds with disabled OpenGL support - the
+software adaptation, can be overridden either by using an environment variable
+or a C++ API. The former consists of setting the \c{QT_QUICK_BACKEND} or the
+legacy \c{QMLSCENE_DEVICE} environment variable before launching applications.
+The latter is done by calling QQuickWindow::setSceneGraphBackend() early in the
+application's main() function.
+
+The supported backends are the following
+
+\list
+
+\li OpenGL - Requested by the string \c{""} or the enum value QSGRendererInterface::OpenGL.
+
+\li Software - Requested by the string \c{"software"} or the enum value QSGRendererInterface::Software.
+
+\li Direct3D 12 - Requested by the string \c{"d3d12"} or the enum value QSGRendererInterface::Direct3D12.
+
+\endlist
+
+When in doubt which backend is in use, enable basic scenegraph information
+logging via the \c{QSG_INFO} environment variable or the
+\c{qt.scenegraph.general} logging category. This will result in printing some
+information during application startup onto the debug output.
+
+\note Adaptations other than OpenGL will typically come with a set of
+limitations since they are unlikely to provide a feature set 100% compatible
+with OpenGL. However, they may provide their own specific advantages in certain
+areas. Refer to the sections below for more information on the various
+adaptations.
+
\section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation
The default adaptation capable of providing the full Qt Quick 2 feature
set is the OpenGL adaptation. All of the details of the OpenGL
-adpatation can are available here
+adpatation can are available here:
\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}
\section1 Software Adaptation
-The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that uses the Raster
-paint engine to render the contents of the scene graph instead of OpenGL.
-As a result of not using OpenGL to render the scene graph, some features
-and optimizations are no longer available. Most Qt Quick 2 applications
-will run without modification though any attempts to use unsupported
-features will be ignored. By using the Software adpatation it is possible to run Qt
-Quick 2 applications on hardware and platforms that do not have OpenGL
-support.
+The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that
+uses the raster paint engine to render the contents of the scene graph. The
+details for this adaptation are available here:
+\l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation}
+
+\section1 Direct3D 12 (experimental)
+
+The Direct3D 12 adaptation is an alternative renderer for \l {Qt Quick} 2 when
+running on Windows 10, both for Win32 and UWP applications. The details for
+this adaptation are available here:
+\l{qtquick-visualcanvas-adaptations-d3d12.html}{Direct3D 12 Adaptation}
+
+*/
+
+
+/*!
+\title Qt Quick Software Adaptation
+\page qtquick-visualcanvas-adaptations-software.html
+
+The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that
+uses the Raster paint engine to render the contents of the scene graph instead
+of OpenGL. As a result of not using OpenGL to render the scene graph, some
+features and optimizations are no longer available. Most Qt Quick 2
+applications will run without modification though any attempts to use
+unsupported features will be ignored. By using the Software adaptation it is
+possible to run Qt Quick 2 applications on hardware and platforms that do not
+have OpenGL support.
The Software adaptation was previously known as the Qt Quick 2D Renderer.
+However, unlike the 2D Renderer, the new, integrated version supports partial
+updates. This means that the full update of the window or screen contents is
+now avoided, and only the changed areas get flushed. This can significantly
+improve performance for many applications.
\section2 Shader Effects
ShaderEffect components in QtQuick 2 can not be rendered by the Software adptation.
@@ -72,15 +127,263 @@ It is not possible to render particle effects with the Software adaptation. When
possible, remove particles completely from the scene. Otherwise they will still
require some processing, even though they are not visible.
-\section2 Sprites
-The Sprite item depends on OpenGL functions and will not be visible.
-
\section2 Rendering Text
The text rendering with the Software adaptation is based on software
rasterization and does not respond as well to transformations such as scaling
as when using OpenGL. The quality is similar to choosing \l [QML] {Text::renderType}
{Text.NativeRendering} with \l [QML] {Text} items.
-\section1 Direct3D 12 (experimental)
+*/
+
+
+/*!
+\title Qt Quick Direct3D 12 Adaptation
+\page qtquick-visualcanvas-adaptations-d3d12.html
+
+The Direct3D 12 adaptation for Windows 10 (both Win32 (\c windows platform
+plugin) and UWP (\c winrt platform plugin)) is shipped as a dynamically loaded
+plugin. It will not be functional on earlier Windows versions. The building of
+the plugin is enabled automatically whenever the necessary D3D and DXGI
+develpoment files are present. In practice this currently means Visual Studio
+2015 and newer.
+
+The adaptation is available both in normal, OpenGL-enabled Qt builds and also
+when Qt was configured with \c{-no-opengl}. However, it is never the default,
+meaning the user or the application has to explicitly request it by setting the
+\c{QT_QUICK_BACKEND} environment variable to \c{d3d12} or by calling
+QQuickWindow::setSceneGraphBackend().
+
+\section2 Motivation
+
+This experimental adaptation is the first Qt Quick backend focusing on a
+modern, lower-level graphics API in combination with a windowing system
+interface different from the traditional approaches used in combination with
+OpenGL.
+
+It also allows better integration with Windows, Direct3D being the primary
+vendor-supported solution. This means that there are fewer problems anticipated
+with drivers, operations like window resizes, and special events like graphics
+device loss caused by device resets or graphics driver updates.
+
+Performance-wise the general expectation is a somewhat lower CPU usage compared
+to OpenGL due to lower driver overhead, and a higher GPU utilization with less
+wasted idle time. The backend does not heavily utilize threads yet, which means
+there are opportunities for further improvements in the future, for example to
+further optimize image loading.
+
+The D3D12 backend also introduces support for pre-compiled shaders. All the
+backend's own shaders (used by the built-in materials on which the Rectangle,
+Image, Text, etc. QML types are built) are compiled to D3D shader bytecode when
+compiling Qt. Applications using ShaderEffect items can chose to ship bytecode
+either in regular files or via the Qt resource system, or use HLSL source
+strings. Unlike OpenGL, the compilation for the latter is properly threaded,
+meaning shader compilation will not block the application and its user
+interface.
+
+\section2 Graphics Adapters
+
+The plugin does not necessarily require hardware acceleration. Using WARP, the
+Direct3D software rasterizer, is also an option. By default the first adapter
+providing hardware acceleration is chosen. To override this, in order to use
+another graphics adapter or to force the usage of the software rasterizer, set
+the environment variable \c{QT_D3D_ADAPTER_INDEX} to the index of the adapter.
+The discovered adapters are printed at startup when \c{QSG_INFO} or the logging
+category \c{qt.scenegraph.general} is enabled.
+
+\section2 Troubleshooting
+
+When encountering issues, always set the \c{QSG_INFO} and \c{QT_D3D_DEBUG}
+environment variables to 1 in order to get debug and warning messages printed
+on the debug output. The latter enables the Direct3D debug layer. Note that the
+debug layer should not be enabled in production use since it can significantly
+impact performance (CPU load) due to increased API overhead.
+
+\section2 Render Loops
+
+By default the D3D12 adaptation uses a single-threaded render loop similar to
+OpenGL's \c windows render loop. There is also a threaded variant available, that
+can be requested by setting the \c{QSG_RENDER_LOOP} environment variable to \c
+threaded. However, due to conceptual limitations in DXGI, the windowing system
+interface, the threaded loop is prone to deadlocks when multiple QQuickWindow
+or QQuickView instances are shown. Therefore the default is the single-threaded
+loop for the time being. This means that with the D3D12 backend applications
+are expected to move their work from the main (GUI) thread out to worker
+threads, instead of expecting Qt to keep the GUI thread responsive and suitable
+for heavy, blocking operations.
+
+See the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph page} for more
+information on render loops and
+\l{https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx#multithreading_and_dxgi}{the
+MSDN page for DXGI} regarding the issues with multithreading.
+
+\section2 Renderer
+
+The scenegraph renderer in the D3D12 adaptation does not currently perform any
+batching. This is less of an issue, unlike OpenGL, because state changes are
+not presenting any problems in the first place. The simpler renderer logic can
+also lead to lower CPU overhead in some cases. The trade-offs between the
+various approaches are currently under research.
+
+\section2 Shader Effects
+
+The ShaderEffect QML type is fully functional with the D3D12 adaptation as well.
+However, the interpretation of the fragmentShader and vertexShader properties is
+different than with OpenGL.
+
+With D3D12, these strings can either be an URL for a local file or a file in
+the resource system, or a HLSL source string. The former indicates that the
+file in question contains pre-compiled D3D shader bytecode generated by the
+\c fxc tool, or, alternatively, HLSL source code. The type of the file is detected
+automatically. This means that the D3D12 backend supports all options from
+GraphicsInfo.shaderCompilationType and GraphicsInfo.shaderSourceType.
+
+Unlike OpenGL, there is a QFileSelector with the extra selector \c hlsl used
+whenever opening a file. This allows easy creation of ShaderEffect items that
+are functional across both backends, for example by placing the GLSL source
+code into \c{shaders/effect.frag}, the HLSL source code or - preferably -
+pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing
+\c{fragmentShader: "qrc:shaders/effect.frag"} in QML.
+
+See the ShaderEffect documentation for more details.
+
+\section2 Multisample Render Targets
+
+The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow
+or QQuickView (or set via QSurfaceFormat::setDefaultFormat()), with two
+exceptions: QSurfaceFormat::samples() and QSurfaceFormat::alphaBufferSize() are
+still taken into account. When the samples value is greater than 1, multisample
+offscreen render targets will be created with the specified sample count and a
+quality of the maximum supported quality level. The backend automatically
+performs resolving into the non-multisample swapchain buffers after each frame.
+
+\section2 Semi-transparent windows
+
+When the alpha channel is enabled either via
+QQuickWindow::setDefaultAlphaBuffer() or by setting alphaBufferSize to a
+non-zero value in the window's QSurfaceFormat or in the global format managed
+by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a
+swapchain for composition and go through DirectComposition since the flip model
+swapchain (which is mandatory) would not support transparency otherwise.
+
+It is therefore important not to unneccessarily request an alpha channel. When
+the alphaBufferSize is 0 or the default -1, all these extra steps can be
+avoided and the traditional window-based swapchain is sufficient.
+
+This is not relevant on WinRT because there the backend always uses a
+composition swapchain which is associated with the ISwapChainPanel that backs
+QWindow on that platform.
+
+\section2 Mipmaps
+
+Mipmap generation is supported and handled transparently to the applications
+via a built-in compute shader, but is experimental and only supports
+power-of-two images at the moment. Textures of other size will work too, but
+this involves a QImage-based scaling on the CPU first. Therefore avoid enabling
+mipmapping for NPOT images whenever possible.
+
+\section2 Image formats
+
+When creating textures via the C++ scenegraph APIs like
+QQuickWindow::createTextureFromImage(), 32-bit formats will not involve any
+conversion, they will map directly to the corresponding \c{R8G8B8A8_UNORM} or
+\c{B8G8R8A8_UNORM} format. Everything else will trigger a QImage-based format
+conversion on the CPU first.
+
+\section2 Unsupported Features
+
+Particles and some other OpenGL-dependent utilities, like
+QQuickFramebufferObject, are not currently supported.
+
+Like with the \l{qtquick-visualcanvas-adaptations-software.html}{Software
+adaptation}, text is always rendered using the native method. Distance
+field-based text rendering is not currently implemented.
+
+The shader sources in the \l {Qt Graphical Effects} module have not been ported
+to any format other than the OpenGL 2.0 compatible one, meaning the QML types
+provided by that module are not currently functional with the D3D12 backend.
+
+Texture atlases are not currently in use.
+
+The renderer may lack support for certain minor features, for example drawing
+points and lines with a width other than 1.
+
+Custom Qt Quick items using custom scenegraph nodes can be problematic.
+Materials are inherently tied to the graphics API. Therefore only items using
+the utility rectangle and image nodes are functional across all adaptations.
+
+QQuickWidget and its underlying OpenGL-based compositing architecture is not
+supported. If mixing with QWidget-based user interfaces is desired, use
+QWidget::createWindowContainer() to embed the native window of the QQuickWindow
+or QQuickView.
+
+Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with
+the D3D12 adaptation at the moment.
+
+\section2 Related APIs
+
+To integrate custom Direct3D 12 rendering, use QSGRenderNode in combination
+with QSGRendererInterface. This approach does not rely on OpenGL contexts or
+API specifics like framebuffers, and allows exposing the graphics device and
+command buffer from the adaptation. It is not necessarily suitable for easy
+integration of all types of content, in particular true 3D, so it will likely
+get complemented by an alternative to QQuickFramebufferObject in future
+releases.
+
+To perform runtime decisions based on the adaptation in use, use
+QSGRendererInterface from C++ and GraphicsInfo from QML. They can also be used
+to check the level of shader support (shading language, compilation approach).
+
+When creating custom items, use the new QSGRectangleNode and QSGImageNode
+classes. These replace the now deprecated QSGSimpleRectNode and
+QSGSimpleTextureNode. Unlike their predecessors, the new classes are
+interfaces, and implementations are created via the factory functions
+QQuickWindow::createRectangleNode() and QQuickWindow::createImageNode().
+
+\section2 Advanced Configuration
+
+The D3D12 adaptation can keep multiple frames in flight, similarly to modern
+game engines. This is somewhat different from the traditional render - swap -
+wait for vsync model and allows better GPU utilization at the expense of higher
+resource usage. This means that the renderer will be a number of frames ahead
+of what is displayed on the screen.
+
+For a discussion of flip model swap chains and the typical configuration
+parameters, refer to
+\l{https://software.intel.com/en-us/articles/sample-application-for-direct3d-12-flip-model-swap-chains}{this
+article}.
+
+Vertical synchronization is always enabled, meaning Present() is invoked with
+an interval of 1.
+
+The configuration can be changed by setting the following environment variables:
+
+\list
+
+\li \c{QT_D3D_BUFFER_COUNT} - The number of swap chain buffers in range 2 - 4.
+The default value is 3.
+
+\li \c{QT_D3D_FRAME_COUNT} - The number of frames prepared without blocking in
+range 1 - 4. Note that Present will start blocking after queuing 3 frames
+(regardless of \c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use.
+Note that every additional frame increases GPU resource usage since geometry
+and constant buffer data will have to be duplicated, and involves more
+bookkeeping on the CPU side. The default value is 2.
+
+\li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY} - When set to a value between 1
+and 16, the frame latency is set to the specified value. This changes the limit
+for Present() and will trigger a wait for an available swap chain buffer when
+beginning each frame. Refer to the article above for a detailed discussion.
+This is considered experimental for now and the default value is 0 (disabled).
+
+\li \c{QT_D3D_BLOCKING_PRESENT} - When set to a non-zero value, there will be
+CPU-side wait for the GPU to finish its work after each call to Present. This
+effectively kills all parallelism but makes the behavior resemble the
+traditional swap-blocks-for-vsync model, and can therefore be useful in some
+special cases. This is not the same as setting the frame count to 1 because
+that still avoids blocking after Present, and may block only when starting to
+prepare the next frame (or may not block at all depending on the time gap
+between the frames). By default blocking present is disabled.
+
+\endlist
*/
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index ea62603f06..2e41c85873 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -186,8 +186,8 @@ dedicated thread. Qt attempts to choose a suitable loop based on the
platform and possibly the graphics drivers in use. When this is not
satisfactory, or for testing purposes, the environment variable
\c QSG_RENDER_LOOP can be used to force the usage of a given loop. To
-verify which render loop is in use, launch the application with
-\c QSG_INFO set to \c 1.
+verify which render loop is in use, enable the \c qt.scenegraph.general
+\l {QLoggingCategory}{logging category}.
\note The \c threaded and \c windows render loops rely on the OpenGL
implementation for throttling by requesting a swap interval of 1. Some
@@ -220,7 +220,7 @@ user input. An event is posted to the render thread to initiate a new
frame.
\li The render thread prepares to draw a new frame and makes the
-OpenGL context current and initiates a blocks on the GUI thread.
+OpenGL context current and initiates a block on the GUI thread.
\li While the render thread is preparing the new frame, the GUI thread
calls QQuickItem::updatePolish() to do final touch-up of items before
@@ -269,7 +269,7 @@ animations, process events, etc.
\endlist
The threaded renderer is currently used by default on Windows with
-opengl32.dll, Linux with non-Mesa based drivers, OS X, mobile
+opengl32.dll, Linux with non-Mesa based drivers, \macos, mobile
platforms, and Embedded Linux with EGLFS but this is subject to
change. It is possible to force use of the threaded renderer by
setting \c {QSG_RENDER_LOOP=threaded} in the environment.
@@ -374,7 +374,7 @@ addition to being helpful to Qt contributors.
\li \c {qt.scenegraph.time.glyph} - logs the time spent preparing distance field glyphs
-\li \c {qt.scenegraph.info} - logs general information about various parts of the scene graph and the graphics stack
+\li \c {qt.scenegraph.general} - logs general information about various parts of the scene graph and the graphics stack
\li \c {qt.scenegraph.renderloop} - creates a detailed log of the various stages involved in rendering. This log mode is primarily useful for developers working on Qt.
diff --git a/src/quick/doc/src/examples.qdoc b/src/quick/doc/src/examples.qdoc
index e69c2f6551..e41b472ee1 100644
--- a/src/quick/doc/src/examples.qdoc
+++ b/src/quick/doc/src/examples.qdoc
@@ -135,7 +135,7 @@ Creator.
\div {class="doc-column"}
\b{Layouts and Views}
\list
- \li \l{Qt Quick Controls - Basic Layouts Example}{Basic Layouts}
+ \li \l{Qt Quick Layouts - Basic Example}
\li \l{Qt Quick Examples - Positioners}{Positioners}
\li \l{Qt Quick Examples - Views}{Views}
\li \l{Qt Quick Examples - Window and Screen}{Windows and Screen}
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index 6e6e66e026..2406722dbc 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -100,9 +100,9 @@ available when you import \c QtQuick.
\li By a hexadecimal triplet or quad in the form \c "#RRGGBB" and \c "#AARRGGBB"
respectively. For example, the color red corresponds to a triplet of \c "#FF0000"
and a slightly transparent blue to a quad of \c "#800000FF".
- \li Using the \l{QtQml::Qt::rgba()}{Qt.rgba()}, \l{QtQml::Qt::hsla()}{Qt.hsla()},
- \l{QtQml::Qt::darker()}{Qt.darker()}, \l{QtQml::Qt::lighter()}{Qt.lighter()} or
- \l{QtQml::Qt::tint()}{Qt.tint()} functions.
+ \li Using the \l{QtQml::Qt::rgba()}{Qt.rgba()}, \l{QtQml::Qt::hsva()}{Qt.hsva()},
+ \l{QtQml::Qt::hsla()}{Qt.hsla()}, \l{QtQml::Qt::darker()}{Qt.darker()},
+ \l{QtQml::Qt::lighter()}{Qt.lighter()} or \l{QtQml::Qt::tint()}{Qt.tint()} functions.
\endlist
Example:
@@ -112,8 +112,11 @@ available when you import \c QtQuick.
\enddiv
\snippet qml/colors.qml colors
- Additionally, a color type has \c r, \c g, \c b and \c a properties that refer to the
- red, green, blue and alpha values of the color, respectively:
+ A color type has \c r, \c g, \c b and \c a properties that refer to the red,
+ green, blue and alpha values of the color, respectively. Additionally it has
+ \c hsvHue, \c hsvSaturation, \c hsvValue and \c hslHue, \c hslSaturation,
+ \c hslLightness properties, which allow access to color values in HSV and HSL
+ color models accordingly:
\qml
Text {
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 7ffb715346..368a2b78d1 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -174,7 +174,7 @@ public:
QUrl baseUrl;
QMap<int, QV4::PersistentValue> animationCallbacks;
mutable QQuickCanvasTextureProvider *textureProvider;
- QSGImageNode *node;
+ QSGInternalImageNode *node;
QSGTexture *nodeTexture;
};
@@ -679,10 +679,14 @@ void QQuickCanvasItem::itemChange(QQuickItem::ItemChange change, const QQuickIte
QSGRenderContext *context = QQuickWindowPrivate::get(d->window)->context;
// Rendering to FramebufferObject needs a valid OpenGL context.
- if (context != 0 && (d->renderTarget != FramebufferObject || context->isValid()))
- sceneGraphInitialized();
- else
+ if (context != 0 && (d->renderTarget != FramebufferObject || context->isValid())) {
+ // Defer the call. In some (arguably incorrect) cases we get here due
+ // to ItemSceneChange with the user-supplied property values not yet
+ // set. Work this around by a deferred invoke. (QTBUG-49692)
+ QMetaObject::invokeMethod(this, "sceneGraphInitialized", Qt::QueuedConnection);
+ } else {
connect(d->window, SIGNAL(sceneGraphInitialized()), SLOT(sceneGraphInitialized()));
+ }
}
void QQuickCanvasItem::updatePolish()
@@ -704,8 +708,8 @@ void QQuickCanvasItem::updatePolish()
for (auto it = animationCallbacks.cbegin(), end = animationCallbacks.cend(); it != end; ++it) {
QV4::ScopedFunctionObject f(scope, it.value().value());
- callData->args[0] = QV4::Primitive::fromUInt32(QDateTime::currentDateTimeUtc().toTime_t());
- f->call(callData);
+ callData->args[0] = QV4::Primitive::fromUInt32(QDateTime::currentMSecsSinceEpoch() / 1000);
+ f->call(scope, callData);
}
}
else {
@@ -739,9 +743,9 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
return 0;
}
- QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
+ QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
- node = QQuickWindowPrivate::get(window())->context->sceneGraphContext()->createImageNode();
+ node = QQuickWindowPrivate::get(window())->context->sceneGraphContext()->createInternalImageNode();
d->node = node;
}
@@ -1091,6 +1095,23 @@ QImage QQuickCanvasItem::toImage(const QRectF& rect) const
return QImage();
}
+static const char* mimeToType(const QString &mime)
+{
+ if (mime == QLatin1String("image/png"))
+ return "PNG";
+ else if (mime == QLatin1String("image/bmp"))
+ return "BMP";
+ else if (mime == QLatin1String("image/jpeg"))
+ return "JPEG";
+ else if (mime == QLatin1String("image/x-portable-pixmap"))
+ return "PPM";
+ else if (mime == QLatin1String("image/tiff"))
+ return "TIFF";
+ else if (mime == QLatin1String("image/xpm"))
+ return "XPM";
+ return nullptr;
+}
+
/*!
\qmlmethod string QtQuick::Canvas::toDataURL(string mimeType)
@@ -1108,27 +1129,14 @@ QString QQuickCanvasItem::toDataURL(const QString& mimeType) const
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
- QString mime = mimeType.toLower();
- QString type;
- if (mime == QLatin1String("image/png")) {
- type = QStringLiteral("PNG");
- } else if (mime == QLatin1String("image/bmp"))
- type = QStringLiteral("BMP");
- else if (mime == QLatin1String("image/jpeg"))
- type = QStringLiteral("JPEG");
- else if (mime == QLatin1String("image/x-portable-pixmap"))
- type = QStringLiteral("PPM");
- else if (mime == QLatin1String("image/tiff"))
- type = QStringLiteral("TIFF");
- else if (mime == QLatin1String("image/xpm"))
- type = QStringLiteral("XPM");
- else
+ const QString mime = mimeType.toLower();
+ const char* type = mimeToType(mime);
+ if (!type)
return QStringLiteral("data:,");
- image.save(&buffer, type.toLatin1());
+ image.save(&buffer, type);
buffer.close();
- QString dataUrl = QStringLiteral("data:%1;base64,%2");
- return dataUrl.arg(mime).arg(QLatin1String(ba.toBase64().constData()));
+ return QLatin1String("data:") + mime + QLatin1String(";base64,") + QLatin1String(ba.toBase64().constData());
}
return QStringLiteral("data:,");
}
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 4f94393a45..1948a57e58 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -191,7 +191,7 @@ private:
Q_INVOKABLE void delayedCreate();
bool createContext(const QString &contextType);
void initializeContext(QQuickCanvasContext *context, const QVariantMap &args = QVariantMap());
- QRect tiledRect(const QRectF &window, const QSize &tileSize);
+ static QRect tiledRect(const QRectF &window, const QSize &tileSize);
bool isPaintConnected();
};
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index caec6cb36a..c26f641754 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -794,7 +794,7 @@ static QPainter::CompositionMode qt_composite_mode_from_string(const QString &co
} else if (compositeOperator == QLatin1String("destination-over")) {
return QPainter::CompositionMode_DestinationOver;
} else if (compositeOperator == QLatin1String("lighter")) {
- return QPainter::CompositionMode_Lighten;
+ return QPainter::CompositionMode_Plus;
} else if (compositeOperator == QLatin1String("copy")) {
return QPainter::CompositionMode_Source;
} else if (compositeOperator == QLatin1String("xor")) {
@@ -857,7 +857,7 @@ static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
case QPainter::CompositionMode_Xor:
return QStringLiteral("xor");
case QPainter::CompositionMode_Plus:
- return QStringLiteral("plus");
+ return QStringLiteral("lighter");
case QPainter::CompositionMode_Multiply:
return QStringLiteral("qt-multiply");
case QPainter::CompositionMode_Screen:
@@ -2674,15 +2674,15 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx
QString textAlign = s->toQString();
QQuickContext2D::TextAlignType ta;
- if (textAlign == QStringLiteral("start"))
+ if (textAlign == QLatin1String("start"))
ta = QQuickContext2D::Start;
- else if (textAlign == QStringLiteral("end"))
+ else if (textAlign == QLatin1String("end"))
ta = QQuickContext2D::End;
- else if (textAlign == QStringLiteral("left"))
+ else if (textAlign == QLatin1String("left"))
ta = QQuickContext2D::Left;
- else if (textAlign == QStringLiteral("right"))
+ else if (textAlign == QLatin1String("right"))
ta = QQuickContext2D::Right;
- else if (textAlign == QStringLiteral("center"))
+ else if (textAlign == QLatin1String("center"))
ta = QQuickContext2D::Center;
else
return QV4::Encode::undefined();
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index cfb62ee052..2e900a49af 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -126,8 +126,8 @@ public:
struct State {
State()
- : strokeStyle(QColor("#000000"))
- , fillStyle(QColor("#000000"))
+ : strokeStyle(QColor(Qt::black))
+ , fillStyle(QColor(Qt::black))
, fillPatternRepeatX(false)
, fillPatternRepeatY(false)
, strokePatternRepeatX(false)
@@ -181,17 +181,17 @@ public:
QQuickContext2D(QObject *parent = 0);
~QQuickContext2D();
- QStringList contextNames() const;
- void init(QQuickCanvasItem *canvasItem, const QVariantMap &args);
- void prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing);
- void flush();
+ QStringList contextNames() const override;
+ void init(QQuickCanvasItem *canvasItem, const QVariantMap &args) override;
+ void prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing) override;
+ void flush() override;
void sync();
QThread *thread() const { return m_thread; }
QQuickContext2DTexture *texture() const;
- QImage toImage(const QRectF& bounds);
+ QImage toImage(const QRectF& bounds) override;
- QV4::ReturnedValue v4value() const;
- void setV4Engine(QV4::ExecutionEngine *eng);
+ QV4::ReturnedValue v4value() const override;
+ void setV4Engine(QV4::ExecutionEngine *eng) override;
QQuickCanvasItem* canvas() const { return m_canvas; }
QQuickContext2DCommandBuffer* buffer() const { return m_buffer; }
@@ -240,8 +240,8 @@ public:
QPainterPath createTextGlyphs(qreal x, qreal y, const QString& text);
QQmlRefPointer<QQuickCanvasPixmap> createPixmap(const QUrl& url);
- QOpenGLContext *glContext() { return m_glContext; }
- QSurface *surface() { return m_surface.data(); }
+ QOpenGLContext *glContext() const { return m_glContext; }
+ QSurface *surface() const { return m_surface.data(); }
void setGrabbedImage(const QImage& grab);
State state;
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
index a82b88f36f..771f941564 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
@@ -67,10 +67,10 @@ public:
void reset();
void clear();
- inline int size() {return commands.size();}
+ inline int size() const { return commands.size(); }
inline bool isEmpty() const {return commands.isEmpty(); }
inline bool hasNext() const {return cmdIdx < commands.size(); }
- inline QQuickContext2D::PaintCommand takeNextCommand() { return commands[cmdIdx++]; }
+ inline QQuickContext2D::PaintCommand takeNextCommand() { return commands.at(cmdIdx++); }
inline qreal takeGlobalAlpha() { return takeReal(); }
inline QPainter::CompositionMode takeGlobalCompositeOperation(){ return static_cast<QPainter::CompositionMode>(takeInt()); }
@@ -227,25 +227,25 @@ public:
colors << color;
}
- inline QTransform takeMatrix() { return matrixes[matrixIdx++]; }
+ inline QTransform takeMatrix() { return matrixes.at(matrixIdx++); }
- inline QRectF takeRect() { return rects[rectIdx++]; }
+ inline QRectF takeRect() { return rects.at(rectIdx++); }
- inline QPainterPath takePath() { return pathes[pathIdx++]; }
+ inline QPainterPath takePath() { return pathes.at(pathIdx++); }
- inline const QImage& takeImage() { return images[imageIdx++]; }
- inline QQmlRefPointer<QQuickCanvasPixmap> takePixmap() { return pixmaps[pixmapIdx++]; }
+ inline const QImage& takeImage() { return images.at(imageIdx++); }
+ inline QQmlRefPointer<QQuickCanvasPixmap> takePixmap() { return pixmaps.at(pixmapIdx++); }
- inline int takeInt() { return ints[intIdx++]; }
- inline bool takeBool() {return bools[boolIdx++]; }
- inline qreal takeReal() { return reals[realIdx++]; }
- inline QColor takeColor() { return colors[colorIdx++]; }
- inline QBrush takeBrush() { return brushes[brushIdx++]; }
+ inline int takeInt() { return ints.at(intIdx++); }
+ inline bool takeBool() {return bools.at(boolIdx++); }
+ inline qreal takeReal() { return reals.at(realIdx++); }
+ inline QColor takeColor() { return colors.at(colorIdx++); }
+ inline QBrush takeBrush() { return brushes.at(brushIdx++); }
void replay(QPainter* painter, QQuickContext2D::State& state, const QVector2D &scaleFactor);
private:
- QPen makePen(const QQuickContext2D::State& state);
+ static QPen makePen(const QQuickContext2D::State& state);
void setPainterState(QPainter* painter, const QQuickContext2D::State& state, const QPen& pen);
int cmdIdx;
int intIdx;
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index ed38382892..d7202ba68f 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -120,7 +120,7 @@ public:
// Called during sync() on the scene graph thread while GUI is blocked.
virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window) = 0;
- bool event(QEvent *e);
+ bool event(QEvent *e) override;
#ifndef QT_NO_OPENGL
void initializeOpenGL(QOpenGLContext *gl, QOffscreenSurface *s) {
m_gl = gl;
@@ -221,17 +221,17 @@ public:
QQuickContext2DImageTexture();
~QQuickContext2DImageTexture();
- virtual QQuickCanvasItem::RenderTarget renderTarget() const;
+ QQuickCanvasItem::RenderTarget renderTarget() const override;
- virtual QQuickContext2DTile* createTile() const;
- virtual QPaintDevice* beginPainting();
- virtual void endPainting();
- virtual void compositeTile(QQuickContext2DTile* tile);
+ QQuickContext2DTile* createTile() const override;
+ QPaintDevice* beginPainting() override;
+ void endPainting() override;
+ void compositeTile(QQuickContext2DTile* tile) override;
- virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window);
+ QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window) override;
public Q_SLOTS:
- virtual void grabImage(const QRectF& region = QRectF());
+ void grabImage(const QRectF& region = QRectF()) override;
private:
QImage m_image;
diff --git a/src/quick/items/context2d/qquickcontext2dtile_p.h b/src/quick/items/context2d/qquickcontext2dtile_p.h
index a87202daae..160d51ec67 100644
--- a/src/quick/items/context2d/qquickcontext2dtile_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtile_p.h
@@ -89,12 +89,12 @@ class QQuickContext2DFBOTile : public QQuickContext2DTile
public:
QQuickContext2DFBOTile();
~QQuickContext2DFBOTile();
- virtual void setRect(const QRect& r);
+ virtual void setRect(const QRect& r) override;
QOpenGLFramebufferObject* fbo() const {return m_fbo;}
- void drawFinished();
+ void drawFinished() override;
protected:
- void aboutToDraw();
+ void aboutToDraw() override;
private:
@@ -106,7 +106,7 @@ class QQuickContext2DImageTile : public QQuickContext2DTile
public:
QQuickContext2DImageTile();
~QQuickContext2DImageTile();
- void setRect(const QRect& r);
+ void setRect(const QRect& r) override;
const QImage& image() const {return m_image;}
private:
QImage m_image;
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 0c7dc97a2c..d91705451e 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -79,7 +79,13 @@ HEADERS += \
$$PWD/qquickrendercontrol.h \
$$PWD/qquickrendercontrol_p.h \
$$PWD/qquickgraphicsinfo_p.h \
- $$PWD/qquickitemgrabresult.h
+ $$PWD/qquickitemgrabresult.h \
+ $$PWD/qquickspriteengine_p.h \
+ $$PWD/qquicksprite_p.h \
+ $$PWD/qquickspritesequence_p.h \
+ $$PWD/qquickanimatedsprite_p.h \
+ $$PWD/qquickanimatedsprite_p_p.h \
+ $$PWD/qquickspritesequence_p_p.h
SOURCES += \
$$PWD/qquickevents.cpp \
@@ -134,39 +140,31 @@ SOURCES += \
$$PWD/qquickgenericshadereffect.cpp \
$$PWD/qquickrendercontrol.cpp \
$$PWD/qquickgraphicsinfo.cpp \
- $$PWD/qquickitemgrabresult.cpp
+ $$PWD/qquickitemgrabresult.cpp \
+ $$PWD/qquickspriteengine.cpp \
+ $$PWD/qquicksprite.cpp \
+ $$PWD/qquickspritesequence.cpp \
+ $$PWD/qquickanimatedsprite.cpp
# Items that depend on OpenGL Renderer
-contains(QT_CONFIG, opengl(es1|es2)?) {
+qtConfig(opengl(es1|es2)?) {
SOURCES += \
$$PWD/qquickopenglinfo.cpp \
$$PWD/qquickopenglshadereffect.cpp \
$$PWD/qquickopenglshadereffectnode.cpp \
- $$PWD/qquickframebufferobject.cpp \
- $$PWD/qquickspriteengine.cpp \
- $$PWD/qquicksprite.cpp \
- $$PWD/qquickspritesequence.cpp \
- $$PWD/qquickanimatedsprite.cpp
+ $$PWD/qquickframebufferobject.cpp
HEADERS += \
$$PWD/qquickopenglinfo_p.h \
- $$PWD/qquickspriteengine_p.h \
- $$PWD/qquicksprite_p.h \
- $$PWD/qquickspritesequence_p.h \
- $$PWD/qquickanimatedsprite_p.h \
$$PWD/qquickopenglshadereffect_p.h \
$$PWD/qquickopenglshadereffectnode_p.h \
$$PWD/qquickframebufferobject.h
OTHER_FILES += \
- $$PWD/shaders/sprite.vert \
- $$PWD/shaders/sprite.frag \
$$PWD/shaders/shadereffect.vert \
$$PWD/shaders/shadereffect.frag \
$$PWD/shaders/shadereffectfallback.vert \
$$PWD/shaders/shadereffectfallback.frag \
- $$PWD/shaders/sprite_core.vert \
- $$PWD/shaders/sprite_core.frag \
$$PWD/shaders/shadereffect_core.vert \
$$PWD/shaders/shadereffect_core.frag \
$$PWD/shaders/shadereffectfallback_core.vert \
diff --git a/src/quick/items/items.qrc b/src/quick/items/items.qrc
index 99f9b5224f..6aaf757c29 100644
--- a/src/quick/items/items.qrc
+++ b/src/quick/items/items.qrc
@@ -1,7 +1,5 @@
<RCC>
<qresource prefix="/qt-project.org/items">
- <file>shaders/sprite.frag</file>
- <file>shaders/sprite.vert</file>
<file>shaders/shadereffect.vert</file>
<file>shaders/shadereffect.frag</file>
<file>shaders/shadereffectfallback.frag</file>
@@ -10,7 +8,5 @@
<file>shaders/shadereffect_core.vert</file>
<file>shaders/shadereffectfallback_core.frag</file>
<file>shaders/shadereffectfallback_core.vert</file>
- <file>shaders/sprite_core.frag</file>
- <file>shaders/sprite_core.vert</file>
</qresource>
</RCC>
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 2c209ae664..7054d9d9c9 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -203,7 +203,7 @@ public:
return object;
}
- QAccessible::State state() { return m_state; }
+ QAccessible::State state() const { return m_state; }
bool ignored() const;
bool doAction(const QString &actionName);
void availableActions(QStringList *actions) const;
diff --git a/src/quick/items/qquickanchors.cpp b/src/quick/items/qquickanchors.cpp
index 4cbd41106e..a7a4a2b882 100644
--- a/src/quick/items/qquickanchors.cpp
+++ b/src/quick/items/qquickanchors.cpp
@@ -285,26 +285,26 @@ void QQuickAnchorsPrivate::clearItem(QQuickItem *item)
}
}
-int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
+QQuickGeometryChange QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem) const
{
- QQuickItemPrivate::GeometryChangeTypes dependency = QQuickItemPrivate::NoChange;
+ QQuickGeometryChange dependency;
if (!controlItem || inDestructor)
return dependency;
if (fill == controlItem) {
if (controlItem == readParentItem(item))
- dependency |= QQuickItemPrivate::SizeChange;
+ dependency.setSizeChange(true);
else //sibling
- dependency |= QQuickItemPrivate::GeometryChange;
+ dependency.setAllChanged(true);
return dependency; //exit early
}
if (centerIn == controlItem) {
if (controlItem == readParentItem(item))
- dependency |= QQuickItemPrivate::SizeChange;
+ dependency.setSizeChange(true);
else //sibling
- dependency |= QQuickItemPrivate::GeometryChange;
+ dependency.setAllChanged(true);
return dependency; //exit early
}
@@ -312,9 +312,9 @@ int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
(usedAnchors & QQuickAnchors::RightAnchor && rightAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::HCenterAnchor && hCenterAnchorItem == controlItem)) {
if (controlItem == readParentItem(item))
- dependency |= QQuickItemPrivate::WidthChange;
+ dependency.setWidthChange(true);
else //sibling
- dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::XChange | QQuickItemPrivate::WidthChange);
+ dependency.setHorizontalChange(true);
}
if ((usedAnchors & QQuickAnchors::TopAnchor && topAnchorItem == controlItem) ||
@@ -322,9 +322,9 @@ int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
(usedAnchors & QQuickAnchors::VCenterAnchor && vCenterAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::BaselineAnchor && baselineAnchorItem == controlItem)) {
if (controlItem == readParentItem(item))
- dependency |= QQuickItemPrivate::HeightChange;
+ dependency.setHeightChange(true);
else //sibling
- dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::YChange | QQuickItemPrivate::HeightChange);
+ dependency.setVerticalChange(true);
}
return dependency;
@@ -336,7 +336,7 @@ void QQuickAnchorsPrivate::addDepend(QQuickItem *item)
return;
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- p->updateOrAddGeometryChangeListener(this, QFlags<QQuickItemPrivate::GeometryChangeType>(calculateDependency(item)));
+ p->updateOrAddGeometryChangeListener(this, calculateDependency(item));
}
void QQuickAnchorsPrivate::remDepend(QQuickItem *item)
@@ -345,7 +345,7 @@ void QQuickAnchorsPrivate::remDepend(QQuickItem *item)
return;
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- p->updateOrRemoveGeometryChangeListener(this, QFlags<QQuickItemPrivate::GeometryChangeType>(calculateDependency(item)));
+ p->updateOrRemoveGeometryChangeListener(this, calculateDependency(item));
}
bool QQuickAnchors::mirrored()
@@ -492,7 +492,7 @@ void QQuickAnchorsPrivate::update()
}
}
-void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newG, const QRectF &oldG)
+void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &)
{
if (!isItemComplete())
return;
@@ -502,11 +502,9 @@ void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newG,
} else if (centerIn) {
centerInChanged();
} else {
- if ((usedAnchors & QQuickAnchors::Horizontal_Mask)
- && (newG.x() != oldG.x() || newG.width() != oldG.width()))
+ if ((usedAnchors & QQuickAnchors::Horizontal_Mask) && change.horizontalChange())
updateHorizontalAnchors();
- if ((usedAnchors & QQuickAnchors::Vertical_Mask)
- && (newG.y() != oldG.y() || newG.height() != oldG.height()))
+ if ((usedAnchors & QQuickAnchors::Vertical_Mask) && change.verticalChange())
updateVerticalAnchors();
}
}
@@ -590,7 +588,7 @@ bool QQuickAnchorsPrivate::calcStretch(QQuickItem *edge1Item,
qreal offset1,
qreal offset2,
QQuickAnchors::Anchor line,
- qreal &stretch)
+ qreal &stretch) const
{
bool edge1IsParent = (edge1Item == readParentItem(item));
bool edge2IsParent = (edge2Item == readParentItem(item));
diff --git a/src/quick/items/qquickanchors_p_p.h b/src/quick/items/qquickanchors_p_p.h
index da659946c0..221b4ccb40 100644
--- a/src/quick/items/qquickanchors_p_p.h
+++ b/src/quick/items/qquickanchors_p_p.h
@@ -124,7 +124,7 @@ public:
void clearItem(QQuickItem *);
- int calculateDependency(QQuickItem *);
+ QQuickGeometryChange calculateDependency(QQuickItem *) const;
void addDepend(QQuickItem *);
void remDepend(QQuickItem *);
bool isItemComplete() const;
@@ -141,7 +141,7 @@ public:
void updateMe();
// QQuickItemGeometryListener interface
- void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
QQuickAnchorsPrivate *anchorPrivate() Q_DECL_OVERRIDE { return this; }
bool checkHValid() const;
@@ -150,7 +150,7 @@ public:
bool checkVAnchorValid(QQuickAnchorLine anchor) const;
bool calcStretch(QQuickItem *edge1Item, QQuickAnchors::Anchor edge1Line,
QQuickItem *edge2Item, QQuickAnchors::Anchor edge2Line,
- qreal offset1, qreal offset2, QQuickAnchors::Anchor line, qreal &stretch);
+ qreal offset1, qreal offset2, QQuickAnchors::Anchor line, qreal &stretch) const;
bool isMirrored() const;
void updateHorizontalAnchors();
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 77c7ae106b..991ca8519f 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qquickanimatedsprite_p.h"
+#include "qquickanimatedsprite_p_p.h"
#include "qquicksprite_p.h"
#include "qquickspriteengine_p.h"
#include <QtQuick/private/qsgcontext_p.h>
@@ -55,111 +56,6 @@
QT_BEGIN_NAMESPACE
-class QQuickAnimatedSpriteMaterial : public QSGMaterial
-{
-public:
- QQuickAnimatedSpriteMaterial();
- ~QQuickAnimatedSpriteMaterial();
- QSGMaterialType *type() const Q_DECL_OVERRIDE { static QSGMaterialType type; return &type; }
- QSGMaterialShader *createShader() const Q_DECL_OVERRIDE;
- int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE
- {
- return this - static_cast<const QQuickAnimatedSpriteMaterial *>(other);
- }
-
- QSGTexture *texture;
-
- float animT;
- float animX1;
- float animY1;
- float animX2;
- float animY2;
- float animW;
- float animH;
-};
-
-QQuickAnimatedSpriteMaterial::QQuickAnimatedSpriteMaterial()
- : texture(0)
- , animT(0.0f)
- , animX1(0.0f)
- , animY1(0.0f)
- , animX2(0.0f)
- , animY2(0.0f)
- , animW(1.0f)
- , animH(1.0f)
-{
- setFlag(Blending, true);
-}
-
-QQuickAnimatedSpriteMaterial::~QQuickAnimatedSpriteMaterial()
-{
- delete texture;
-}
-
-class AnimatedSpriteMaterialData : public QSGMaterialShader
-{
-public:
- AnimatedSpriteMaterialData()
- : QSGMaterialShader()
- {
- setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/items/shaders/sprite.vert"));
- setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/items/shaders/sprite.frag"));
- }
-
- void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE
- {
- QQuickAnimatedSpriteMaterial *m = static_cast<QQuickAnimatedSpriteMaterial *>(newEffect);
- m->texture->bind();
-
- program()->setUniformValue(m_opacity_id, state.opacity());
- program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT);
- program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2);
-
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrix_id, state.combinedMatrix());
- }
-
- void initialize() Q_DECL_OVERRIDE {
- m_matrix_id = program()->uniformLocation("qt_Matrix");
- m_opacity_id = program()->uniformLocation("qt_Opacity");
- m_animData_id = program()->uniformLocation("animData");
- m_animPos_id = program()->uniformLocation("animPos");
- }
-
- char const *const *attributeNames() const Q_DECL_OVERRIDE {
- static const char *attr[] = {
- "vPos",
- "vTex",
- 0
- };
- return attr;
- }
-
- int m_matrix_id;
- int m_opacity_id;
- int m_animData_id;
- int m_animPos_id;
-};
-
-QSGMaterialShader *QQuickAnimatedSpriteMaterial::createShader() const
-{
- return new AnimatedSpriteMaterialData;
-}
-
-struct AnimatedSpriteVertex {
- float x;
- float y;
- float tx;
- float ty;
-};
-
-struct AnimatedSpriteVertices {
- AnimatedSpriteVertex v1;
- AnimatedSpriteVertex v2;
- AnimatedSpriteVertex v3;
- AnimatedSpriteVertex v4;
-};
-
/*!
\qmltype AnimatedSprite
\instantiates QQuickAnimatedSprite
@@ -315,18 +211,11 @@ struct AnimatedSpriteVertices {
//TODO: Implicitly size element to size of sprite
QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) :
- QQuickItem(parent)
- , m_sprite(new QQuickSprite(this))
- , m_spriteEngine(0)
- , m_curFrame(0)
- , m_pleaseReset(false)
- , m_running(true)
- , m_paused(false)
- , m_interpolate(true)
- , m_loops(-1)
- , m_curLoop(0)
- , m_pauseOffset(0)
+ QQuickItem(*(new QQuickAnimatedSpritePrivate), parent)
{
+ Q_D(QQuickAnimatedSprite);
+ d->m_sprite = new QQuickSprite(this);
+
setFlag(ItemHasContents);
connect(this, SIGNAL(widthChanged()),
this, SLOT(reset()));
@@ -334,6 +223,96 @@ QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) :
this, SLOT(reset()));
}
+bool QQuickAnimatedSprite::running() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_running;
+}
+
+bool QQuickAnimatedSprite::interpolate() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_interpolate;
+}
+
+QUrl QQuickAnimatedSprite::source() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->source();
+}
+
+bool QQuickAnimatedSprite::reverse() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->reverse();
+}
+
+bool QQuickAnimatedSprite::frameSync() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->frameSync();
+}
+
+int QQuickAnimatedSprite::frameCount() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->frames();
+}
+
+int QQuickAnimatedSprite::frameHeight() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->frameHeight();
+}
+
+int QQuickAnimatedSprite::frameWidth() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->frameWidth();
+}
+
+int QQuickAnimatedSprite::frameX() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->frameX();
+}
+
+int QQuickAnimatedSprite::frameY() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->frameY();
+}
+
+qreal QQuickAnimatedSprite::frameRate() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->frameRate();
+}
+
+int QQuickAnimatedSprite::frameDuration() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_sprite->frameDuration();
+}
+
+int QQuickAnimatedSprite::loops() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_loops;
+}
+
+bool QQuickAnimatedSprite::paused() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_paused;
+}
+
+int QQuickAnimatedSprite::currentFrame() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_curFrame;
+}
+
bool QQuickAnimatedSprite::isCurrentFrameChangedConnected()
{
IS_SIGNAL_CONNECTED(this, QQuickAnimatedSprite, currentFrameChanged, (int));
@@ -348,23 +327,25 @@ void QQuickAnimatedSprite::reloadImage()
void QQuickAnimatedSprite::componentComplete()
{
+ Q_D(const QQuickAnimatedSprite);
createEngine();
QQuickItem::componentComplete();
- if (m_running)
+ if (d->m_running)
start();
}
void QQuickAnimatedSprite::start()
{
- m_running = true;
+ Q_D(QQuickAnimatedSprite);
+ d->m_running = true;
if (!isComponentComplete())
return;
- m_curLoop = 0;
- m_timestamp.start();
- if (m_spriteEngine) {
- m_spriteEngine->stop(0);
- m_spriteEngine->updateSprites(0);
- m_spriteEngine->start(0);
+ d->m_curLoop = 0;
+ d->m_timestamp.start();
+ if (d->m_spriteEngine) {
+ d->m_spriteEngine->stop(0);
+ d->m_spriteEngine->updateSprites(0);
+ d->m_spriteEngine->start(0);
}
emit currentFrameChanged(0);
emit runningChanged(true);
@@ -373,10 +354,11 @@ void QQuickAnimatedSprite::start()
void QQuickAnimatedSprite::stop()
{
- m_running = false;
+ Q_D(QQuickAnimatedSprite);
+ d->m_running = false;
if (!isComponentComplete())
return;
- m_pauseOffset = 0;
+ d->m_pauseOffset = 0;
emit runningChanged(false);
update();
}
@@ -388,14 +370,15 @@ void QQuickAnimatedSprite::stop()
*/
void QQuickAnimatedSprite::advance(int frames)
{
+ Q_D(QQuickAnimatedSprite);
if (!frames)
return;
//TODO-C: May not work when running - only when paused
- m_curFrame += frames;
- while (m_curFrame < 0)
- m_curFrame += m_spriteEngine->maxFrames();
- m_curFrame = m_curFrame % m_spriteEngine->maxFrames();
- emit currentFrameChanged(m_curFrame);
+ d->m_curFrame += frames;
+ while (d->m_curFrame < 0)
+ d->m_curFrame += d->m_spriteEngine->maxFrames();
+ d->m_curFrame = d->m_curFrame % d->m_spriteEngine->maxFrames();
+ emit currentFrameChanged(d->m_curFrame);
update();
}
@@ -409,10 +392,12 @@ void QQuickAnimatedSprite::advance(int frames)
*/
void QQuickAnimatedSprite::pause()
{
- if (m_paused)
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_paused)
return;
- m_pauseOffset = m_timestamp.elapsed();
- m_paused = true;
+ d->m_pauseOffset = d->m_timestamp.elapsed();
+ d->m_paused = true;
emit pausedChanged(true);
update();
}
@@ -427,246 +412,363 @@ void QQuickAnimatedSprite::pause()
*/
void QQuickAnimatedSprite::resume()
{
- if (!m_paused)
+ Q_D(QQuickAnimatedSprite);
+
+ if (!d->m_paused)
return;
- m_pauseOffset = m_pauseOffset - m_timestamp.elapsed();
- m_paused = false;
+ d->m_pauseOffset = d->m_pauseOffset - d->m_timestamp.elapsed();
+ d->m_paused = false;
emit pausedChanged(false);
update();
}
-void QQuickAnimatedSprite::createEngine()
+void QQuickAnimatedSprite::setRunning(bool arg)
{
- if (m_spriteEngine)
- delete m_spriteEngine;
- QList<QQuickSprite*> spriteList;
- spriteList << m_sprite;
- m_spriteEngine = new QQuickSpriteEngine(QList<QQuickSprite*>(spriteList), this);
- m_spriteEngine->startAssemblingImage();
- reset();
- update();
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_running != arg) {
+ if (d->m_running)
+ stop();
+ else
+ start();
+ }
}
-static QSGGeometry::Attribute AnimatedSprite_Attributes[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // pos
- QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // tex
-};
+void QQuickAnimatedSprite::setPaused(bool arg)
+{
+ Q_D(const QQuickAnimatedSprite);
-static QSGGeometry::AttributeSet AnimatedSprite_AttributeSet =
+ if (d->m_paused != arg) {
+ if (d->m_paused)
+ resume();
+ else
+ pause();
+ }
+}
+
+void QQuickAnimatedSprite::setInterpolate(bool arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_interpolate != arg) {
+ d->m_interpolate = arg;
+ Q_EMIT interpolateChanged(arg);
+ }
+}
+
+void QQuickAnimatedSprite::setSource(QUrl arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_sprite->m_source != arg) {
+ d->m_sprite->setSource(arg);
+ Q_EMIT sourceChanged(arg);
+ reloadImage();
+ }
+}
+
+void QQuickAnimatedSprite::setReverse(bool arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_sprite->m_reverse != arg) {
+ d->m_sprite->setReverse(arg);
+ Q_EMIT reverseChanged(arg);
+ }
+}
+
+void QQuickAnimatedSprite::setFrameSync(bool arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_sprite->m_frameSync != arg) {
+ d->m_sprite->setFrameSync(arg);
+ Q_EMIT frameSyncChanged(arg);
+ if (d->m_running)
+ restart();
+ }
+}
+
+void QQuickAnimatedSprite::setFrameCount(int arg)
{
- 2, // Attribute Count
- (2+2) * sizeof(float),
- AnimatedSprite_Attributes
-};
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_sprite->m_frames != arg) {
+ d->m_sprite->setFrameCount(arg);
+ Q_EMIT frameCountChanged(arg);
+ reloadImage();
+ }
+}
-void QQuickAnimatedSprite::sizeVertices(QSGGeometryNode *node)
+void QQuickAnimatedSprite::setFrameHeight(int arg)
{
- AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) node->geometry()->vertexData();
- p->v1.x = 0;
- p->v1.y = 0;
+ Q_D(QQuickAnimatedSprite);
- p->v2.x = width();
- p->v2.y = 0;
+ if (d->m_sprite->m_frameHeight != arg) {
+ d->m_sprite->setFrameHeight(arg);
+ Q_EMIT frameHeightChanged(arg);
+ reloadImage();
+ }
+}
- p->v3.x = 0;
- p->v3.y = height();
+void QQuickAnimatedSprite::setFrameWidth(int arg)
+{
+ Q_D(QQuickAnimatedSprite);
- p->v4.x = width();
- p->v4.y = height();
+ if (d->m_sprite->m_frameWidth != arg) {
+ d->m_sprite->setFrameWidth(arg);
+ Q_EMIT frameWidthChanged(arg);
+ reloadImage();
+ }
}
-QSGGeometryNode* QQuickAnimatedSprite::buildNode()
+void QQuickAnimatedSprite::setFrameX(int arg)
{
- if (!m_spriteEngine) {
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_sprite->m_frameX != arg) {
+ d->m_sprite->setFrameX(arg);
+ Q_EMIT frameXChanged(arg);
+ reloadImage();
+ }
+}
+
+void QQuickAnimatedSprite::setFrameY(int arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_sprite->m_frameY != arg) {
+ d->m_sprite->setFrameY(arg);
+ Q_EMIT frameYChanged(arg);
+ reloadImage();
+ }
+}
+
+void QQuickAnimatedSprite::setFrameRate(qreal arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_sprite->m_frameRate != arg) {
+ d->m_sprite->setFrameRate(arg);
+ Q_EMIT frameRateChanged(arg);
+ if (d->m_running)
+ restart();
+ }
+}
+
+void QQuickAnimatedSprite::setFrameDuration(int arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_sprite->m_frameDuration != arg) {
+ d->m_sprite->setFrameDuration(arg);
+ Q_EMIT frameDurationChanged(arg);
+ if (d->m_running)
+ restart();
+ }
+}
+
+void QQuickAnimatedSprite::resetFrameRate()
+{
+ setFrameRate(-1.0);
+}
+
+void QQuickAnimatedSprite::resetFrameDuration()
+{
+ setFrameDuration(-1);
+}
+
+void QQuickAnimatedSprite::setLoops(int arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_loops != arg) {
+ d->m_loops = arg;
+ Q_EMIT loopsChanged(arg);
+ }
+}
+
+void QQuickAnimatedSprite::setCurrentFrame(int arg) //TODO-C: Probably only works when paused
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_curFrame != arg) {
+ d->m_curFrame = arg;
+ Q_EMIT currentFrameChanged(arg); //TODO-C Only emitted on manual advance!
+ update();
+ }
+}
+
+void QQuickAnimatedSprite::createEngine()
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_spriteEngine)
+ delete d->m_spriteEngine;
+ QList<QQuickSprite*> spriteList;
+ spriteList << d->m_sprite;
+ d->m_spriteEngine = new QQuickSpriteEngine(QList<QQuickSprite*>(spriteList), this);
+ d->m_spriteEngine->startAssemblingImage();
+ reset();
+ update();
+}
+
+QSGSpriteNode* QQuickAnimatedSprite::initNode()
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (!d->m_spriteEngine) {
qmlInfo(this) << "No sprite engine...";
- return 0;
- } else if (m_spriteEngine->status() == QQuickPixmap::Null) {
- m_spriteEngine->startAssemblingImage();
+ return nullptr;
+ } else if (d->m_spriteEngine->status() == QQuickPixmap::Null) {
+ d->m_spriteEngine->startAssemblingImage();
update();//Schedule another update, where we will check again
- return 0;
- } else if (m_spriteEngine->status() == QQuickPixmap::Loading) {
+ return nullptr;
+ } else if (d->m_spriteEngine->status() == QQuickPixmap::Loading) {
update();//Schedule another update, where we will check again
- return 0;
+ return nullptr;
}
- QQuickAnimatedSpriteMaterial *material = new QQuickAnimatedSpriteMaterial();
-
- QImage image = m_spriteEngine->assembledImage(); //Engine prints errors if there are any
+ QImage image = d->m_spriteEngine->assembledImage(d->sceneGraphRenderContext()->maxTextureSize()); //Engine prints errors if there are any
if (image.isNull())
- return 0;
- m_sheetSize = QSizeF(image.size());
- material->texture = window()->createTextureFromImage(image);
- m_spriteEngine->start(0);
- material->animT = 0;
- material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width();
- material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height();
- material->animX2 = material->animX1;
- material->animY2 = material->animY1;
- material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width();
- material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height();
-
- int vCount = 4;
- int iCount = 6;
- QSGGeometry *g = new QSGGeometry(AnimatedSprite_AttributeSet, vCount, iCount);
- g->setDrawingMode(GL_TRIANGLES);
-
- AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) g->vertexData();
-
- QRectF texRect = material->texture->normalizedTextureSubRect();
-
- p->v1.tx = texRect.topLeft().x();
- p->v1.ty = texRect.topLeft().y();
-
- p->v2.tx = texRect.topRight().x();
- p->v2.ty = texRect.topRight().y();
-
- p->v3.tx = texRect.bottomLeft().x();
- p->v3.ty = texRect.bottomLeft().y();
-
- p->v4.tx = texRect.bottomRight().x();
- p->v4.ty = texRect.bottomRight().y();
-
- quint16 *indices = g->indexDataAsUShort();
- indices[0] = 0;
- indices[1] = 1;
- indices[2] = 2;
- indices[3] = 1;
- indices[4] = 3;
- indices[5] = 2;
-
-
- QSGGeometryNode *node = new QSGGeometryNode();
- node->setGeometry(g);
- node->setMaterial(material);
- node->setFlag(QSGGeometryNode::OwnsMaterial);
- node->setFlag(QSGGeometryNode::OwnsGeometry);
- sizeVertices(node);
+ return nullptr;
+
+ QSGSpriteNode *node = d->sceneGraphContext()->createSpriteNode();
+
+ d->m_sheetSize = QSize(image.size());
+ node->setTexture(window()->createTextureFromImage(image));
+ d->m_spriteEngine->start(0);
+ node->setTime(0.0f);
+ node->setSourceA(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY()));
+ node->setSourceB(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY()));
+ node->setSpriteSize(QSize(d->m_spriteEngine->spriteWidth(), d->m_spriteEngine->spriteHeight()));
+ node->setSheetSize(d->m_sheetSize);
+ node->setSize(QSizeF(width(), height()));
return node;
}
void QQuickAnimatedSprite::reset()
{
- m_pleaseReset = true;
+ Q_D(QQuickAnimatedSprite);
+ d->m_pleaseReset = true;
update();
}
QSGNode *QQuickAnimatedSprite::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
- if (m_pleaseReset) {
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_pleaseReset) {
delete oldNode;
- oldNode = 0;
- m_pleaseReset = false;
+ oldNode = nullptr;
+ d->m_pleaseReset = false;
}
- QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode);
+ QSGSpriteNode *node = static_cast<QSGSpriteNode *>(oldNode);
if (!node)
- node = buildNode();
+ node = initNode();
if (node)
prepareNextFrame(node);
- if (m_running) {
- if (!m_paused)
- update();
-
- if (node) {
- node->markDirty(QSGNode::DirtyMaterial);
- }
- }
+ if (d->m_running && !d->m_paused)
+ update();
return node;
}
-void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node)
+void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
{
- int timeInt = m_timestamp.elapsed() + m_pauseOffset;
+ Q_D(QQuickAnimatedSprite);
+
+ int timeInt = d->m_timestamp.elapsed() + d->m_pauseOffset;
qreal time = timeInt / 1000.;
int frameAt;
qreal progress = 0.0;
- int lastFrame = m_curFrame;
- if (m_running && !m_paused) {
- const int nColumns = int(m_sheetSize.width()) / m_spriteEngine->spriteWidth();
+ int lastFrame = d->m_curFrame;
+ if (d->m_running && !d->m_paused) {
+ const int nColumns = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth();
//Advance State (keeps time for psuedostates)
- m_spriteEngine->updateSprites(timeInt);
+ d->m_spriteEngine->updateSprites(timeInt);
//Advance AnimatedSprite
- qreal animT = m_spriteEngine->spriteStart()/1000.0;
- const int frameCountInRow = m_spriteEngine->spriteFrames();
- const qreal frameDuration = m_spriteEngine->spriteDuration()/frameCountInRow;
+ qreal animT = d->m_spriteEngine->spriteStart()/1000.0;
+ const int frameCountInRow = d->m_spriteEngine->spriteFrames();
+ const qreal frameDuration = d->m_spriteEngine->spriteDuration() / frameCountInRow;
if (frameDuration > 0) {
qreal frame = (time - animT)/(frameDuration / 1000.0);
- bool lastLoop = m_loops > 0 && m_curLoop == m_loops-1;
+ bool lastLoop = d->m_loops > 0 && d->m_curLoop == d->m_loops-1;
//don't visually interpolate for the last frame of the last loop
const int max = lastLoop ? frameCountInRow - 1 : frameCountInRow;
frame = qBound(qreal(0.0), frame, qreal(max));
double intpart;
progress = std::modf(frame,&intpart);
frameAt = (int)intpart;
- const int rowIndex = m_spriteEngine->spriteY()/frameHeight();
+ const int rowIndex = d->m_spriteEngine->spriteY()/frameHeight();
const int newFrame = rowIndex * nColumns + frameAt;
- if (m_curFrame > newFrame) //went around
- m_curLoop++;
- m_curFrame = newFrame;
+ if (d->m_curFrame > newFrame) //went around
+ d->m_curLoop++;
+ d->m_curFrame = newFrame;
} else {
- m_curFrame++;
- if (m_curFrame >= m_spriteEngine->maxFrames()) { // maxFrames: total number of frames including all rows
- m_curFrame = 0;
- m_curLoop++;
+ d->m_curFrame++;
+ if (d->m_curFrame >= d->m_spriteEngine->maxFrames()) { // maxFrames: total number of frames including all rows
+ d->m_curFrame = 0;
+ d->m_curLoop++;
}
- frameAt = m_curFrame % nColumns;
+ frameAt = d->m_curFrame % nColumns;
if (frameAt == 0)
- m_spriteEngine->advance();
+ d->m_spriteEngine->advance();
progress = 0;
}
- if (m_loops > 0 && m_curLoop >= m_loops) {
+ if (d->m_loops > 0 && d->m_curLoop >= d->m_loops) {
frameAt = 0;
- m_running = false;
+ d->m_running = false;
emit runningChanged(false);
update();
}
} else {
- frameAt = m_curFrame;
+ frameAt = d->m_curFrame;
}
- if (m_curFrame != lastFrame) {
+ if (d->m_curFrame != lastFrame) {
if (isCurrentFrameChangedConnected())
- emit currentFrameChanged(m_curFrame);
+ emit currentFrameChanged(d->m_curFrame);
update();
}
- qreal frameCount = m_spriteEngine->spriteFrames();
- bool reverse = m_spriteEngine->sprite()->reverse();
+ qreal frameCount = d->m_spriteEngine->spriteFrames();
+ bool reverse = d->m_spriteEngine->sprite()->reverse();
if (reverse)
frameAt = (frameCount - 1) - frameAt;
- qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width();
- qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height();
- qreal x1;
- qreal y1;
- if (m_paused) {
- int spriteY = m_spriteEngine->spriteY();
+ int w = d->m_spriteEngine->spriteWidth();
+ int h = d->m_spriteEngine->spriteHeight();
+ int x1;
+ int y1;
+ if (d->m_paused) {
+ int spriteY = d->m_spriteEngine->spriteY();
if (reverse) {
- int rows = m_spriteEngine->maxFrames() * m_spriteEngine->spriteWidth() / m_sheetSize.width();
- spriteY -= rows * m_spriteEngine->spriteHeight();
+ int rows = d->m_spriteEngine->maxFrames() * d->m_spriteEngine->spriteWidth() / d->m_sheetSize.width();
+ spriteY -= rows * d->m_spriteEngine->spriteHeight();
frameAt = (frameCount - 1) - frameAt;
}
- int position = frameAt * m_spriteEngine->spriteWidth() + m_spriteEngine->spriteX();
- int row = position / m_sheetSize.width();
+ int position = frameAt * d->m_spriteEngine->spriteWidth() + d->m_spriteEngine->spriteX();
+ int row = position / d->m_sheetSize.width();
- x1 = (position - (row * m_sheetSize.width())) / m_sheetSize.width();
- y1 = (row * m_spriteEngine->spriteHeight() + spriteY) / m_sheetSize.height();
+ x1 = (position - (row * d->m_sheetSize.width()));
+ y1 = (row * d->m_spriteEngine->spriteHeight() + spriteY);
} else {
- x1 = m_spriteEngine->spriteX() / m_sheetSize.width() + frameAt * w;
- y1 = m_spriteEngine->spriteY() / m_sheetSize.height();
+ x1 = d->m_spriteEngine->spriteX() + frameAt * w;
+ y1 = d->m_spriteEngine->spriteY();
}
//### hard-coded 0/1 work because we are the only
// images in the sprite sheet (without this we cannot assume
// where in the sheet we begin/end).
- qreal x2;
- qreal y2;
+ int x2;
+ int y2;
if (reverse) {
if (frameAt > 0) {
x2 = x1 - w;
@@ -676,9 +778,9 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node)
y2 = y1 - h;
if (y2 < 0.0) {
//the last row may not fill the entire width
- int maxRowFrames = m_sheetSize.width() / m_spriteEngine->spriteWidth();
- if (m_spriteEngine->maxFrames() % maxRowFrames)
- x2 = ((m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w;
+ 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;
}
@@ -695,15 +797,13 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node)
}
}
- QQuickAnimatedSpriteMaterial *material = static_cast<QQuickAnimatedSpriteMaterial *>(node->material());
- material->animX1 = x1;
- material->animY1 = y1;
- material->animX2 = x2;
- material->animY2 = y2;
- material->animW = w;
- material->animH = h;
- material->animT = m_interpolate ? progress : 0.0;
- material->texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
+ node->setSourceA(QPoint(x1, y1));
+ node->setSourceB(QPoint(x2, y2));
+ node->setSpriteSize(QSize(w, h));
+ node->setTime(d->m_interpolate ? progress : 0.0);
+ node->setSize(QSizeF(width(), height()));
+ node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
+ node->update();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h
index 1e5981c1a4..cbd6524c40 100644
--- a/src/quick/items/qquickanimatedsprite_p.h
+++ b/src/quick/items/qquickanimatedsprite_p.h
@@ -62,6 +62,8 @@ class QQuickSprite;
class QQuickSpriteEngine;
class QSGGeometryNode;
class QQuickAnimatedSpriteMaterial;
+class QQuickAnimatedSpritePrivate;
+class QSGSpriteNode;
class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem
{
Q_OBJECT
@@ -94,80 +96,21 @@ public:
};
Q_ENUM(LoopParameters)
- bool running() const
- {
- return m_running;
- }
-
- bool interpolate() const
- {
- return m_interpolate;
- }
-
- QUrl source() const
- {
- return m_sprite->source();
- }
-
- bool reverse() const
- {
- return m_sprite->reverse();
- }
-
- bool frameSync() const
- {
- return m_sprite->frameSync();
- }
-
- int frameCount() const
- {
- return m_sprite->frames();
- }
-
- int frameHeight() const
- {
- return m_sprite->frameHeight();
- }
-
- int frameWidth() const
- {
- return m_sprite->frameWidth();
- }
-
- int frameX() const
- {
- return m_sprite->frameX();
- }
-
- int frameY() const
- {
- return m_sprite->frameY();
- }
-
- qreal frameRate() const
- {
- return m_sprite->frameRate();
- }
-
- int frameDuration() const
- {
- return m_sprite->frameDuration();
- }
-
- int loops() const
- {
- return m_loops;
- }
-
- bool paused() const
- {
- return m_paused;
- }
-
- int currentFrame() const
- {
- return m_curFrame;
- }
+ bool running() const;
+ bool interpolate() const;
+ QUrl source() const;
+ bool reverse() const;
+ bool frameSync() const;
+ int frameCount() const;
+ int frameHeight() const;
+ int frameWidth() const;
+ int frameX() const;
+ int frameY() const;
+ qreal frameRate() const;
+ int frameDuration() const;
+ int loops() const;
+ bool paused() const;
+ int currentFrame() const;
Q_SIGNALS:
@@ -176,27 +119,16 @@ Q_SIGNALS:
void interpolateChanged(bool arg);
void sourceChanged(QUrl arg);
-
void reverseChanged(bool arg);
-
void frameSyncChanged(bool arg);
-
void frameCountChanged(int arg);
-
void frameHeightChanged(int arg);
-
void frameWidthChanged(int arg);
-
void frameXChanged(int arg);
-
void frameYChanged(int arg);
-
void frameRateChanged(qreal arg);
-
void frameDurationChanged(int arg);
-
void loopsChanged(int arg);
-
void currentFrameChanged(int arg);
public Q_SLOTS:
@@ -207,157 +139,27 @@ public Q_SLOTS:
void pause();
void resume();
- void setRunning(bool arg)
- {
- if (m_running != arg) {
- if (m_running)
- stop();
- else
- start();
- }
- }
-
- void setPaused(bool arg)
- {
- if (m_paused != arg) {
- if (m_paused)
- resume();
- else
- pause();
- }
- }
-
- void setInterpolate(bool arg)
- {
- if (m_interpolate != arg) {
- m_interpolate = arg;
- Q_EMIT interpolateChanged(arg);
- }
- }
-
- void setSource(QUrl arg)
- {
- if (m_sprite->m_source != arg) {
- m_sprite->setSource(arg);
- Q_EMIT sourceChanged(arg);
- reloadImage();
- }
- }
-
- void setReverse(bool arg)
- {
- if (m_sprite->m_reverse != arg) {
- m_sprite->setReverse(arg);
- Q_EMIT reverseChanged(arg);
- }
- }
-
- void setFrameSync(bool arg)
- {
- if (m_sprite->m_frameSync != arg) {
- m_sprite->setFrameSync(arg);
- Q_EMIT frameSyncChanged(arg);
- if (m_running)
- restart();
- }
- }
-
- void setFrameCount(int arg)
- {
- if (m_sprite->m_frames != arg) {
- m_sprite->setFrameCount(arg);
- Q_EMIT frameCountChanged(arg);
- reloadImage();
- }
- }
-
- void setFrameHeight(int arg)
- {
- if (m_sprite->m_frameHeight != arg) {
- m_sprite->setFrameHeight(arg);
- Q_EMIT frameHeightChanged(arg);
- reloadImage();
- }
- }
-
- void setFrameWidth(int arg)
- {
- if (m_sprite->m_frameWidth != arg) {
- m_sprite->setFrameWidth(arg);
- Q_EMIT frameWidthChanged(arg);
- reloadImage();
- }
- }
-
- void setFrameX(int arg)
- {
- if (m_sprite->m_frameX != arg) {
- m_sprite->setFrameX(arg);
- Q_EMIT frameXChanged(arg);
- reloadImage();
- }
- }
-
- void setFrameY(int arg)
- {
- if (m_sprite->m_frameY != arg) {
- m_sprite->setFrameY(arg);
- Q_EMIT frameYChanged(arg);
- reloadImage();
- }
- }
-
- void setFrameRate(qreal arg)
- {
- if (m_sprite->m_frameRate != arg) {
- m_sprite->setFrameRate(arg);
- Q_EMIT frameRateChanged(arg);
- if (m_running)
- restart();
- }
- }
-
- void setFrameDuration(int arg)
- {
- if (m_sprite->m_frameDuration != arg) {
- m_sprite->setFrameDuration(arg);
- Q_EMIT frameDurationChanged(arg);
- if (m_running)
- restart();
- }
- }
-
- void resetFrameRate()
- {
- setFrameRate(-1.0);
- }
-
- void resetFrameDuration()
- {
- setFrameDuration(-1);
- }
-
- void setLoops(int arg)
- {
- if (m_loops != arg) {
- m_loops = arg;
- Q_EMIT loopsChanged(arg);
- }
- }
-
- void setCurrentFrame(int arg) //TODO-C: Probably only works when paused
- {
- if (m_curFrame != arg) {
- m_curFrame = arg;
- Q_EMIT currentFrameChanged(arg); //TODO-C Only emitted on manual advance!
- update();
- }
- }
+ void setRunning(bool arg);
+ void setPaused(bool arg);
+ void setInterpolate(bool arg);
+ void setSource(QUrl arg);
+ void setReverse(bool arg);
+ void setFrameSync(bool arg);
+ void setFrameCount(int arg);
+ void setFrameHeight(int arg);
+ void setFrameWidth(int arg);
+ void setFrameX(int arg);
+ void setFrameY(int arg);
+ void setFrameRate(qreal arg);
+ void setFrameDuration(int arg);
+ void resetFrameRate();
+ void resetFrameDuration();
+ void setLoops(int arg);
+ void setCurrentFrame(int arg);
private Q_SLOTS:
void createEngine();
- void sizeVertices(QSGGeometryNode *node);
protected Q_SLOTS:
void reset();
@@ -367,21 +169,13 @@ protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
private:
bool isCurrentFrameChangedConnected();
- void prepareNextFrame(QSGGeometryNode *node);
+ void prepareNextFrame(QSGSpriteNode *node);
void reloadImage();
- QSGGeometryNode* buildNode();
- QQuickSprite* m_sprite;
- QQuickSpriteEngine* m_spriteEngine;
- QElapsedTimer m_timestamp;
- int m_curFrame;
- bool m_pleaseReset;
- bool m_running;
- bool m_paused;
- bool m_interpolate;
- QSizeF m_sheetSize;
- int m_loops;
- int m_curLoop;
- int m_pauseOffset;
+ QSGSpriteNode* initNode();
+
+private:
+ Q_DISABLE_COPY(QQuickAnimatedSprite)
+ Q_DECLARE_PRIVATE(QQuickAnimatedSprite)
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickanimatedsprite_p_p.h b/src/quick/items/qquickanimatedsprite_p_p.h
new file mode 100644
index 0000000000..0e4a1e9066
--- /dev/null
+++ b/src/quick/items/qquickanimatedsprite_p_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKANIMATEDSPRITE_P_P_H
+#define QQUICKANIMATEDSPRITE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickitem_p.h"
+#include "qquicksprite_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAnimatedSprite;
+
+class QQuickAnimatedSpritePrivate : public QQuickItemPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickAnimatedSprite)
+
+public:
+ QQuickAnimatedSpritePrivate()
+ : m_sprite(nullptr)
+ , m_spriteEngine(nullptr)
+ , m_curFrame(0)
+ , m_pleaseReset(false)
+ , m_running(true)
+ , m_paused(false)
+ , m_interpolate(true)
+ , m_loops(-1)
+ , m_curLoop(0)
+ , m_pauseOffset(0)
+ {
+ }
+
+ QQuickSprite* m_sprite;
+ QQuickSpriteEngine* m_spriteEngine;
+ QElapsedTimer m_timestamp;
+ int m_curFrame;
+ bool m_pleaseReset;
+ bool m_running;
+ bool m_paused;
+ bool m_interpolate;
+ QSize m_sheetSize;
+ int m_loops;
+ int m_curLoop;
+ int m_pauseOffset;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKANIMATEDSPRITE_P_P_H
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index b3a35e6219..ca5ad8dbbd 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -631,12 +631,12 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
return 0;
}
- QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
+ QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
bool updatePixmap = d->pixmapChanged;
d->pixmapChanged = false;
if (!node) {
- node = d->sceneGraphContext()->createImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode();
updatePixmap = true;
}
diff --git a/src/quick/items/qquickclipnode.cpp b/src/quick/items/qquickclipnode.cpp
index 1114686a9a..747e844172 100644
--- a/src/quick/items/qquickclipnode.cpp
+++ b/src/quick/items/qquickclipnode.cpp
@@ -93,7 +93,7 @@ void QQuickDefaultClipNode::updateGeometry()
int segments = qMin(30, qCeil(radius)); // Number of segments per corner.
- g->allocate((segments + 1) * 2);
+ g->allocate((segments + 1) * 4);
QVector2D *vertices = (QVector2D *)g->vertexData();
@@ -113,7 +113,7 @@ void QQuickDefaultClipNode::updateGeometry()
}
}
- markDirty(DirtyGeometry);
setClipRect(m_rect);
+ markDirty(DirtyGeometry);
}
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index cc30199253..b943c28661 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -82,7 +82,7 @@ public:
{
}
- void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
void itemParentChanged(QQuickItem *, QQuickItem *parent) Q_DECL_OVERRIDE;
void updatePosition();
void restartDrag();
@@ -148,9 +148,10 @@ public:
\sa {Qt Quick Examples - Drag and Drop}, {Qt Quick Examples - externaldraganddrop}
*/
-void QQuickDragAttachedPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickDragAttachedPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange change,
+ const QRectF &)
{
- if (newGeometry.topLeft() == oldGeometry.topLeft() || !active || itemMoved)
+ if (!change.positionChange() || !active || itemMoved)
return;
updatePosition();
}
@@ -760,7 +761,7 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct
{
Q_Q(QQuickDragAttached);
- QDrag *drag = new QDrag(q);
+ QDrag *drag = new QDrag(source ? source : q);
QMimeData *mimeData = new QMimeData();
for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it)
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index 17721251d9..f9faca55e0 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -290,7 +290,7 @@ public:
Q_INVOKABLE int drop();
- bool event(QEvent *event);
+ bool event(QEvent *event) override;
public Q_SLOTS:
void start(QQmlV4Function *);
diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index 1701441240..70d76c99a1 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -235,7 +235,7 @@ bool QQuickDropAreaPrivate::hasMatchingKey(const QStringList &keys) const
return true;
QRegExp copy = keyRegExp;
- foreach (const QString &key, keys) {
+ for (const QString &key : keys) {
if (copy.exactMatch(key))
return true;
}
@@ -513,7 +513,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
easily be translated into a QByteArray. \a format should be one contained in the \l formats property.
*/
-QObject *QQuickDropEvent::source()
+QObject *QQuickDropEvent::source() const
{
if (const QQuickDragMimeData *dragMime = qobject_cast<const QQuickDragMimeData *>(event->mimeData()))
return dragMime->source();
diff --git a/src/quick/items/qquickdroparea_p.h b/src/quick/items/qquickdroparea_p.h
index d3b37979da..ecd4da4367 100644
--- a/src/quick/items/qquickdroparea_p.h
+++ b/src/quick/items/qquickdroparea_p.h
@@ -86,7 +86,7 @@ public:
qreal x() const { return event->pos().x(); }
qreal y() const { return event->pos().y(); }
- QObject *source();
+ QObject *source() const;
Qt::DropActions supportedActions() const { return event->possibleActions(); }
Qt::DropActions proposedAction() const { return event->proposedAction(); }
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 14c0adf393..86d1ddac6c 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -38,9 +38,15 @@
****************************************************************************/
#include "qquickevents_p_p.h"
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <private/qdebug_p.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcPointerEvents, "qt.quick.pointer.events")
+
/*!
\qmltype KeyEvent
\instantiates QQuickKeyEvent
@@ -379,7 +385,7 @@ Item {
\qmlproperty point QtQuick::WheelEvent::pixelDelta
This property holds the delta in screen pixels and is available in platforms that
- have high-resolution trackpads, such as OS X.
+ have high-resolution trackpads, such as \macos.
The x and y cordinate of this property holds the delta in horizontal and
vertical orientation. The value should be used directly to scroll content on screen.
@@ -437,4 +443,504 @@ Item {
\l inverted always returns false.
*/
+typedef QHash<QTouchDevice *, QQuickPointerDevice *> PointerDeviceForTouchDeviceHash;
+Q_GLOBAL_STATIC(PointerDeviceForTouchDeviceHash, g_touchDevices)
+
+Q_GLOBAL_STATIC_WITH_ARGS(QQuickPointerDevice, g_genericMouseDevice,
+ (QQuickPointerDevice::Mouse,
+ QQuickPointerDevice::GenericPointer,
+ QQuickPointerDevice::Position | QQuickPointerDevice::Scroll | QQuickPointerDevice::Hover,
+ 1, 3, QLatin1String("core pointer"), 0))
+
+typedef QHash<qint64, QQuickPointerDevice *> PointerDeviceForDeviceIdHash;
+Q_GLOBAL_STATIC(PointerDeviceForDeviceIdHash, g_tabletDevices)
+
+QQuickPointerDevice *QQuickPointerDevice::touchDevice(QTouchDevice *d)
+{
+ if (g_touchDevices->contains(d))
+ return g_touchDevices->value(d);
+
+ QQuickPointerDevice::DeviceType type = QQuickPointerDevice::TouchScreen;
+ QString name;
+ int maximumTouchPoints = 10;
+ QQuickPointerDevice::Capabilities caps = QQuickPointerDevice::Capabilities(QTouchDevice::Position);
+ if (d) {
+ QQuickPointerDevice::Capabilities caps =
+ static_cast<QQuickPointerDevice::Capabilities>(static_cast<int>(d->capabilities()) & 0x0F);
+ if (d->type() == QTouchDevice::TouchPad) {
+ type = QQuickPointerDevice::TouchPad;
+ caps |= QQuickPointerDevice::Scroll;
+ }
+ name = d->name();
+ maximumTouchPoints = d->maximumTouchPoints();
+ } else {
+ qWarning() << "QQuickWindowPrivate::touchDevice: creating touch device from nullptr device in QTouchEvent";
+ }
+
+ QQuickPointerDevice *dev = new QQuickPointerDevice(type, QQuickPointerDevice::Finger,
+ caps, maximumTouchPoints, 0, name, 0);
+ g_touchDevices->insert(d, dev);
+ return dev;
+}
+
+QList<QQuickPointerDevice*> QQuickPointerDevice::touchDevices()
+{
+ return g_touchDevices->values();
+}
+
+QQuickPointerDevice *QQuickPointerDevice::genericMouseDevice()
+{
+ return g_genericMouseDevice;
+}
+
+QQuickPointerDevice *QQuickPointerDevice::tabletDevice(qint64 id)
+{
+ auto it = g_tabletDevices->find(id);
+ if (it != g_tabletDevices->end())
+ return it.value();
+
+ // ### Figure out how to populate the tablet devices
+ return nullptr;
+}
+
+void QQuickEventPoint::reset(Qt::TouchPointState state, QPointF scenePos, quint64 pointId, ulong timestamp)
+{
+ m_scenePos = scenePos;
+ m_pointId = pointId;
+ m_valid = true;
+ m_accept = false;
+ m_state = static_cast<QQuickEventPoint::State>(state);
+ m_timestamp = timestamp;
+ if (state == Qt::TouchPointPressed)
+ m_pressTimestamp = timestamp;
+ // TODO calculate velocity
+}
+
+QQuickItem *QQuickEventPoint::grabber() const
+{
+ return m_grabber.data();
+}
+
+void QQuickEventPoint::setGrabber(QQuickItem *grabber)
+{
+ m_grabber = QPointer<QQuickItem>(grabber);
+}
+
+void QQuickEventPoint::setAccepted(bool accepted)
+{
+ if (m_accept != accepted) {
+ qCDebug(lcPointerEvents) << this << m_accept << "->" << accepted;
+ m_accept = accepted;
+ }
+}
+
+QQuickEventTouchPoint::QQuickEventTouchPoint(QQuickPointerTouchEvent *parent)
+ : QQuickEventPoint(parent), m_rotation(0), m_pressure(0)
+{}
+
+void QQuickEventTouchPoint::reset(const QTouchEvent::TouchPoint &tp, ulong timestamp)
+{
+ QQuickEventPoint::reset(tp.state(), tp.scenePos(), tp.id(), timestamp);
+ m_rotation = tp.rotation();
+ m_pressure = tp.pressure();
+ m_uniqueId = tp.uniqueId();
+}
+
+/*!
+ \internal
+ \class QQuickPointerEvent
+
+ QQuickPointerEvent is used as a long-lived object to store data related to
+ an event from a pointing device, such as a mouse, touch or tablet event,
+ during event delivery. It also provides properties which may be used later
+ to expose the event to QML, the same as is done with QQuickMouseEvent,
+ QQuickTouchPoint, QQuickKeyEvent, etc. Since only one event can be
+ delivered at a time, this class is effectively a singleton. We don't worry
+ about the QObject overhead because the instances are long-lived: we don't
+ dynamically create and destroy objects of this type for each event.
+*/
+
+QQuickPointerEvent::~QQuickPointerEvent()
+{}
+
+QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
+{
+ auto ev = static_cast<QMouseEvent*>(event);
+ m_event = ev;
+ if (!event)
+ return this;
+
+ m_device = QQuickPointerDevice::genericMouseDevice();
+ m_button = ev->button();
+ m_pressedButtons = ev->buttons();
+ Qt::TouchPointState state = Qt::TouchPointStationary;
+ switch (ev->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ state = Qt::TouchPointPressed;
+ break;
+ case QEvent::MouseButtonRelease:
+ state = Qt::TouchPointReleased;
+ break;
+ case QEvent::MouseMove:
+ state = Qt::TouchPointMoved;
+ break;
+ default:
+ break;
+ }
+ m_mousePoint->reset(state, ev->windowPos(), 0, ev->timestamp()); // mouse is 0
+ return this;
+}
+
+QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
+{
+ auto ev = static_cast<QTouchEvent*>(event);
+ m_event = ev;
+ if (!event)
+ return this;
+
+ m_device = QQuickPointerDevice::touchDevice(ev->device());
+ m_button = Qt::NoButton;
+ m_pressedButtons = Qt::NoButton;
+
+ const QList<QTouchEvent::TouchPoint> &tps = ev->touchPoints();
+ int newPointCount = tps.count();
+ m_touchPoints.reserve(newPointCount);
+
+ for (int i = m_touchPoints.size(); i < newPointCount; ++i)
+ m_touchPoints.insert(i, new QQuickEventTouchPoint(this));
+
+ // Make sure the grabbers are right from one event to the next
+ QVector<QQuickItem*> grabbers;
+ // Copy all grabbers, because the order of points might have changed in the event.
+ // The ID is all that we can rely on (release might remove the first point etc).
+ for (int i = 0; i < newPointCount; ++i) {
+ QQuickItem *grabber = nullptr;
+ if (auto point = pointById(tps.at(i).id()))
+ grabber = point->grabber();
+ grabbers.append(grabber);
+ }
+
+ for (int i = 0; i < newPointCount; ++i) {
+ auto point = m_touchPoints.at(i);
+ point->reset(tps.at(i), ev->timestamp());
+ if (point->state() == QQuickEventPoint::Pressed) {
+ if (grabbers.at(i))
+ qWarning() << "TouchPointPressed without previous release event" << point;
+ point->setGrabber(nullptr);
+ } else {
+ point->setGrabber(grabbers.at(i));
+ }
+ }
+ m_pointCount = newPointCount;
+ return this;
+}
+
+QQuickEventPoint *QQuickPointerMouseEvent::point(int i) const {
+ if (i == 0)
+ return m_mousePoint;
+ return nullptr;
+}
+
+QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const {
+ if (i >= 0 && i < m_pointCount)
+ return m_touchPoints.at(i);
+ return nullptr;
+}
+
+QQuickEventPoint::QQuickEventPoint(QQuickPointerEvent *parent)
+ : QObject(parent), m_pointId(0), m_grabber(nullptr), m_timestamp(0), m_pressTimestamp(0),
+ m_state(QQuickEventPoint::Released), m_valid(false), m_accept(false)
+{
+ Q_UNUSED(m_reserved);
+}
+
+QQuickPointerEvent *QQuickEventPoint::pointerEvent() const
+{
+ return static_cast<QQuickPointerEvent *>(parent());
+}
+
+bool QQuickPointerMouseEvent::allPointsAccepted() const {
+ return m_mousePoint->isAccepted();
+}
+
+QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) const
+{
+ auto event = static_cast<QMouseEvent *>(m_event);
+ event->setLocalPos(localPos);
+ return event;
+}
+
+QVector<QQuickItem *> QQuickPointerMouseEvent::grabbers() const
+{
+ QVector<QQuickItem *> result;
+ if (QQuickItem *grabber = m_mousePoint->grabber())
+ result << grabber;
+ return result;
+}
+
+void QQuickPointerMouseEvent::clearGrabbers() const {
+ m_mousePoint->setGrabber(nullptr);
+}
+
+bool QQuickPointerMouseEvent::isPressEvent() const
+{
+ auto me = static_cast<QMouseEvent*>(m_event);
+ return ((me->type() == QEvent::MouseButtonPress || me->type() == QEvent::MouseButtonDblClick) &&
+ (me->buttons() & me->button()) == me->buttons());
+}
+
+bool QQuickPointerTouchEvent::allPointsAccepted() const {
+ for (int i = 0; i < m_pointCount; ++i) {
+ if (!m_touchPoints.at(i)->isAccepted())
+ return false;
+ }
+ return true;
+}
+
+QVector<QQuickItem *> QQuickPointerTouchEvent::grabbers() const
+{
+ QVector<QQuickItem *> result;
+ for (int i = 0; i < m_pointCount; ++i) {
+ auto point = m_touchPoints.at(i);
+ if (QQuickItem *grabber = point->grabber()) {
+ if (!result.contains(grabber))
+ result << grabber;
+ }
+ }
+ return result;
+}
+
+void QQuickPointerTouchEvent::clearGrabbers() const {
+ for (auto point: m_touchPoints)
+ point->setGrabber(nullptr);
+}
+
+bool QQuickPointerTouchEvent::isPressEvent() const
+{
+ return static_cast<QTouchEvent*>(m_event)->touchPointStates() & Qt::TouchPointPressed;
+}
+
+QVector<QPointF> QQuickPointerEvent::unacceptedPressedPointScenePositions() const
+{
+ QVector<QPointF> points;
+ for (int i = 0; i < pointCount(); ++i) {
+ if (!point(i)->isAccepted() && point(i)->state() == QQuickEventPoint::Pressed)
+ points << point(i)->scenePos();
+ }
+ return points;
+}
+
+/*!
+ \internal
+ Populate the reusable synth-mouse event from one touchpoint.
+ It's required that isTouchEvent() be true when this is called.
+ If the touchpoint cannot be found, this returns nullptr.
+ Ownership of the event is NOT transferred to the caller.
+*/
+QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const {
+ const QTouchEvent::TouchPoint *p = touchPointById(pointID);
+ if (!p)
+ return nullptr;
+ QEvent::Type type;
+ Qt::MouseButton buttons = Qt::LeftButton;
+ switch (p->state()) {
+ case Qt::TouchPointPressed:
+ type = QEvent::MouseButtonPress;
+ break;
+ case Qt::TouchPointMoved:
+ case Qt::TouchPointStationary:
+ type = QEvent::MouseMove;
+ break;
+ case Qt::TouchPointReleased:
+ type = QEvent::MouseButtonRelease;
+ buttons = Qt::NoButton;
+ break;
+ default:
+ Q_ASSERT(false);
+ return nullptr;
+ }
+ m_synthMouseEvent = QMouseEvent(type, relativeTo->mapFromScene(p->scenePos()),
+ p->scenePos(), p->screenPos(), Qt::LeftButton, buttons, m_event->modifiers());
+ m_synthMouseEvent.setAccepted(true);
+ m_synthMouseEvent.setTimestamp(m_event->timestamp());
+ // In the future we will try to always have valid velocity in every QQuickEventPoint.
+ // QQuickFlickablePrivate::handleMouseMoveEvent() checks for QTouchDevice::Velocity
+ // and if it is set, then it does not need to do its own velocity calculations.
+ // That's probably the only usecase for this, so far. Some day Flickable should handle
+ // pointer events, and then passing touchpoint velocity via QMouseEvent will be obsolete.
+ // Conveniently (by design), QTouchDevice::Velocity == QQuickPointerDevice.Velocity
+ // so that we don't need to convert m_device->capabilities().
+ if (m_device)
+ QGuiApplicationPrivate::setMouseEventCapsAndVelocity(&m_synthMouseEvent, m_device->capabilities(), p->velocity());
+ QGuiApplicationPrivate::setMouseEventSource(&m_synthMouseEvent, Qt::MouseEventSynthesizedByQt);
+ return &m_synthMouseEvent;
+}
+
+/*!
+ \internal
+ Returns a pointer to the QQuickEventPoint which has the \a pointId as
+ \l {QQuickEventPoint::pointId}{pointId}.
+ Returns nullptr if there is no point with that ID.
+
+ \fn QQuickPointerEvent::pointById(quint64 pointId) const
+*/
+QQuickEventPoint *QQuickPointerMouseEvent::pointById(quint64 pointId) const {
+ if (m_mousePoint && pointId == m_mousePoint->pointId())
+ return m_mousePoint;
+ return nullptr;
+}
+
+QQuickEventPoint *QQuickPointerTouchEvent::pointById(quint64 pointId) const {
+ auto it = std::find_if(m_touchPoints.constBegin(), m_touchPoints.constEnd(),
+ [pointId](const QQuickEventTouchPoint *tp) { return tp->pointId() == pointId; } );
+ if (it != m_touchPoints.constEnd())
+ return *it;
+ return nullptr;
+}
+
+
+/*!
+ \internal
+ Returns a pointer to the original TouchPoint which has the same
+ \l {QTouchEvent::TouchPoint::id}{id} as \a pointId, if the original event is a
+ QTouchEvent, and if that point is found. Otherwise, returns nullptr.
+*/
+const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const {
+ const QTouchEvent *ev = asTouchEvent();
+ if (!ev)
+ return nullptr;
+ const QList<QTouchEvent::TouchPoint> &tps = ev->touchPoints();
+ auto it = std::find_if(tps.constBegin(), tps.constEnd(),
+ [pointId](QTouchEvent::TouchPoint const& tp) { return tp.id() == pointId; } );
+ // return the pointer to the actual TP in QTouchEvent::_touchPoints
+ return (it == tps.constEnd() ? nullptr : it.operator->());
+}
+
+/*!
+ \internal
+ Make a new QTouchEvent, giving it a subset of the original touch points.
+
+ Returns a nullptr if all points are stationary or there are no points inside the item.
+*/
+QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool isFiltering) const
+{
+ QList<QTouchEvent::TouchPoint> touchPoints;
+ Qt::TouchPointStates eventStates;
+ // TODO maybe add QQuickItem::mapVector2DFromScene(QVector2D) to avoid needing QQuickItemPrivate here
+ // Or else just document that velocity is always scene-relative and is not scaled and rotated with the item
+ // but that would require changing tst_qquickwindow::touchEvent_velocity(): it expects transformed velocity
+
+ QMatrix4x4 transformMatrix(QQuickItemPrivate::get(item)->windowToItemTransform());
+ for (int i = 0; i < m_pointCount; ++i) {
+ auto p = m_touchPoints.at(i);
+ if (p->isAccepted())
+ continue;
+ bool isGrabber = p->grabber() == item;
+ bool isPressInside = p->state() == QQuickEventPoint::Pressed && item->contains(item->mapFromScene(p->scenePos()));
+ if (!(isGrabber || isPressInside || isFiltering))
+ continue;
+
+ const QTouchEvent::TouchPoint *tp = touchPointById(p->pointId());
+ if (tp) {
+ eventStates |= tp->state();
+ QTouchEvent::TouchPoint tpCopy = *tp;
+ tpCopy.setPos(item->mapFromScene(tpCopy.scenePos()));
+ tpCopy.setLastPos(item->mapFromScene(tpCopy.lastScenePos()));
+ tpCopy.setStartPos(item->mapFromScene(tpCopy.startScenePos()));
+ tpCopy.setRect(item->mapRectFromScene(tpCopy.sceneRect()));
+ tpCopy.setVelocity(transformMatrix.mapVector(tpCopy.velocity()).toVector2D());
+ touchPoints << tpCopy;
+ }
+ }
+
+ if (eventStates == Qt::TouchPointStationary || touchPoints.isEmpty())
+ return nullptr;
+
+ // if all points have the same state, set the event type accordingly
+ const QTouchEvent &event = *asTouchEvent();
+ QEvent::Type eventType = event.type();
+ switch (eventStates) {
+ case Qt::TouchPointPressed:
+ eventType = QEvent::TouchBegin;
+ break;
+ case Qt::TouchPointReleased:
+ eventType = QEvent::TouchEnd;
+ break;
+ default:
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+
+ QTouchEvent *touchEvent = new QTouchEvent(eventType);
+ touchEvent->setWindow(event.window());
+ touchEvent->setTarget(item);
+ touchEvent->setDevice(event.device());
+ touchEvent->setModifiers(event.modifiers());
+ touchEvent->setTouchPoints(touchPoints);
+ touchEvent->setTouchPointStates(eventStates);
+ touchEvent->setTimestamp(event.timestamp());
+ touchEvent->accept();
+ return touchEvent;
+}
+
+QTouchEvent *QQuickPointerTouchEvent::asTouchEvent() const
+{
+ return static_cast<QTouchEvent *>(m_event);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *dev) {
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ if (!dev) {
+ dbg << "QQuickPointerDevice(0)";
+ return dbg;
+ }
+ dbg << "QQuickPointerDevice("<< dev->name() << ' ';
+ QtDebugUtils::formatQEnum(dbg, dev->type());
+ dbg << ' ';
+ QtDebugUtils::formatQEnum(dbg, dev->pointerType());
+ dbg << " caps:";
+ QtDebugUtils::formatQFlags(dbg, dev->capabilities());
+ if (dev->type() == QQuickPointerDevice::TouchScreen ||
+ dev->type() == QQuickPointerDevice::TouchPad)
+ dbg << " maxTouchPoints:" << dev->maximumTouchPoints();
+ else
+ dbg << " buttonCount:" << dev->buttonCount();
+ dbg << ')';
+ return dbg;
+}
+
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event) {
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg << "QQuickPointerEvent(dev:";
+ QtDebugUtils::formatQEnum(dbg, event->device()->type());
+ if (event->buttons() != Qt::NoButton) {
+ dbg << " buttons:";
+ QtDebugUtils::formatQEnum(dbg, event->buttons());
+ }
+ dbg << " [";
+ int c = event->pointCount();
+ for (int i = 0; i < c; ++i)
+ dbg << event->point(i) << ' ';
+ dbg << "])";
+ return dbg;
+}
+
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event) {
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg << "QQuickEventPoint(valid:" << event->isValid() << " accepted:" << event->isAccepted()
+ << " state:";
+ QtDebugUtils::formatQEnum(dbg, event->state());
+ dbg << " scenePos:" << event->scenePos() << " id:" << hex << event->pointId() << dec
+ << " timeHeld:" << event->timeHeld() << ')';
+ return dbg;
+}
+
+#endif
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 6d4b49b3cd..61bbb4ecda 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -55,12 +55,20 @@
#include <qqml.h>
#include <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
#include <QtGui/qvector2d.h>
#include <QtGui/qevent.h>
#include <QtGui/qkeysequence.h>
+#include <QtQuick/qquickitem.h>
QT_BEGIN_NAMESPACE
+class QQuickPointerDevice;
+class QQuickPointerEvent;
+class QQuickPointerMouseEvent;
+class QQuickPointerTabletEvent;
+class QQuickPointerTouchEvent;
+
class QQuickKeyEvent : public QObject
{
Q_OBJECT
@@ -121,7 +129,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
- QQuickMouseEvent() {}
+ QQuickMouseEvent()
+ : _x(0), _y(0), _button(Qt::NoButton), _buttons(Qt::NoButton), _modifiers(Qt::NoModifier)
+ , _source(Qt::MouseEventNotSynthesized), _wasHeld(false), _isClick(false), _accepted(false)
+ {}
void reset(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons,
Qt::KeyboardModifiers modifiers, bool isClick = false, bool wasHeld = false)
@@ -180,7 +191,10 @@ class QQuickWheelEvent : public QObject
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
- QQuickWheelEvent() {}
+ QQuickWheelEvent()
+ : _x(0), _y(0), _buttons(Qt::NoButton), _modifiers(Qt::NoModifier)
+ , _inverted(false), _accepted(false)
+ {}
void reset(qreal x, qreal y, const QPoint &angleDelta, const QPoint &pixelDelta,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, bool inverted)
@@ -216,10 +230,331 @@ private:
bool _accepted;
};
+class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ QQuickCloseEvent()
+ : _accepted(true) {}
+
+ bool isAccepted() { return _accepted; }
+ void setAccepted(bool accepted) { _accepted = accepted; }
+
+private:
+ bool _accepted;
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickEventPoint : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QPointF scenePos READ scenePos)
+ Q_PROPERTY(State state READ state)
+ Q_PROPERTY(quint64 pointId READ pointId)
+ Q_PROPERTY(qreal timeHeld READ timeHeld)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+ Q_PROPERTY(QQuickItem *grabber READ grabber WRITE setGrabber)
+
+public:
+ enum State {
+ Pressed = Qt::TouchPointPressed,
+ Updated = Qt::TouchPointMoved,
+ Stationary = Qt::TouchPointStationary,
+ Released = Qt::TouchPointReleased
+ // Canceled = Qt::TouchPointReleased << 1 // 0x10 // TODO maybe
+ };
+ Q_ENUM(State)
+
+ QQuickEventPoint(QQuickPointerEvent *parent);
+
+ void reset(Qt::TouchPointState state, QPointF scenePos, quint64 pointId, ulong timestamp);
+
+ void invalidate() { m_valid = false; }
+
+ QQuickPointerEvent *pointerEvent() const;
+ QPointF scenePos() const { return m_scenePos; }
+ State state() const { return m_state; }
+ quint64 pointId() const { return m_pointId; }
+ bool isValid() const { return m_valid; }
+ qreal timeHeld() const { return (m_timestamp - m_pressTimestamp) / 1000.0; }
+ bool isAccepted() const { return m_accept; }
+ void setAccepted(bool accepted = true);
+ QQuickItem *grabber() const;
+ void setGrabber(QQuickItem *grabber);
+
+private:
+ QPointF m_scenePos;
+ quint64 m_pointId;
+ QPointer<QQuickItem> m_grabber;
+ ulong m_timestamp;
+ ulong m_pressTimestamp;
+ State m_state;
+ bool m_valid : 1;
+ bool m_accept : 1;
+ int m_reserved : 30;
+
+ Q_DISABLE_COPY(QQuickEventPoint)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickEventTouchPoint : public QQuickEventPoint
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal rotation READ rotation)
+ Q_PROPERTY(qreal pressure READ pressure)
+ Q_PROPERTY(QPointerUniqueId uniqueId READ uniqueId)
+
+public:
+ QQuickEventTouchPoint(QQuickPointerTouchEvent *parent);
+
+ void reset(const QTouchEvent::TouchPoint &tp, ulong timestamp);
+
+ qreal rotation() const { return m_rotation; }
+ qreal pressure() const { return m_pressure; }
+ QPointerUniqueId uniqueId() const { return m_uniqueId; }
+
+private:
+ qreal m_rotation;
+ qreal m_pressure;
+ QPointerUniqueId m_uniqueId;
+
+ Q_DISABLE_COPY(QQuickEventTouchPoint)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(const QQuickPointerDevice *device READ device)
+ Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers)
+ Q_PROPERTY(Qt::MouseButtons button READ button)
+ Q_PROPERTY(Qt::MouseButtons buttons READ buttons)
+
+public:
+ QQuickPointerEvent(QObject *parent = nullptr)
+ : QObject(parent)
+ , m_device(nullptr)
+ , m_event(nullptr)
+ , m_button(Qt::NoButton)
+ , m_pressedButtons(Qt::NoButton)
+ { }
+
+ virtual ~QQuickPointerEvent();
+
+public: // property accessors
+ QQuickPointerDevice *device() const { return m_device; }
+ Qt::KeyboardModifiers modifiers() const { return m_event ? m_event->modifiers() : Qt::NoModifier; }
+ Qt::MouseButton button() const { return m_button; }
+ Qt::MouseButtons buttons() const { return m_pressedButtons; }
+
+public: // helpers for C++ only (during event delivery)
+ virtual QQuickPointerEvent *reset(QEvent *ev) = 0;
+
+ virtual bool isPressEvent() const = 0;
+ virtual QQuickPointerMouseEvent *asPointerMouseEvent() { return nullptr; }
+ virtual QQuickPointerTouchEvent *asPointerTouchEvent() { return nullptr; }
+ virtual QQuickPointerTabletEvent *asPointerTabletEvent() { return nullptr; }
+ virtual const QQuickPointerMouseEvent *asPointerMouseEvent() const { return nullptr; }
+ virtual const QQuickPointerTouchEvent *asPointerTouchEvent() const { return nullptr; }
+ virtual const QQuickPointerTabletEvent *asPointerTabletEvent() const { return nullptr; }
+ bool isValid() const { return m_event != nullptr; }
+ virtual bool allPointsAccepted() const = 0;
+ bool isAccepted() { return m_event->isAccepted(); }
+ void setAccepted(bool accepted) { m_event->setAccepted(accepted); }
+ QVector<QPointF> unacceptedPressedPointScenePositions() const;
+
+ virtual int pointCount() const = 0;
+ virtual QQuickEventPoint *point(int i) const = 0;
+ virtual QQuickEventPoint *pointById(quint64 pointId) const = 0;
+ virtual QVector<QQuickItem *> grabbers() const = 0;
+ virtual void clearGrabbers() const = 0;
+
+ ulong timestamp() const { return m_event->timestamp(); }
+
+protected:
+ QQuickPointerDevice *m_device;
+ QInputEvent *m_event; // original event as received by QQuickWindow
+ Qt::MouseButton m_button;
+ Qt::MouseButtons m_pressedButtons;
+
+ Q_DISABLE_COPY(QQuickPointerEvent)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickPointerEvent
+{
+ Q_OBJECT
+public:
+ QQuickPointerMouseEvent(QObject *parent = nullptr)
+ : QQuickPointerEvent(parent), m_mousePoint(new QQuickEventPoint(this)) { }
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ bool isPressEvent() const override;
+ QQuickPointerMouseEvent *asPointerMouseEvent() override { return this; }
+ const QQuickPointerMouseEvent *asPointerMouseEvent() const override { return this; }
+ int pointCount() const override { return 1; }
+ QQuickEventPoint *point(int i) const override;
+ QQuickEventPoint *pointById(quint64 pointId) const override;
+ bool allPointsAccepted() const override;
+ QVector<QQuickItem *> grabbers() const override;
+ void clearGrabbers() const override;
+
+ QMouseEvent *asMouseEvent(const QPointF& localPos) const;
+
+private:
+ QQuickEventPoint *m_mousePoint;
+
+ Q_DISABLE_COPY(QQuickPointerMouseEvent)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerTouchEvent : public QQuickPointerEvent
+{
+ Q_OBJECT
+public:
+ QQuickPointerTouchEvent(QObject *parent = nullptr)
+ : QQuickPointerEvent(parent)
+ , m_pointCount(0)
+ , m_synthMouseEvent(QEvent::MouseMove, QPointF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier)
+ { }
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ bool isPressEvent() const override;
+ QQuickPointerTouchEvent *asPointerTouchEvent() override { return this; }
+ const QQuickPointerTouchEvent *asPointerTouchEvent() const override { return this; }
+ int pointCount() const override { return m_pointCount; }
+ QQuickEventPoint *point(int i) const override;
+ QQuickEventPoint *pointById(quint64 pointId) const override;
+ const QTouchEvent::TouchPoint *touchPointById(int pointId) const;
+ bool allPointsAccepted() const override;
+ QVector<QQuickItem *> grabbers() const override;
+ void clearGrabbers() const override;
+
+ QMouseEvent *syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const;
+ QTouchEvent *touchEventForItem(QQuickItem *item, bool isFiltering = false) const;
+
+ QTouchEvent *asTouchEvent() const;
+
+private:
+ int m_pointCount;
+ QVector<QQuickEventTouchPoint *> m_touchPoints;
+ mutable QMouseEvent m_synthMouseEvent;
+
+ Q_DISABLE_COPY(QQuickPointerTouchEvent)
+};
+
+// ### Qt 6: move this to qtbase, replace QTouchDevice and the enums in QTabletEvent
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerDevice : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(DeviceType type READ type CONSTANT)
+ Q_PROPERTY(PointerType pointerType READ pointerType CONSTANT)
+ Q_PROPERTY(Capabilities capabilities READ capabilities CONSTANT)
+ Q_PROPERTY(int maximumTouchPoints READ maximumTouchPoints CONSTANT)
+ Q_PROPERTY(int buttonCount READ buttonCount CONSTANT)
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(qint64 uniqueId READ uniqueId CONSTANT)
+
+public:
+ enum DeviceType {
+ UnknownDevice = 0x0000,
+ Mouse = 0x0001,
+ TouchScreen = 0x0002,
+ TouchPad = 0x0004,
+ Puck = 0x0008,
+ Stylus = 0x0010,
+ Airbrush = 0x0020,
+ AllDevices = 0x003F
+ };
+ Q_DECLARE_FLAGS(DeviceTypes, DeviceType)
+ Q_ENUM(DeviceType)
+ Q_FLAG(DeviceTypes)
+
+ enum PointerType {
+ GenericPointer = 0x0001,
+ Finger = 0x0002,
+ Pen = 0x0004,
+ Eraser = 0x0008,
+ Cursor = 0x0010,
+ AllPointerTypes = 0x001F
+ };
+ Q_DECLARE_FLAGS(PointerTypes, PointerType)
+ Q_ENUM(PointerType)
+ Q_FLAG(PointerTypes)
+
+ enum CapabilityFlag {
+ Position = QTouchDevice::Position,
+ Area = QTouchDevice::Area,
+ Pressure = QTouchDevice::Pressure,
+ Velocity = QTouchDevice::Velocity,
+ // some bits reserved in case we need more of QTouchDevice::Capabilities
+ Scroll = 0x0100, // mouse has a wheel, or there is OS-level scroll gesture recognition (dubious?)
+ Hover = 0x0200,
+ Rotation = 0x0400,
+ XTilt = 0x0800,
+ YTilt = 0x1000
+ };
+ Q_DECLARE_FLAGS(Capabilities, CapabilityFlag)
+ Q_ENUM(CapabilityFlag)
+ Q_FLAG(Capabilities)
+
+ QQuickPointerDevice(DeviceType devType, PointerType pType, Capabilities caps, int maxPoints, int buttonCount, const QString &name, qint64 uniqueId = 0)
+ : m_deviceType(devType), m_pointerType(pType), m_capabilities(caps)
+ , m_maximumTouchPoints(maxPoints), m_buttonCount(buttonCount), m_name(name), m_uniqueId(uniqueId), m_event(nullptr)
+ {
+ if (m_deviceType == Mouse) {
+ m_event = new QQuickPointerMouseEvent;
+ } else if (m_deviceType == TouchScreen || m_deviceType == TouchPad) {
+ m_event = new QQuickPointerTouchEvent;
+ } else {
+ Q_ASSERT(false);
+ }
+ }
+
+ ~QQuickPointerDevice() { delete m_event; }
+ DeviceType type() const { return m_deviceType; }
+ PointerType pointerType() const { return m_pointerType; }
+ Capabilities capabilities() const { return m_capabilities; }
+ bool hasCapability(CapabilityFlag cap) { return m_capabilities & cap; }
+ int maximumTouchPoints() const { return m_maximumTouchPoints; }
+ int buttonCount() const { return m_buttonCount; }
+ QString name() const { return m_name; }
+ qint64 uniqueId() const { return m_uniqueId; }
+ QQuickPointerEvent *pointerEvent() const { return m_event; }
+
+ static QQuickPointerDevice *touchDevice(QTouchDevice *d);
+ static QList<QQuickPointerDevice *> touchDevices();
+ static QQuickPointerDevice *genericMouseDevice();
+ static QQuickPointerDevice *tabletDevice(qint64);
+
+private:
+ DeviceType m_deviceType;
+ PointerType m_pointerType;
+ Capabilities m_capabilities;
+ int m_maximumTouchPoints;
+ int m_buttonCount;
+ QString m_name;
+ qint64 m_uniqueId;
+ // the device-specific event instance which is reused during event delivery
+ QQuickPointerEvent *m_event;
+
+ Q_DISABLE_COPY(QQuickPointerDevice)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPointerDevice::DeviceTypes)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPointerDevice::PointerTypes)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPointerDevice::Capabilities)
+
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QQuickPointerDevice *);
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QQuickPointerEvent *);
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QQuickEventPoint *);
+//Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QQuickEventTouchPoint *); TODO maybe
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickKeyEvent)
QML_DECLARE_TYPE(QQuickMouseEvent)
QML_DECLARE_TYPE(QQuickWheelEvent)
+QML_DECLARE_TYPE(QQuickCloseEvent)
+QML_DECLARE_TYPE(QQuickPointerDevice)
+QML_DECLARE_TYPE(QPointerUniqueId)
+QML_DECLARE_TYPE(QQuickPointerEvent)
#endif // QQUICKEVENTS_P_P_H
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 1853a1d948..45bc7b2e8b 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -55,6 +55,8 @@
#include <QtCore/qmath.h>
#include "qplatformdefs.h"
+#include <cmath>
+
QT_BEGIN_NAMESPACE
// FlickThreshold determines how far the "mouse" must have moved
@@ -65,7 +67,24 @@ static const int FlickThreshold = 15;
// will ensure the Flickable retains the grab on consecutive flicks.
static const int RetainGrabVelocity = 100;
+#ifdef Q_OS_OSX
static const int MovementEndingTimerInterval = 100;
+#endif
+
+// Currently std::round can't be used on Android when using ndk g++, so
+// use C version instead. We could just define two versions of Round, one
+// for float and one for double, but then only one of them would be used
+// and compiler would trigger a warning about unused function.
+//
+// See https://code.google.com/p/android/issues/detail?id=54418
+template<typename T>
+static T Round(T t) {
+ return round(t);
+}
+template<>
+Q_DECL_UNUSED float Round<float>(float f) {
+ return roundf(f);
+}
static qreal EaseOvershoot(qreal t) {
return qAtan(t);
@@ -258,7 +277,7 @@ void QQuickFlickablePrivate::init()
Returns the amount to overshoot by given a velocity.
Will be roughly in range 0 - size/4
*/
-qreal QQuickFlickablePrivate::overShootDistance(qreal size)
+qreal QQuickFlickablePrivate::overShootDistance(qreal size) const
{
if (maxVelocity <= 0)
return 0.0;
@@ -290,14 +309,14 @@ void QQuickFlickablePrivate::AxisData::updateVelocity()
}
}
-void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeom, const QRectF &oldGeom)
+void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
{
Q_Q(QQuickFlickable);
if (item == contentItem) {
Qt::Orientations orient = 0;
- if (newGeom.x() != oldGeom.x())
+ if (change.xChange())
orient |= Qt::Horizontal;
- if (newGeom.y() != oldGeom.y())
+ if (change.yChange())
orient |= Qt::Vertical;
if (orient)
q->viewportMoved(orient);
@@ -349,7 +368,7 @@ bool QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExt
qreal dist = v2 / (accel * 2.0);
if (v > 0)
dist = -dist;
- qreal target = -qRound(-(data.move.value() - dist));
+ qreal target = -Round(-(data.move.value() - dist));
dist = -target + data.move.value();
accel = v2 / (2.0f * qAbs(dist));
@@ -453,18 +472,18 @@ void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExt
} else if (data.move.value() <= maxExtent) {
resetTimeline(data);
adjustContentPos(data, maxExtent);
- } else if (-qRound(-data.move.value()) != data.move.value()) {
+ } else if (-Round(-data.move.value()) != data.move.value()) {
// We could animate, but since it is less than 0.5 pixel it's probably not worthwhile.
resetTimeline(data);
qreal val = data.move.value();
- if (qAbs(-qRound(-val) - val) < 0.25) // round small differences
- val = -qRound(-val);
+ if (std::abs(-Round(-val) - val) < 0.25) // round small differences
+ val = -Round(-val);
else if (data.smoothVelocity.value() > 0) // continue direction of motion for larger
- val = -qFloor(-val);
+ val = -std::floor(-val);
else if (data.smoothVelocity.value() < 0)
- val = -qCeil(-val);
+ val = -std::ceil(-val);
else // otherwise round
- val = -qRound(-val);
+ val = -Round(-val);
timeline.set(data.move, val);
}
data.inOvershoot = false;
@@ -855,9 +874,9 @@ bool QQuickFlickable::isAtYBeginning() const
}
\endcode
*/
-QQuickItem *QQuickFlickable::contentItem()
+QQuickItem *QQuickFlickable::contentItem() const
{
- Q_D(QQuickFlickable);
+ Q_D(const QQuickFlickable);
return d->contentItem;
}
@@ -884,7 +903,7 @@ QQuickFlickableVisibleArea *QQuickFlickable::visibleArea()
\li Flickable.AutoFlickIfNeeded - allows flicking vertically if the
\e contentHeight is greater than the \e height of the Flickable.
Allows flicking horizontally if the \e contentWidth is greater than
- to the \e width of the Flickable.
+ to the \e width of the Flickable. (since \c{QtQuick 2.7})
\li Flickable.HorizontalFlick - allows flicking horizontally.
\li Flickable.VerticalFlick - allows flicking vertically.
\li Flickable.HorizontalAndVerticalFlick - allows flicking in both directions.
@@ -932,7 +951,7 @@ void QQuickFlickable::setPixelAligned(bool align)
}
}
-qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
+qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event) const
{
if (0 != event->timestamp())
return event->timestamp();
@@ -941,7 +960,7 @@ qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
return timer.elapsed();
}
-qreal QQuickFlickablePrivate::devicePixelRatio()
+qreal QQuickFlickablePrivate::devicePixelRatio() const
{
return (window ? window->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
}
@@ -1232,13 +1251,17 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
return;
qint64 currentTimestamp = computeCurrentTime(event);
- qreal elapsed = qreal(currentTimestamp - (lastPos.isNull() ? lastPressTime : lastPosTime)) / 1000.;
QVector2D deltas = QVector2D(event->localPos() - pressPos);
bool overThreshold = false;
QVector2D velocity = QGuiApplicationPrivate::mouseEventVelocity(event);
// TODO guarantee that events always have velocity so that it never needs to be computed here
- if (!(QGuiApplicationPrivate::mouseEventCaps(event) & QTouchDevice::Velocity))
+ if (!(QGuiApplicationPrivate::mouseEventCaps(event) & QTouchDevice::Velocity)) {
+ qint64 lastTimestamp = (lastPos.isNull() ? lastPressTime : lastPosTime);
+ if (currentTimestamp == lastTimestamp)
+ return; // events are too close together: velocity would be infinite
+ qreal elapsed = qreal(currentTimestamp - lastTimestamp) / 1000.;
velocity = QVector2D(event->localPos() - (lastPos.isNull() ? pressPos : lastPos)) / elapsed;
+ }
if (q->yflick())
overThreshold |= QQuickWindowPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, event);
@@ -1547,12 +1570,12 @@ void QQuickFlickablePrivate::replayDelayedPress()
//XXX pixelAligned ignores the global position of the Flickable, i.e. assumes Flickable itself is pixel aligned.
void QQuickFlickablePrivate::setViewportX(qreal x)
{
- contentItem->setX(pixelAligned ? -qRound(-x) : x);
+ contentItem->setX(pixelAligned ? -Round(-x) : x);
}
void QQuickFlickablePrivate::setViewportY(qreal y)
{
- contentItem->setY(pixelAligned ? -qRound(-y) : y);
+ contentItem->setY(pixelAligned ? -Round(-y) : y);
}
void QQuickFlickable::timerEvent(QTimerEvent *event)
@@ -1588,13 +1611,13 @@ qreal QQuickFlickable::minXExtent() const
qreal QQuickFlickable::maxXExtent() const
{
Q_D(const QQuickFlickable);
- return qMin<qreal>(0, width() - vWidth() - d->hData.endMargin);
+ return qMin<qreal>(minXExtent(), width() - vWidth() - d->hData.endMargin);
}
/* returns -ve */
qreal QQuickFlickable::maxYExtent() const
{
Q_D(const QQuickFlickable);
- return qMin<qreal>(0, height() - vHeight() - d->vData.endMargin);
+ return qMin<qreal>(minYExtent(), height() - vHeight() - d->vData.endMargin);
}
void QQuickFlickable::componentComplete()
diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h
index 318b8ce473..cd727a2a68 100644
--- a/src/quick/items/qquickflickable_p.h
+++ b/src/quick/items/qquickflickable_p.h
@@ -190,7 +190,7 @@ public:
bool isAtYEnd() const;
bool isAtYBeginning() const;
- QQuickItem *contentItem();
+ QQuickItem *contentItem() const;
enum FlickableDirection { AutoFlickDirection=0x0, HorizontalFlick=0x1, VerticalFlick=0x2, HorizontalAndVerticalFlick=0x3,
AutoFlickIfNeeded=0xc };
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 3c59b19ec2..0c3bc21071 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -62,6 +62,7 @@
#include <private/qquicktimeline_p_p.h>
#include <private/qquickanimation_p_p.h>
#include <private/qquicktransitionmanager_p_p.h>
+#include <private/qpodvector_p.h>
QT_BEGIN_NAMESPACE
@@ -191,9 +192,9 @@ public:
void setViewportX(qreal x);
void setViewportY(qreal y);
- qreal overShootDistance(qreal size);
+ qreal overShootDistance(qreal size) const;
- void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
void draggingStarting();
void draggingEnding();
@@ -259,8 +260,8 @@ public:
const QVector2D &deltas, bool overThreshold, bool momentum,
bool velocitySensitiveOverBounds, const QVector2D &velocity);
- qint64 computeCurrentTime(QInputEvent *event);
- qreal devicePixelRatio();
+ qint64 computeCurrentTime(QInputEvent *event) const;
+ qreal devicePixelRatio() const;
// flickableData property
static void data_append(QQmlListProperty<QObject> *, QObject *);
diff --git a/src/quick/items/qquickflipable.cpp b/src/quick/items/qquickflipable.cpp
index 342e6c07b8..6a6b6c00a9 100644
--- a/src/quick/items/qquickflipable.cpp
+++ b/src/quick/items/qquickflipable.cpp
@@ -143,7 +143,7 @@ QQuickFlipable::~QQuickFlipable()
The front and back sides of the flipable.
*/
-QQuickItem *QQuickFlipable::front()
+QQuickItem *QQuickFlipable::front() const
{
Q_D(const QQuickFlipable);
return d->front;
diff --git a/src/quick/items/qquickflipable_p.h b/src/quick/items/qquickflipable_p.h
index 189d94775a..d5a1e54d25 100644
--- a/src/quick/items/qquickflipable_p.h
+++ b/src/quick/items/qquickflipable_p.h
@@ -73,7 +73,7 @@ public:
QQuickFlipable(QQuickItem *parent=0);
~QQuickFlipable();
- QQuickItem *front();
+ QQuickItem *front() const;
void setFront(QQuickItem *);
QQuickItem *back();
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index d8147a48a5..857cd44b15 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -44,6 +44,7 @@
#include <private/qquickitem_p.h>
#include <QSGSimpleTextureNode>
+#include <QSGRendererInterface>
QT_BEGIN_NAMESPACE
@@ -260,6 +261,12 @@ public:
int devicePixelRatio;
};
+static inline bool isOpenGL(QSGRenderContext *rc)
+{
+ QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc);
+ return !rif || rif->graphicsApi() == QSGRendererInterface::OpenGL;
+}
+
/*!
* \internal
*/
@@ -278,6 +285,8 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
Q_D(QQuickFramebufferObject);
if (!n) {
+ if (!isOpenGL(d->sceneGraphRenderContext()))
+ return 0;
if (!d->node)
d->node = new QSGFramebufferObjectNode;
n = d->node;
@@ -360,6 +369,8 @@ QSGTextureProvider *QQuickFramebufferObject::textureProvider() const
qWarning("QQuickFramebufferObject::textureProvider: can only be queried on the rendering thread of an exposed window");
return 0;
}
+ if (!isOpenGL(d->sceneGraphRenderContext()))
+ return 0;
if (!d->node)
d->node = new QSGFramebufferObjectNode;
return d->node;
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
index 47272a2eac..2f8d71fc11 100644
--- a/src/quick/items/qquickgenericshadereffect.cpp
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -59,9 +59,13 @@ QQuickGenericShaderEffect::QQuickGenericShaderEffect(QQuickShaderEffect *item, Q
, m_blending(true)
, m_supportsAtlasTextures(false)
, m_mgr(nullptr)
+ , m_fragNeedsUpdate(true)
+ , m_vertNeedsUpdate(true)
, m_dirty(0)
{
- connect(m_item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(itemWindowChanged(QQuickWindow*)));
+ qRegisterMetaType<QSGGuiThreadShaderEffectManager::ShaderInfo::Type>("ShaderInfo::Type");
+ for (int i = 0; i < NShader; ++i)
+ m_inProgress[i] = nullptr;
}
QQuickGenericShaderEffect::~QQuickGenericShaderEffect()
@@ -85,12 +89,11 @@ void QQuickGenericShaderEffect::setFragmentShader(const QByteArray &src)
return;
m_fragShader = src;
- m_dirty |= QSGShaderEffectNode::DirtyShaders;
+ m_fragNeedsUpdate = true;
if (m_item->isComponentComplete())
- updateShader(Fragment, src);
+ maybeUpdateShaders();
- m_item->update();
emit m_item->fragmentShaderChanged();
}
@@ -100,12 +103,11 @@ void QQuickGenericShaderEffect::setVertexShader(const QByteArray &src)
return;
m_vertShader = src;
- m_dirty |= QSGShaderEffectNode::DirtyShaders;
+ m_vertNeedsUpdate = true;
if (m_item->isComponentComplete())
- updateShader(Vertex, src);
+ maybeUpdateShaders();
- m_item->update();
emit m_item->vertexShaderChanged();
}
@@ -184,6 +186,12 @@ void QQuickGenericShaderEffect::setSupportsAtlasTextures(bool supports)
emit m_item->supportsAtlasTexturesChanged();
}
+QString QQuickGenericShaderEffect::parseLog()
+{
+ maybeUpdateShaders();
+ return log();
+}
+
QString QQuickGenericShaderEffect::log() const
{
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
@@ -232,6 +240,10 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
return nullptr;
}
+ // Do not change anything while a new shader is being reflected or compiled.
+ if (m_inProgress[Vertex] || m_inProgress[Fragment])
+ return node;
+
// The manager should be already created on the gui thread. Just take that instance.
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
if (!mgr) {
@@ -287,10 +299,22 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
return node;
}
-void QQuickGenericShaderEffect::handleComponentComplete()
+void QQuickGenericShaderEffect::maybeUpdateShaders()
{
- updateShader(Vertex, m_vertShader);
- updateShader(Fragment, m_fragShader);
+ if (m_vertNeedsUpdate)
+ m_vertNeedsUpdate = !updateShader(Vertex, m_vertShader);
+ if (m_fragNeedsUpdate)
+ m_fragNeedsUpdate = !updateShader(Fragment, m_fragShader);
+ if (m_vertNeedsUpdate || m_fragNeedsUpdate) {
+ // This function is invoked either from componentComplete or in a
+ // response to a previous invocation's polish() request. If this is
+ // case #1 then updateShader can fail due to not having a window or
+ // scenegraph ready. Schedule the polish to try again later. In case #2
+ // the backend probably does not have shadereffect support so there is
+ // nothing to do for us here.
+ if (!m_item->window() || !m_item->window()->isSceneGraphInitialized())
+ m_item->polish();
+ }
}
void QQuickGenericShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
@@ -319,43 +343,21 @@ QSGGuiThreadShaderEffectManager *QQuickGenericShaderEffect::shaderEffectManager(
// return null if this is not the gui thread and not already created
if (QThread::currentThread() != m_item->thread())
return m_mgr;
- // need a window and a rendercontext (i.e. the scenegraph backend is ready)
QQuickWindow *w = m_item->window();
- if (w && w->isSceneGraphInitialized()) {
+ if (w) { // note: just the window, don't care about isSceneGraphInitialized() here
m_mgr = QQuickWindowPrivate::get(w)->context->sceneGraphContext()->createGuiThreadShaderEffectManager();
if (m_mgr) {
connect(m_mgr, SIGNAL(logAndStatusChanged()), m_item, SIGNAL(logChanged()));
connect(m_mgr, SIGNAL(logAndStatusChanged()), m_item, SIGNAL(statusChanged()));
connect(m_mgr, SIGNAL(textureChanged()), this, SLOT(markGeometryDirtyAndUpdateIfSupportsAtlas()));
+ connect(m_mgr, &QSGGuiThreadShaderEffectManager::shaderCodePrepared, this, &QQuickGenericShaderEffect::shaderCodePrepared);
}
- } else if (!w) {
- // Wait until itemWindowChanged() gets called. Return null for now.
- } else {
- // Have window, but no scenegraph -> ensure the signal is connected. Return null for now.
- const_cast<QQuickGenericShaderEffect *>(this)->itemWindowChanged(w);
}
}
return m_mgr;
}
-void QQuickGenericShaderEffect::itemWindowChanged(QQuickWindow *w)
-{
- if (w) {
- if (w->isSceneGraphInitialized())
- backendChanged();
- else
- connect(w, SIGNAL(sceneGraphInitialized()), this, SLOT(backendChanged()), Qt::UniqueConnection);
- }
-}
-
-void QQuickGenericShaderEffect::backendChanged()
-{
- disconnect(m_item->window(), SIGNAL(sceneGraphInitialized()), this, SLOT(backendChanged()));
- emit m_item->logChanged();
- emit m_item->statusChanged();
-}
-
void QQuickGenericShaderEffect::disconnectSignals(Shader shaderType)
{
for (auto &sm : m_signalMappers[shaderType]) {
@@ -377,33 +379,33 @@ void QQuickGenericShaderEffect::disconnectSignals(Shader shaderType)
}
}
-struct ReflectCache
+struct ShaderInfoCache
{
bool contains(const QByteArray &key) const
{
- return m_reflectCache.contains(key);
+ return m_shaderInfoCache.contains(key);
}
QSGGuiThreadShaderEffectManager::ShaderInfo value(const QByteArray &key) const
{
- return m_reflectCache.value(key);
+ return m_shaderInfoCache.value(key);
}
void insert(const QByteArray &key, const QSGGuiThreadShaderEffectManager::ShaderInfo &value)
{
- m_reflectCache.insert(key, value);
+ m_shaderInfoCache.insert(key, value);
}
- QHash<QByteArray, QSGGuiThreadShaderEffectManager::ShaderInfo> m_reflectCache;
+ QHash<QByteArray, QSGGuiThreadShaderEffectManager::ShaderInfo> m_shaderInfoCache;
};
-Q_GLOBAL_STATIC(ReflectCache, reflectCache)
+Q_GLOBAL_STATIC(ShaderInfoCache, shaderInfoCache)
-void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray &src)
+bool QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray &src)
{
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
if (!mgr)
- return;
+ return false;
const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
@@ -413,22 +415,26 @@ void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
m_shaders[shaderType].varData.clear();
if (!src.isEmpty()) {
- // Figure out what input parameters and variables are used in the shader.
- // For file-based shader source/bytecode this is where the data is pulled
- // in from the file.
- if (reflectCache()->contains(src)) {
- m_shaders[shaderType].shaderInfo = reflectCache()->value(src);
+ if (shaderInfoCache()->contains(src)) {
+ m_shaders[shaderType].shaderInfo = shaderInfoCache()->value(src);
+ m_shaders[shaderType].hasShaderCode = true;
} else {
- QSGGuiThreadShaderEffectManager::ShaderInfo shaderInfo;
- if (!mgr->reflect(src, &shaderInfo)) {
- qWarning("ShaderEffect: shader reflection failed for %s", src.constData());
- m_shaders[shaderType].hasShaderCode = false;
- return;
- }
- m_shaders[shaderType].shaderInfo = shaderInfo;
- reflectCache()->insert(src, shaderInfo);
+ // Each prepareShaderCode call needs its own work area, hence the
+ // dynamic alloc. If there are calls in progress, let those run to
+ // finish, their results can then simply be ignored because
+ // m_inProgress indicates what we care about.
+ m_inProgress[shaderType] = new QSGGuiThreadShaderEffectManager::ShaderInfo;
+ const QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint =
+ shaderType == Vertex ? QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex
+ : QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
+ // Figure out what input parameters and variables are used in the
+ // shader. For file-based shader source/bytecode this is where the data
+ // is pulled in from the file. Some backends may choose to do
+ // source->bytecode compilation as well in this step.
+ mgr->prepareShaderCode(typeHint, src, m_inProgress[shaderType]);
+ // the rest is handled in shaderCodePrepared()
+ return true;
}
- m_shaders[shaderType].hasShaderCode = true;
} else {
m_shaders[shaderType].hasShaderCode = false;
if (shaderType == Fragment) {
@@ -446,6 +452,49 @@ void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
}
}
+ updateShaderVars(shaderType);
+ m_dirty |= QSGShaderEffectNode::DirtyShaders;
+ m_item->update();
+ return true;
+}
+
+void QQuickGenericShaderEffect::shaderCodePrepared(bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
+ const QByteArray &src, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
+{
+ const Shader shaderType = typeHint == QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex ? Vertex : Fragment;
+
+ // If another call was made to updateShader() for the same shader type in
+ // the meantime then our results are useless, just drop them.
+ if (result != m_inProgress[shaderType]) {
+ delete result;
+ return;
+ }
+
+ m_shaders[shaderType].shaderInfo = *result;
+ delete result;
+ m_inProgress[shaderType] = nullptr;
+
+ if (!ok) {
+ qWarning("ShaderEffect: shader preparation failed for %s\n%s\n", src.constData(), qPrintable(log()));
+ m_shaders[shaderType].hasShaderCode = false;
+ return;
+ }
+
+ m_shaders[shaderType].hasShaderCode = true;
+ shaderInfoCache()->insert(src, m_shaders[shaderType].shaderInfo);
+ updateShaderVars(shaderType);
+ m_dirty |= QSGShaderEffectNode::DirtyShaders;
+ m_item->update();
+}
+
+void QQuickGenericShaderEffect::updateShaderVars(Shader shaderType)
+{
+ QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
+ if (!mgr)
+ return;
+
+ const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
+
const int varCount = m_shaders[shaderType].shaderInfo.variables.count();
m_shaders[shaderType].varData.resize(varCount);
@@ -461,9 +510,9 @@ void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
QSGShaderEffectNode::VariableData &vd(m_shaders[shaderType].varData[i]);
const bool isSpecial = v.name.startsWith("qt_"); // special names not mapped to properties
if (isSpecial) {
- if (v.name == QByteArrayLiteral("qt_Opacity"))
+ if (v.name == "qt_Opacity")
vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
- else if (v.name == QByteArrayLiteral("qt_Matrix"))
+ else if (v.name == "qt_Matrix")
vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
else if (v.name.startsWith("qt_SubRect_"))
vd.specialType = QSGShaderEffectNode::VariableData::SubRect;
diff --git a/src/quick/items/qquickgenericshadereffect_p.h b/src/quick/items/qquickgenericshadereffect_p.h
index ab17a7fb87..ab19816493 100644
--- a/src/quick/items/qquickgenericshadereffect_p.h
+++ b/src/quick/items/qquickgenericshadereffect_p.h
@@ -90,19 +90,22 @@ public:
bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
void setSupportsAtlasTextures(bool supports);
+ QString parseLog();
+
void handleEvent(QEvent *);
void handleGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
QSGNode *handleUpdatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *);
void handleComponentComplete();
void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value);
+ void maybeUpdateShaders();
private slots:
void propertyChanged(int mappedId);
void sourceDestroyed(QObject *object);
void markGeometryDirtyAndUpdate();
void markGeometryDirtyAndUpdateIfSupportsAtlas();
- void itemWindowChanged(QQuickWindow *w);
- void backendChanged();
+ void shaderCodePrepared(bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
+ const QByteArray &src, QSGGuiThreadShaderEffectManager::ShaderInfo *result);
private:
QSGGuiThreadShaderEffectManager *shaderEffectManager() const;
@@ -113,8 +116,9 @@ private:
NShader
};
- void updateShader(Shader which, const QByteArray &src);
- void disconnectSignals(Shader which);
+ bool updateShader(Shader shaderType, const QByteArray &src);
+ void updateShaderVars(Shader shaderType);
+ void disconnectSignals(Shader shaderType);
bool sourceIsUnique(QQuickItem *source, Shader typeToSkip, int indexToSkip) const;
QQuickShaderEffect *m_item;
@@ -126,12 +130,15 @@ private:
bool m_supportsAtlasTextures;
mutable QSGGuiThreadShaderEffectManager *m_mgr;
QByteArray m_fragShader;
+ bool m_fragNeedsUpdate;
QByteArray m_vertShader;
+ bool m_vertNeedsUpdate;
QSGShaderEffectNode::ShaderData m_shaders[NShader];
QSGShaderEffectNode::DirtyShaderFlags m_dirty;
QSet<int> m_dirtyConstants[NShader];
QSet<int> m_dirtyTextures[NShader];
+ QSGGuiThreadShaderEffectManager::ShaderInfo *m_inProgress[NShader];
struct SignalMapper {
SignalMapper() : mapper(nullptr), active(false) { }
diff --git a/src/quick/items/qquickgraphicsinfo.cpp b/src/quick/items/qquickgraphicsinfo.cpp
index 79b0edf031..761d0c3cad 100644
--- a/src/quick/items/qquickgraphicsinfo.cpp
+++ b/src/quick/items/qquickgraphicsinfo.cpp
@@ -112,11 +112,11 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
\endlist
\note The value is only up-to-date once the item is associated with a
- window and the window's scenegraph has initialized. Bindings relying on the
- value have to keep this in mind since the value may change from
- GraphicsInfo.UnknownShadingLanguage to the actual value after component
- initialization is complete. This is particularly relevant for ShaderEffect
- items inside ShaderEffectSource items set as property values.
+ window. Bindings relying on the value have to keep this in mind since the
+ value may change from GraphicsInfo.UnknownShadingLanguage to the actual
+ value after component initialization is complete. This is particularly
+ relevant for ShaderEffect items inside ShaderEffectSource items set as
+ property values.
\since 5.8
\since QtQuick 2.8
@@ -140,11 +140,10 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
expected to focus more on GraphicsInfo.OfflineCompilation, however.
\note The value is only up-to-date once the item is associated with a
- window and the window's scenegraph has initialized. Bindings relying on the
- value have to keep this in mind since the value may change from \c 0 to the
- actual bitmask after component initialization is complete. This is
- particularly relevant for ShaderEffect items inside ShaderEffectSource
- items set as property values.
+ window. Bindings relying on the value have to keep this in mind since the
+ value may change from \c 0 to the actual bitmask after component
+ initialization is complete. This is particularly relevant for ShaderEffect
+ items inside ShaderEffectSource items set as property values.
\since 5.8
\since QtQuick 2.8
@@ -172,11 +171,10 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
bytecode.
\note The value is only up-to-date once the item is associated with a
- window and the window's scenegraph has initialized. Bindings relying on the
- value have to keep this in mind since the value may change from \c 0 to the
- actual bitmask after component initialization is complete. This is
- particularly relevant for ShaderEffect items inside ShaderEffectSource
- items set as property values.
+ window. Bindings relying on the value have to keep this in mind since the
+ value may change from \c 0 to the actual bitmask after component
+ initialization is complete. This is particularly relevant for ShaderEffect
+ items inside ShaderEffectSource items set as property values.
\since 5.8
\since QtQuick 2.8
@@ -240,9 +238,8 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
void QQuickGraphicsInfo::updateInfo()
{
- const bool sgReady = m_window && m_window->isSceneGraphInitialized();
-
- if (sgReady) {
+ // The queries via the RIF do not depend on isSceneGraphInitialized(), they only need a window.
+ if (m_window) {
QSGRendererInterface *rif = m_window->rendererInterface();
if (rif) {
GraphicsApi newAPI = GraphicsApi(rif->graphicsApi());
@@ -261,7 +258,7 @@ void QQuickGraphicsInfo::updateInfo()
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
#ifndef QT_NO_OPENGL
- if (sgReady) {
+ if (m_window && m_window->isSceneGraphInitialized()) {
QOpenGLContext *context = m_window->openglContext();
if (context)
format = context->format();
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index da48fd869d..14ea43f123 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -478,7 +478,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
qreal colPos = colPosAt(visibleIndex);
qreal rowPos = rowPosAt(visibleIndex);
if (visibleItems.count()) {
- FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
+ FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.constLast());
rowPos = lastItem->rowPos();
int colNum = qFloor((lastItem->colPos()+colSize()/2) / colSize());
if (++colNum >= columns) {
@@ -536,7 +536,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
// Find first column
if (visibleItems.count()) {
- FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
+ FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.constFirst());
rowPos = firstItem->rowPos();
colNum = qFloor((firstItem->colPos()+colSize()/2) / colSize());
if (--colNum < 0) {
@@ -586,7 +586,7 @@ bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
bool changed = false;
while (visibleItems.count() > 1
- && (item = static_cast<FxGridItemSG*>(visibleItems.first()))
+ && (item = static_cast<FxGridItemSG*>(visibleItems.constFirst()))
&& item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
if (item->attached->delayRemove())
break;
@@ -598,7 +598,7 @@ bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
changed = true;
}
while (visibleItems.count() > 1
- && (item = static_cast<FxGridItemSG*>(visibleItems.last()))
+ && (item = static_cast<FxGridItemSG*>(visibleItems.constLast()))
&& item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
if (item->attached->delayRemove())
break;
@@ -623,7 +623,7 @@ void QQuickGridViewPrivate::layoutVisibleItems(int fromModelIndex)
const qreal from = isContentFlowReversed() ? -position()-displayMarginBeginning-size() : position()-displayMarginBeginning;
const qreal to = isContentFlowReversed() ? -position()+displayMarginEnd : position()+size()+displayMarginEnd;
- FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
+ FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.constFirst());
qreal rowPos = firstItem->rowPos();
qreal colPos = firstItem->colPos();
int col = visibleIndex % columns;
@@ -679,7 +679,7 @@ void QQuickGridViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
void QQuickGridViewPrivate::resetFirstItemPosition(qreal pos)
{
- FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.first());
+ FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.constFirst());
item->setPosition(0, pos);
}
@@ -692,7 +692,7 @@ void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int
if (moveCount == 0 && changeBeforeVisible != 0)
moveCount += (changeBeforeVisible % columns) - (columns - 1);
- FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.first());
+ FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.constFirst());
gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
}
@@ -1549,10 +1549,12 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
Note that cacheBuffer is not a pixel buffer - it only maintains additional
instantiated delegates.
- Setting this value can make scrolling the list smoother at the expense
- of additional memory usage. It is not a substitute for creating efficient
- delegates; the fewer objects and bindings in a delegate, the faster a view may be
- scrolled.
+ \note Setting this property is not a replacement for creating efficient delegates.
+ It can improve the smoothness of scrolling behavior at the expense of additional
+ memory usage. The fewer objects and bindings in a delegate, the faster a
+ view can be scrolled. It is important to realize that setting a cacheBuffer
+ will only postpone issues caused by slow-loading delegates, it is not a
+ solution for this scenario.
The cacheBuffer operates outside of any display margins specified by
displayMarginBeginning or displayMarginEnd.
@@ -2515,7 +2517,7 @@ void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
int markerItemIndex = -1;
for (int i=0; i<visibleItems.count(); i++) {
- if (visibleItems[i]->index == afterModelIndex) {
+ if (visibleItems.at(i)->index == afterModelIndex) {
markerItemIndex = i;
break;
}
@@ -2534,7 +2536,7 @@ void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
countItemsRemoved -= removalResult.countChangeAfterVisibleItems;
for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
- FxGridItemSG *gridItem = static_cast<FxGridItemSG *>(visibleItems[i]);
+ FxGridItemSG *gridItem = static_cast<FxGridItemSG *>(visibleItems.at(i));
if (!gridItem->transitionScheduledOrRunning()) {
qreal origRowPos = gridItem->colPos();
qreal origColPos = gridItem->rowPos();
@@ -2610,7 +2612,7 @@ bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) co
*/
/*!
- \qmlmethod int QtQuick::GridView::indexAt(int x, int y)
+ \qmlmethod int QtQuick::GridView::indexAt(real x, real y)
Returns the index of the visible item containing the point \a x, \a y in content
coordinates. If there is no item at the point specified, or the item is
@@ -2623,7 +2625,7 @@ bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) co
*/
/*!
- \qmlmethod Item QtQuick::GridView::itemAt(int x, int y)
+ \qmlmethod Item QtQuick::GridView::itemAt(real x, real y)
Returns the visible item containing the point \a x, \a y in content
coordinates. If there is no item at the point specified, or the item is
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index a168b43fd1..a53d068597 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -69,7 +69,7 @@ public:
emit textureChanged();
}
- QSGTexture *texture() const {
+ QSGTexture *texture() const override {
if (m_texture) {
m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest);
m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None);
@@ -614,10 +614,10 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
return 0;
}
- QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
+ QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
d->pixmapChanged = true;
- node = d->sceneGraphContext()->createImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode();
}
QRectF targetRect;
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 60e31631c0..a2b99b6395 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -355,7 +355,7 @@ void QQuickImageBase::resolve2xLocalFile(const QUrl &url, qreal targetDevicePixe
if (disable2xImageLoading)
return;
- QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
+ const QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
// Non-local file path: @2x loading is not supported.
if (localFile.isEmpty())
diff --git a/src/quick/items/qquickimplicitsizeitem.cpp b/src/quick/items/qquickimplicitsizeitem.cpp
index 5dadf81ce4..08886329fd 100644
--- a/src/quick/items/qquickimplicitsizeitem.cpp
+++ b/src/quick/items/qquickimplicitsizeitem.cpp
@@ -42,6 +42,19 @@
QT_BEGIN_NAMESPACE
+/*!
+ \internal
+
+ The purpose of QQuickImplicitSizeItem is not immediately clear, as both
+ the implicit size properties and signals exist on QQuickItem. However,
+ for some items - where the implicit size has an underlying meaning (such as
+ Image, where the implicit size represents the real size of the image)
+ having implicit size writable is an undesirable thing.
+
+ QQuickImplicitSizeItem redefines the properties as being readonly.
+ Unfortunately, this also means they need to redefine the change signals.
+ See QTBUG-30258 for more information.
+*/
void QQuickImplicitSizeItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickImplicitSizeItem);
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 9a13198d7d..09d5e55c24 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -66,7 +66,6 @@
#include <private/qqmlopenmetaobject_p.h>
#include <QtQuick/private/qquickstate_p.h>
#include <private/qquickitem_p.h>
-#include <private/qqmlaccessors_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
#include <private/qv4engine_p.h>
@@ -86,10 +85,7 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE_TARGET)
-
-#ifndef QT_NO_DEBUG
-static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
-#endif
+Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
{
@@ -101,7 +97,8 @@ void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
<< item->hasActiveFocus()
<< item->isFocusScope()
<< item;
- foreach (QQuickItem *child, item->childItems()) {
+ const auto childItems = item->childItems();
+ for (QQuickItem *child : childItems) {
debugFocusTree(
child,
item->isFocusScope() || !scope ? item : scope,
@@ -110,37 +107,6 @@ void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
}
}
-static void QQuickItem_parentNotifier(QObject *o, QQmlNotifier **n)
-{
- QQuickItemPrivate *d = QQuickItemPrivate::get(static_cast<QQuickItem *>(o));
- *n = &d->parentNotifier;
-}
-
-QML_PRIVATE_ACCESSOR(QQuickItem, QQuickItem *, parent, parentItem)
-QML_PRIVATE_ACCESSOR(QQuickItem, qreal, x, x)
-QML_PRIVATE_ACCESSOR(QQuickItem, qreal, y, y)
-QML_PRIVATE_ACCESSOR(QQuickItem, qreal, width, width)
-QML_PRIVATE_ACCESSOR(QQuickItem, qreal, height, height)
-
-static QQmlAccessors QQuickItem_parent = { QQuickItem_parentRead, QQuickItem_parentNotifier };
-static QQmlAccessors QQuickItem_x = { QQuickItem_xRead, 0 };
-static QQmlAccessors QQuickItem_y = { QQuickItem_yRead, 0 };
-static QQmlAccessors QQuickItem_width = { QQuickItem_widthRead, 0 };
-static QQmlAccessors QQuickItem_height = { QQuickItem_heightRead, 0 };
-
-QML_DECLARE_PROPERTIES(QQuickItem) {
- { QML_PROPERTY_NAME(parent), 0, &QQuickItem_parent },
- { QML_PROPERTY_NAME(x), 0, &QQuickItem_x },
- { QML_PROPERTY_NAME(y), 0, &QQuickItem_y },
- { QML_PROPERTY_NAME(width), 0, &QQuickItem_width },
- { QML_PROPERTY_NAME(height), 0, &QQuickItem_height }
-};
-
-void QQuickItemPrivate::registerAccessorProperties()
-{
- QML_DEFINE_PROPERTIES(QQuickItem);
-}
-
/*!
\qmltype Transform
\instantiates QQuickTransform
@@ -180,8 +146,8 @@ QQuickTransform::QQuickTransform(QQuickTransformPrivate &dd, QObject *parent)
QQuickTransform::~QQuickTransform()
{
Q_D(QQuickTransform);
- for (int ii = 0; ii < d->items.count(); ++ii) {
- QQuickItemPrivate *p = QQuickItemPrivate::get(d->items.at(ii));
+ for (QQuickItem *item : qAsConst(d->items)) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
p->transforms.removeOne(this);
p->dirty(QQuickItemPrivate::Transform);
}
@@ -190,8 +156,8 @@ QQuickTransform::~QQuickTransform()
void QQuickTransform::update()
{
Q_D(QQuickTransform);
- for (int ii = 0; ii < d->items.count(); ++ii) {
- QQuickItemPrivate *p = QQuickItemPrivate::get(d->items.at(ii));
+ for (QQuickItem *item : qAsConst(d->items)) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
p->dirty(QQuickItemPrivate::Transform);
}
}
@@ -203,9 +169,7 @@ QQuickContents::QQuickContents(QQuickItem *item)
QQuickContents::~QQuickContents()
{
- QList<QQuickItem *> children = m_item->childItems();
- for (int i = 0; i < children.count(); ++i) {
- QQuickItem *child = children.at(i);
+ for (QQuickItem *child : m_item->childItems()) {
QQuickItemPrivate::get(child)->removeItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
}
}
@@ -228,9 +192,8 @@ bool QQuickContents::calcHeight(QQuickItem *changed)
} else {
qreal top = std::numeric_limits<qreal>::max();
qreal bottom = -std::numeric_limits<qreal>::max();
- QList<QQuickItem *> children = m_item->childItems();
- for (int i = 0; i < children.count(); ++i) {
- QQuickItem *child = children.at(i);
+ const QList<QQuickItem*> children = m_item->childItems();
+ for (QQuickItem *child : qAsConst(children)) {
qreal y = child->y();
if (y + child->height() > bottom)
bottom = y + child->height();
@@ -263,9 +226,8 @@ bool QQuickContents::calcWidth(QQuickItem *changed)
} else {
qreal left = std::numeric_limits<qreal>::max();
qreal right = -std::numeric_limits<qreal>::max();
- QList<QQuickItem *> children = m_item->childItems();
- for (int i = 0; i < children.count(); ++i) {
- QQuickItem *child = children.at(i);
+ const QList<QQuickItem*> children = m_item->childItems();
+ for (QQuickItem *child : qAsConst(children)) {
qreal x = child->x();
if (x + child->width() > right)
right = x + child->width();
@@ -284,9 +246,7 @@ void QQuickContents::complete()
{
QQuickItemPrivate::get(m_item)->addItemChangeListener(this, QQuickItemPrivate::Children);
- QList<QQuickItem *> children = m_item->childItems();
- for (int i = 0; i < children.count(); ++i) {
- QQuickItem *child = children.at(i);
+ for (QQuickItem *child : m_item->childItems()) {
QQuickItemPrivate::get(child)->addItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
//###what about changes to visibility?
}
@@ -298,15 +258,15 @@ void QQuickContents::updateRect()
QQuickItemPrivate::get(m_item)->emitChildrenRectChanged(rectF());
}
-void QQuickContents::itemGeometryChanged(QQuickItem *changed, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickContents::itemGeometryChanged(QQuickItem *changed, QQuickGeometryChange change, const QRectF &)
{
Q_UNUSED(changed)
bool wChanged = false;
bool hChanged = false;
//### we can only pass changed if the left edge has moved left, or the right edge has moved right
- if (newGeometry.width() != oldGeometry.width() || newGeometry.x() != oldGeometry.x())
+ if (change.horizontalChange())
wChanged = calcWidth(/*changed*/);
- if (newGeometry.height() != oldGeometry.height() || newGeometry.y() != oldGeometry.y())
+ if (change.verticalChange())
hChanged = calcHeight(/*changed*/);
if (wChanged || hChanged)
updateRect();
@@ -423,21 +383,44 @@ void QQuickItemKeyFilter::componentComplete()
/*!
\qmlproperty Item QtQuick::KeyNavigation::left
+
+ This property holds the item to assign focus to
+ when the left cursor key is pressed.
+*/
+
+/*!
\qmlproperty Item QtQuick::KeyNavigation::right
+
+ This property holds the item to assign focus to
+ when the right cursor key is pressed.
+*/
+
+/*!
\qmlproperty Item QtQuick::KeyNavigation::up
+
+ This property holds the item to assign focus to
+ when the up cursor key is pressed.
+*/
+
+/*!
\qmlproperty Item QtQuick::KeyNavigation::down
- These properties hold the item to assign focus to
- when the left, right, up or down cursor keys
- are pressed.
+ This property holds the item to assign focus to
+ when the down cursor key is pressed.
*/
/*!
\qmlproperty Item QtQuick::KeyNavigation::tab
+
+ This property holds the item to assign focus to
+ when the Tab key is pressed.
+*/
+
+/*!
\qmlproperty Item QtQuick::KeyNavigation::backtab
- These properties hold the item to assign focus to
- when the Tab key or Shift+Tab key combination (Backtab) are pressed.
+ This property holds the item to assign focus to
+ when the Shift+Tab key combination (Backtab) is pressed.
*/
QQuickKeyNavigationAttached::QQuickKeyNavigationAttached(QObject *parent)
@@ -791,7 +774,7 @@ const SigMap sigMap[] = {
{ 0, 0 }
};
-const QByteArray QQuickKeysAttached::keyToSignal(int key)
+QByteArray QQuickKeysAttached::keyToSignal(int key)
{
QByteArray keySignal;
if (key >= Qt::Key_0 && key <= Qt::Key_9) {
@@ -806,9 +789,9 @@ const QByteArray QQuickKeysAttached::keyToSignal(int key)
return keySignal;
}
-bool QQuickKeysAttached::isConnected(const char *signalName)
+bool QQuickKeysAttached::isConnected(const char *signalName) const
{
- Q_D(QQuickKeysAttached);
+ Q_D(const QQuickKeysAttached);
int signal_index = d->signalIndex(signalName);
return d->isSignalConnected(signal_index);
}
@@ -1318,8 +1301,7 @@ void QQuickKeysAttached::componentComplete()
#ifndef QT_NO_IM
Q_D(QQuickKeysAttached);
if (d->item) {
- for (int ii = 0; ii < d->targets.count(); ++ii) {
- QQuickItem *targetItem = d->targets.at(ii);
+ for (QQuickItem *targetItem : qAsConst(d->targets)) {
if (targetItem && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod)) {
d->item->setFlag(QQuickItem::ItemAcceptsInputMethod);
break;
@@ -1341,11 +1323,10 @@ void QQuickKeysAttached::keyPressed(QKeyEvent *event, bool post)
// first process forwards
if (d->item && d->item->window()) {
d->inPress = true;
- for (int ii = 0; ii < d->targets.count(); ++ii) {
- QQuickItem *i = d->targets.at(ii);
- if (i && i->isVisible()) {
+ for (QQuickItem *targetItem : qAsConst(d->targets)) {
+ if (targetItem && targetItem->isVisible()) {
event->accept();
- QCoreApplication::sendEvent(i, event);
+ QCoreApplication::sendEvent(targetItem, event);
if (event->isAccepted()) {
d->inPress = false;
return;
@@ -1385,11 +1366,10 @@ void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post)
if (d->item && d->item->window()) {
d->inRelease = true;
- for (int ii = 0; ii < d->targets.count(); ++ii) {
- QQuickItem *i = d->targets.at(ii);
- if (i && i->isVisible()) {
+ for (QQuickItem *targetItem : qAsConst(d->targets)) {
+ if (targetItem && targetItem->isVisible()) {
event->accept();
- QCoreApplication::sendEvent(i, event);
+ QCoreApplication::sendEvent(targetItem, event);
if (event->isAccepted()) {
d->inRelease = false;
return;
@@ -1413,12 +1393,11 @@ void QQuickKeysAttached::inputMethodEvent(QInputMethodEvent *event, bool post)
Q_D(QQuickKeysAttached);
if (post == m_processPost && d->item && !d->inIM && d->item->window()) {
d->inIM = true;
- for (int ii = 0; ii < d->targets.count(); ++ii) {
- QQuickItem *i = d->targets.at(ii);
- if (i && i->isVisible() && (i->flags() & QQuickItem::ItemAcceptsInputMethod)) {
- d->item->window()->sendEvent(i, event);
+ for (QQuickItem *targetItem : qAsConst(d->targets)) {
+ if (targetItem && targetItem->isVisible() && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod)) {
+ QCoreApplication::sendEvent(targetItem, event);
if (event->isAccepted()) {
- d->imeItem = i;
+ d->imeItem = targetItem;
d->inIM = false;
return;
}
@@ -1433,13 +1412,12 @@ QVariant QQuickKeysAttached::inputMethodQuery(Qt::InputMethodQuery query) const
{
Q_D(const QQuickKeysAttached);
if (d->item) {
- for (int ii = 0; ii < d->targets.count(); ++ii) {
- QQuickItem *i = d->targets.at(ii);
- if (i && i->isVisible() && (i->flags() & QQuickItem::ItemAcceptsInputMethod) && i == d->imeItem) {
- //### how robust is i == d->imeItem check?
- QVariant v = i->inputMethodQuery(query);
+ for (QQuickItem *targetItem : qAsConst(d->targets)) {
+ if (targetItem && targetItem->isVisible() && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod) && targetItem == d->imeItem) {
+ //### how robust is targetItem == d->imeItem check?
+ QVariant v = targetItem->inputMethodQuery(query);
if (v.userType() == QVariant::RectF)
- v = d->item->mapRectFromItem(i, v.toRectF()); //### cost?
+ v = d->item->mapRectFromItem(targetItem, v.toRectF()); //### cost?
return v;
}
}
@@ -1472,6 +1450,9 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj)
behavior to all child items as well. If the \c LayoutMirroring attached property has not been defined
for an item, mirroring is not enabled.
+ \note Since Qt 5.8, \c LayoutMirroring can be attached to a \l Window. In practice, it is the same as
+ attaching \c LayoutMirroring to the window's \c contentItem.
+
The following example shows mirroring in action. The \l Row below is specified as being anchored
to the left of its parent. However, since mirroring has been enabled, the anchor is horizontally
reversed and it is now anchored to the right. Also, since items in a \l Row are positioned
@@ -1521,11 +1502,15 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj)
QQuickLayoutMirroringAttached::QQuickLayoutMirroringAttached(QObject *parent) : QObject(parent), itemPrivate(0)
{
- if (QQuickItem *item = qobject_cast<QQuickItem*>(parent)) {
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(parent))
itemPrivate = QQuickItemPrivate::get(item);
+ else if (QQuickWindow *window = qobject_cast<QQuickWindow *>(parent))
+ itemPrivate = QQuickItemPrivate::get(window->contentItem());
+
+ if (itemPrivate)
itemPrivate->extra.value().layoutDirectionAttached = this;
- } else
- qmlInfo(parent) << tr("LayoutDirection attached property only works with Items");
+ else
+ qmlInfo(parent) << tr("LayoutDirection attached property only works with Items and Windows");
}
QQuickLayoutMirroringAttached * QQuickLayoutMirroringAttached::qmlAttachedProperties(QObject *object)
@@ -1596,11 +1581,9 @@ void QQuickItemPrivate::setImplicitLayoutMirror(bool mirror, bool inherit)
if (isMirrorImplicit)
setLayoutMirror(inherit ? inheritedLayoutMirror : false);
- for (int i = 0; i < childItems.count(); ++i) {
- if (QQuickItem *child = qmlobject_cast<QQuickItem *>(childItems.at(i))) {
- QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
- childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent);
- }
+ for (QQuickItem *child : qAsConst(childItems)) {
+ QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
+ childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent);
}
}
@@ -2083,6 +2066,9 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
\value ItemDevicePixelRatioHasChanged The device pixel ratio of the screen
the item is on has changed. ItemChangedData::realValue contains the new
device pixel ratio.
+
+ \value ItemAntialiasingHasChanged The antialiasing has changed. The current
+ (boolean) value can be found in QQuickItem::antialiasing.
*/
/*!
@@ -2304,29 +2290,11 @@ QQuickItem::QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent)
d->init(parent);
}
-#ifndef QT_NO_DEBUG
-static int qt_item_count = 0;
-
-static void qt_print_item_count()
-{
- qDebug("Number of leaked items: %i", qt_item_count);
- qt_item_count = -1;
-}
-#endif
-
/*!
Destroys the QQuickItem.
*/
QQuickItem::~QQuickItem()
{
-#ifndef QT_NO_DEBUG
- if (qsg_leak_check) {
- --qt_item_count;
- if (qt_item_count < 0)
- qDebug("Item destroyed after qt_print_item_count() was called.");
- }
-#endif
-
Q_D(QQuickItem);
if (d->windowRefCount > 1)
@@ -2340,8 +2308,9 @@ QQuickItem::~QQuickItem()
while (!d->childItems.isEmpty())
d->childItems.constFirst()->setParentItem(0);
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- QQuickAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
if (anchor)
anchor->clearItem(this);
}
@@ -2350,14 +2319,13 @@ QQuickItem::~QQuickItem()
update item anchors that depended on us unless they are our child (and will also be destroyed),
or our sibling, and our parent is also being destroyed.
*/
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- QQuickAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
if (anchor && anchor->item && anchor->item->parentItem() && anchor->item->parentItem() != this)
anchor->update();
}
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Destroyed)
change.listener->itemDestroyed(this);
}
@@ -2369,8 +2337,7 @@ QQuickItem::~QQuickItem()
remove themselves from our list of transforms when that list has already
been destroyed after ~QQuickItem() has run.
*/
- for (int ii = 0; ii < d->transforms.count(); ++ii) {
- QQuickTransform *t = d->transforms.at(ii);
+ for (QQuickTransform *t : qAsConst(d->transforms)) {
QQuickTransformPrivate *tp = QQuickTransformPrivate::get(t);
tp->items.removeOne(this);
}
@@ -2736,8 +2703,6 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
d->itemChange(ItemParentHasChanged, d->parentItem);
- d->parentNotifier.notify();
-
emit parentChanged(d->parentItem);
if (isVisible() && d->parentItem)
emit d->parentItem->visibleChildrenChanged();
@@ -2861,8 +2826,8 @@ QList<QQuickItem *> QQuickItemPrivate::paintOrderChildItems() const
// If none of the items have set Z then the paint order list is the same as
// the childItems list. This is by far the most common case.
bool haveZ = false;
- for (int i = 0; i < childItems.count(); ++i) {
- if (QQuickItemPrivate::get(childItems.at(i))->z() != 0.) {
+ for (QQuickItem *childItem : qAsConst(childItems)) {
+ if (QQuickItemPrivate::get(childItem)->z() != 0.) {
haveZ = true;
break;
}
@@ -2891,10 +2856,10 @@ void QQuickItemPrivate::addChild(QQuickItem *child)
// if the added child has a cursor and we do not currently have any children
// with cursors, bubble the notification up
- if (childPrivate->hasCursorInChild && !hasCursorInChild)
+ if (childPrivate->subtreeCursorEnabled && !subtreeCursorEnabled)
setHasCursorInChild(true);
#endif
- if (childPrivate->hasHoverInChild && !hasHoverInChild)
+ if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled)
setHasHoverInChild(true);
markSortedChildrenDirty(child);
@@ -2918,10 +2883,10 @@ void QQuickItemPrivate::removeChild(QQuickItem *child)
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
// turn it off, if nothing else is using it
- if (childPrivate->hasCursorInChild && hasCursorInChild)
+ if (childPrivate->subtreeCursorEnabled && subtreeCursorEnabled)
setHasCursorInChild(false);
#endif
- if (childPrivate->hasHoverInChild && hasHoverInChild)
+ if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled)
setHasHoverInChild(false);
markSortedChildrenDirty(child);
@@ -2961,8 +2926,7 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c)
if (!parentItem)
QQuickWindowPrivate::get(window)->parentlessItems.insert(q);
- for (int ii = 0; ii < childItems.count(); ++ii) {
- QQuickItem *child = childItems.at(ii);
+ for (QQuickItem *child : qAsConst(childItems)) {
QQuickItemPrivate::get(child)->refWindow(c);
}
@@ -2989,13 +2953,7 @@ void QQuickItemPrivate::derefWindow()
QQuickWindowPrivate *c = QQuickWindowPrivate::get(window);
if (polishScheduled)
c->itemsToPolish.removeOne(q);
- QMutableHashIterator<int, QQuickItem *> itemTouchMapIt(c->itemForTouchPointId);
- while (itemTouchMapIt.hasNext()) {
- if (itemTouchMapIt.next().value() == q)
- itemTouchMapIt.remove();
- }
- if (c->mouseGrabberItem == q)
- c->mouseGrabberItem = 0;
+ c->removeGrabber(q);
#ifndef QT_NO_CURSOR
if (c->cursorItem == q) {
c->cursorItem = 0;
@@ -3020,8 +2978,7 @@ void QQuickItemPrivate::derefWindow()
paintNode = 0;
- for (int ii = 0; ii < childItems.count(); ++ii) {
- QQuickItem *child = childItems.at(ii);
+ for (QQuickItem *child : qAsConst(childItems)) {
QQuickItemPrivate::get(child)->derefWindow();
}
@@ -3144,8 +3101,8 @@ QQuickItemPrivate::QQuickItemPrivate()
, isAccessible(false)
, culled(false)
, hasCursor(false)
- , hasCursorInChild(false)
- , hasHoverInChild(false)
+ , subtreeCursorEnabled(false)
+ , subtreeHoverEnabled(false)
, activeFocusOnTab(false)
, implicitAntialiasing(false)
, antialiasingValid(false)
@@ -3179,21 +3136,8 @@ QQuickItemPrivate::~QQuickItemPrivate()
void QQuickItemPrivate::init(QQuickItem *parent)
{
-#ifndef QT_NO_DEBUG
- if (qsg_leak_check) {
- ++qt_item_count;
- static bool atexit_registered = false;
- if (!atexit_registered) {
- atexit(qt_print_item_count);
- atexit_registered = true;
- }
- }
-#endif
-
Q_Q(QQuickItem);
- registerAccessorProperties();
-
baselineOffset = 0.0;
if (parent) {
@@ -3338,7 +3282,7 @@ void QQuickItemPrivate::resources_clear(QQmlListProperty<QObject> *prop)
QQuickItem *quickItem = static_cast<QQuickItem *>(prop->object);
QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(quickItem);
if (quickItemPrivate->extra.isAllocated()) {//If extra is not allocated resources is empty.
- foreach (QObject *object, quickItemPrivate->extra->resourcesList) {
+ for (QObject *object : qAsConst(quickItemPrivate->extra->resourcesList)) {
qmlobject_disconnect(object, QObject, SIGNAL(destroyed(QObject*)),
quickItem, QQuickItem, SLOT(_q_resourceObjectDeleted(QObject*)));
}
@@ -3479,8 +3423,7 @@ void QQuickItemPrivate::transform_clear(QQmlListProperty<QQuickTransform> *prop)
QQuickItem *that = static_cast<QQuickItem *>(prop->object);
QQuickItemPrivate *p = QQuickItemPrivate::get(that);
- for (int ii = 0; ii < p->transforms.count(); ++ii) {
- QQuickTransform *t = p->transforms.at(ii);
+ for (QQuickTransform *t : qAsConst(p->transforms)) {
QQuickTransformPrivate *tp = QQuickTransformPrivate::get(t);
tp->items.removeOne(that);
}
@@ -3604,8 +3547,8 @@ QQuickAnchors *QQuickItemPrivate::anchors() const
void QQuickItemPrivate::siblingOrderChanged()
{
Q_Q(QQuickItem);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::SiblingOrder) {
change.listener->itemSiblingOrderChanged(q);
}
@@ -3708,32 +3651,31 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
if (d->_anchors)
QQuickAnchorsPrivate::get(d->_anchors)->updateMe();
- bool xChange = (newGeometry.x() != oldGeometry.x());
- bool yChange = (newGeometry.y() != oldGeometry.y());
- bool widthChange = (newGeometry.width() != oldGeometry.width());
- bool heightChange = (newGeometry.height() != oldGeometry.height());
-
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
- if (change.types & QQuickItemPrivate::Geometry) {
- if (change.gTypes == QQuickItemPrivate::GeometryChange) {
- change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
- } else if ((xChange && (change.gTypes & QQuickItemPrivate::XChange)) ||
- (yChange && (change.gTypes & QQuickItemPrivate::YChange)) ||
- (widthChange && (change.gTypes & QQuickItemPrivate::WidthChange)) ||
- (heightChange && (change.gTypes & QQuickItemPrivate::HeightChange))) {
- change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
- }
+ QQuickGeometryChange change;
+ QRectF diff(newGeometry.x() - oldGeometry.x(),
+ newGeometry.y() - oldGeometry.y(),
+ newGeometry.width() - oldGeometry.width(),
+ newGeometry.height() - oldGeometry.height());
+ change.setXChange(diff.x() != 0);
+ change.setYChange(diff.y() != 0);
+ change.setWidthChange(diff.width() != 0);
+ change.setHeightChange(diff.height() != 0);
+
+ const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &listener : listeners) {
+ if (listener.types & QQuickItemPrivate::Geometry) {
+ if (change.matches(listener.gTypes))
+ listener.listener->itemGeometryChanged(this, change, diff);
}
}
- if (xChange)
+ if (change.xChange())
emit xChanged();
- if (yChange)
+ if (change.yChange())
emit yChanged();
- if (widthChange)
+ if (change.widthChange())
emit widthChanged();
- if (heightChange)
+ if (change.heightChange())
emit heightChanged();
}
@@ -3798,6 +3740,11 @@ QSGNode *QQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *upda
return 0;
}
+QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
+: transformNode(0)
+{
+}
+
/*!
This function is called when an item should release graphics
resources which are not already managed by the nodes returend from
@@ -3847,10 +3794,11 @@ void QQuickItemPrivate::removeItemChangeListener(QQuickItemChangeListener *liste
changeListeners.removeOne(change);
}
-void QQuickItemPrivate::updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types)
+void QQuickItemPrivate::updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener,
+ QQuickGeometryChange types)
{
ChangeListener change(listener, types);
- int index = changeListeners.find(change);
+ int index = changeListeners.indexOf(change);
if (index > -1)
changeListeners[index].gTypes = change.gTypes; //we may have different GeometryChangeTypes
else
@@ -3858,13 +3806,13 @@ void QQuickItemPrivate::updateOrAddGeometryChangeListener(QQuickItemChangeListen
}
void QQuickItemPrivate::updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener,
- GeometryChangeTypes types)
+ QQuickGeometryChange types)
{
ChangeListener change(listener, types);
- if (types == NoChange) {
+ if (types.noChange()) {
changeListeners.removeOne(change);
} else {
- int index = changeListeners.find(change);
+ int index = changeListeners.indexOf(change);
if (index > -1)
changeListeners[index].gTypes = change.gTypes; //we may have different GeometryChangeTypes
}
@@ -4130,7 +4078,8 @@ bool QQuickItem::childMouseEventFilter(QQuickItem *item, QEvent *event)
*/
void QQuickItem::windowDeactivateEvent()
{
- foreach (QQuickItem* item, childItems()) {
+ const auto children = childItems();
+ for (QQuickItem* item : children) {
item->windowDeactivateEvent();
}
}
@@ -4273,8 +4222,8 @@ void QQuickItem::setBaselineOffset(qreal offset)
d->baselineOffset = offset;
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Geometry) {
QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
if (anchor)
@@ -4845,14 +4794,16 @@ void QQuickItem::componentComplete()
QQuickAnchorsPrivate::get(d->_anchors)->updateOnComplete();
}
- if (d->extra.isAllocated() && d->extra->layer)
- d->extra->layer->componentComplete();
+ if (d->extra.isAllocated()) {
+ if (d->extra->layer)
+ d->extra->layer->componentComplete();
- if (d->extra.isAllocated() && d->extra->keyHandler)
- d->extra->keyHandler->componentComplete();
+ if (d->extra->keyHandler)
+ d->extra->keyHandler->componentComplete();
- if (d->extra.isAllocated() && d->extra->contents)
- d->extra->contents->complete();
+ if (d->extra->contents)
+ d->extra->contents->complete();
+ }
if (d->window && d->dirtyAttributes) {
d->addToDirtyList();
@@ -5746,13 +5697,13 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
if (window) {
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
- if (windowPriv->mouseGrabberItem == q)
- q->ungrabMouse();
+ windowPriv->removeGrabber(q);
}
bool childVisibilityChanged = false;
- for (int ii = 0; ii < childItems.count(); ++ii)
- childVisibilityChanged |= QQuickItemPrivate::get(childItems.at(ii))->setEffectiveVisibleRecur(newEffectiveVisible);
+ for (QQuickItem *childItem : qAsConst(childItems)) {
+ childVisibilityChanged |= QQuickItemPrivate::get(childItem)->setEffectiveVisibleRecur(newEffectiveVisible);
+ }
itemChange(QQuickItem::ItemVisibleHasChanged, effectiveVisible);
#ifndef QT_NO_ACCESSIBILITY
@@ -5794,16 +5745,15 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
if (window) {
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
- if (windowPriv->mouseGrabberItem == q)
- q->ungrabMouse();
+ windowPriv->removeGrabber(q);
if (scope && !effectiveEnable && activeFocus) {
windowPriv->clearFocusInScope(
scope, q, Qt::OtherFocusReason, QQuickWindowPrivate::DontChangeFocusProperty | QQuickWindowPrivate::DontChangeSubFocusItem);
}
}
- for (int ii = 0; ii < childItems.count(); ++ii) {
- QQuickItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur(
+ for (QQuickItem *childItem : qAsConst(childItems)) {
+ QQuickItemPrivate::get(childItem)->setEffectiveEnableRecur(
(flags & QQuickItem::ItemIsFocusScope) && scope ? q : scope, newEffectiveEnable);
}
@@ -5945,66 +5895,72 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
{
Q_Q(QQuickItem);
switch (change) {
- case QQuickItem::ItemChildAddedChange:
+ case QQuickItem::ItemChildAddedChange: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Children) {
change.listener->itemChildAdded(q, data.item);
}
}
break;
- case QQuickItem::ItemChildRemovedChange:
+ }
+ case QQuickItem::ItemChildRemovedChange: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Children) {
change.listener->itemChildRemoved(q, data.item);
}
}
break;
+ }
case QQuickItem::ItemSceneChange:
q->itemChange(change, data);
break;
- case QQuickItem::ItemVisibleHasChanged:
+ case QQuickItem::ItemVisibleHasChanged: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Visibility) {
change.listener->itemVisibilityChanged(q);
}
}
break;
- case QQuickItem::ItemParentHasChanged:
+ }
+ case QQuickItem::ItemParentHasChanged: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Parent) {
change.listener->itemParentChanged(q, data.item);
}
}
break;
- case QQuickItem::ItemOpacityHasChanged:
+ }
+ case QQuickItem::ItemOpacityHasChanged: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Opacity) {
change.listener->itemOpacityChanged(q);
}
}
break;
+ }
case QQuickItem::ItemActiveFocusHasChanged:
q->itemChange(change, data);
break;
- case QQuickItem::ItemRotationHasChanged:
+ case QQuickItem::ItemRotationHasChanged: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Rotation) {
change.listener->itemRotationChanged(q);
}
}
break;
+ }
case QQuickItem::ItemAntialiasingHasChanged:
// fall through
case QQuickItem::ItemDevicePixelRatioHasChanged:
@@ -6359,8 +6315,8 @@ void QQuickItem::resetWidth()
void QQuickItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickItem);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::ImplicitWidth) {
change.listener->itemImplicitWidthChanged(q);
}
@@ -6523,8 +6479,8 @@ void QQuickItem::resetHeight()
void QQuickItemPrivate::implicitHeightChanged()
{
Q_Q(QQuickItem);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::ImplicitHeight) {
change.listener->itemImplicitHeightChanged(q);
}
@@ -7022,17 +6978,18 @@ void QQuickItemPrivate::setHasCursorInChild(bool hasCursor)
Q_Q(QQuickItem);
// if we're asked to turn it off (because of an unsetcursor call, or a node
- // removal) then we should check our children and make sure it's really ok
- // to turn it off.
- if (!hasCursor && hasCursorInChild) {
- foreach (QQuickItem *otherChild, childItems) {
+ // removal) then we should make sure it's really ok to turn it off.
+ if (!hasCursor && subtreeCursorEnabled) {
+ if (hasCursor)
+ return; // nope! sorry, I have a cursor myself
+ for (QQuickItem *otherChild : qAsConst(childItems)) {
QQuickItemPrivate *otherChildPrivate = QQuickItemPrivate::get(otherChild);
- if (otherChildPrivate->hasCursorInChild)
+ if (otherChildPrivate->subtreeCursorEnabled || otherChildPrivate->hasCursor)
return; // nope! sorry, something else wants it kept on.
}
}
- hasCursorInChild = hasCursor;
+ subtreeCursorEnabled = hasCursor;
QQuickItem *parent = q->parentItem();
if (parent) {
QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent);
@@ -7046,17 +7003,19 @@ void QQuickItemPrivate::setHasHoverInChild(bool hasHover)
Q_Q(QQuickItem);
// if we're asked to turn it off (because of a setAcceptHoverEvents call, or a node
- // removal) then we should check our children and make sure it's really ok
- // to turn it off.
- if (!hasHover && hasHoverInChild) {
- foreach (QQuickItem *otherChild, childItems) {
+ // removal) then we should make sure it's really ok to turn it off.
+ if (!hasHover && subtreeHoverEnabled) {
+ if (hoverEnabled)
+ return; // nope! sorry, I need hover myself
+ for (QQuickItem *otherChild : qAsConst(childItems)) {
QQuickItemPrivate *otherChildPrivate = QQuickItemPrivate::get(otherChild);
- if (otherChildPrivate->hasHoverInChild)
+ if (otherChildPrivate->subtreeHoverEnabled || otherChildPrivate->hoverEnabled)
return; // nope! sorry, something else wants it kept on.
}
}
- hasHoverInChild = hasHover;
+ qCDebug(DBG_HOVER_TRACE) << q << subtreeHoverEnabled << "->" << hasHover;
+ subtreeHoverEnabled = hasHover;
QQuickItem *parent = q->parentItem();
if (parent) {
QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent);
@@ -7069,7 +7028,7 @@ void QQuickItemPrivate::markObjects(QV4::ExecutionEngine *e)
Q_Q(QQuickItem);
QV4::QObjectWrapper::markWrapper(q, e);
- foreach (QQuickItem *child, childItems)
+ for (QQuickItem *child : qAsConst(childItems))
QQuickItemPrivate::get(child)->markObjects(e);
}
@@ -7163,6 +7122,11 @@ void QQuickItem::unsetCursor()
Grabs the mouse input.
This item will receive all mouse events until ungrabMouse() is called.
+ Usually this function should not be called, since accepting for example
+ a mouse press event makes sure that the following events are delivered
+ to the item.
+ If an item wants to take over mouse events from the current receiver,
+ it needs to call this function.
\warning This function should be used with caution.
*/
@@ -7177,6 +7141,12 @@ void QQuickItem::grabMouse()
/*!
Releases the mouse grab following a call to grabMouse().
+
+ Note that this function should only be called when the item wants
+ to stop handling further events. There is no need to call this function
+ after a release or cancel event since no future events will be received
+ in any case. No move or release events will be delivered after this
+ function was called.
*/
void QQuickItem::ungrabMouse()
{
@@ -7184,16 +7154,7 @@ void QQuickItem::ungrabMouse()
if (!d->window)
return;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window);
- if (windowPriv->mouseGrabberItem != this) {
- qWarning("QQuickItem::ungrabMouse(): Item is not the mouse grabber.");
- return;
- }
-
- qCDebug(DBG_MOUSE_TARGET) << "ungrabMouse" << windowPriv->mouseGrabberItem << "-> null";
- windowPriv->mouseGrabberItem = 0;
-
- QEvent ev(QEvent::UngrabMouse);
- d->window->sendEvent(this, &ev);
+ windowPriv->removeGrabber(this, true, false);
}
@@ -7246,32 +7207,16 @@ void QQuickItem::grabTouchPoints(const QVector<int> &ids)
if (!d->window)
return;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window);
-
- QSet<QQuickItem*> ungrab;
- for (int i = 0; i < ids.count(); ++i) {
- QQuickItem *oldGrabber = windowPriv->itemForTouchPointId.value(ids.at(i));
- if (oldGrabber == this)
- return;
-
- windowPriv->itemForTouchPointId[ids.at(i)] = this;
- if (oldGrabber)
- ungrab.insert(oldGrabber);
-
- QQuickItem *mouseGrabber = windowPriv->mouseGrabberItem;
- if (windowPriv->touchMouseId == ids.at(i) && mouseGrabber && mouseGrabber != this) {
- qCDebug(DBG_MOUSE_TARGET) << "grabTouchPoints: grabber" << windowPriv->mouseGrabberItem << "-> null";
- windowPriv->mouseGrabberItem = 0;
- QEvent ev(QEvent::UngrabMouse);
- d->window->sendEvent(mouseGrabber, &ev);
- }
- }
- foreach (QQuickItem *oldGrabber, ungrab)
- oldGrabber->touchUngrabEvent();
+ windowPriv->grabTouchPoints(this, ids);
}
/*!
Ungrabs the touch points owned by this item.
+ \note there is hardly any reason to call this function. It should only be
+ called when an item does not want to receive any further events, so no
+ move or release events will be delivered after calling this function.
+
\sa grabTouchPoints()
*/
void QQuickItem::ungrabTouchPoints()
@@ -7280,14 +7225,7 @@ void QQuickItem::ungrabTouchPoints()
if (!d->window)
return;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window);
-
- QMutableHashIterator<int, QQuickItem*> i(windowPriv->itemForTouchPointId);
- while (i.hasNext()) {
- i.next();
- if (i.value() == this)
- i.remove();
- }
- touchUngrabEvent();
+ windowPriv->removeGrabber(this, false, true);
}
/*!
@@ -7346,7 +7284,9 @@ void QQuickItem::setKeepTouchGrab(bool keep)
bool QQuickItem::contains(const QPointF &point) const
{
Q_D(const QQuickItem);
- return QRectF(0, 0, d->width, d->height).contains(point);
+ qreal x = point.x();
+ qreal y = point.y();
+ return x >= 0 && y >= 0 && x <= d->width && y <= d->height;
}
/*!
@@ -8149,7 +8089,7 @@ void QQuickItemLayer::itemOpacityChanged(QQuickItem *item)
updateOpacity();
}
-void QQuickItemLayer::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &)
+void QQuickItemLayer::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
{
updateGeometry();
}
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index c5c17615ee..87ae83246c 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -148,7 +148,6 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QQmlParserStatus
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQuickItemLayer *layer READ layer DESIGNABLE false CONSTANT FINAL)
Q_CLASSINFO("DefaultProperty", "data")
- Q_CLASSINFO("qt_HasQmlAccessors", "true")
public:
enum Flag {
@@ -369,7 +368,6 @@ Q_SIGNALS:
void clipChanged(bool);
Q_REVISION(1) void windowChanged(QQuickWindow* window);
- // XXX todo
void childrenChanged();
void opacityChanged();
void enabledChanged();
@@ -454,7 +452,6 @@ private:
Q_DECLARE_PRIVATE(QQuickItem)
};
-// XXX todo
Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickItem::Flags)
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 477071f7b3..c5cac2ff1e 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -63,7 +63,6 @@
#include <QtQuick/qsgnode.h>
#include "qquickclipnode_p.h"
-#include <private/qpodvector_p.h>
#include <QtQuick/private/qquickstate_p.h>
#include <private/qqmlnullablevalue_p.h>
#include <private/qqmlnotifier_p.h>
@@ -99,7 +98,7 @@ public:
void complete();
protected:
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE;
void itemChildAdded(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
void itemChildRemoved(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
@@ -189,7 +188,7 @@ public:
QQuickShaderEffectSource *effectSource() const { return m_effectSource; }
- void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
void itemOpacityChanged(QQuickItem *) Q_DECL_OVERRIDE;
void itemParentChanged(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
void itemSiblingOrderChanged(QQuickItem *) Q_DECL_OVERRIDE;
@@ -245,8 +244,6 @@ public:
static QQuickItemPrivate* get(QQuickItem *item) { return item->d_func(); }
static const QQuickItemPrivate* get(const QQuickItem *item) { return item->d_func(); }
- static void registerAccessorProperties();
-
QQuickItemPrivate();
~QQuickItemPrivate();
void init(QQuickItem *parent);
@@ -319,24 +316,12 @@ public:
Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
- enum GeometryChangeType {
- NoChange = 0,
- XChange = 0x01,
- YChange = 0x02,
- WidthChange = 0x04,
- HeightChange = 0x08,
- SizeChange = WidthChange | HeightChange,
- GeometryChange = XChange | YChange | SizeChange
- };
-
- Q_DECLARE_FLAGS(GeometryChangeTypes, GeometryChangeType)
-
struct ChangeListener {
- ChangeListener(QQuickItemChangeListener *l, QQuickItemPrivate::ChangeTypes t) : listener(l), types(t), gTypes(GeometryChange) {}
- ChangeListener(QQuickItemChangeListener *l, QQuickItemPrivate::GeometryChangeTypes gt) : listener(l), types(Geometry), gTypes(gt) {}
+ ChangeListener(QQuickItemChangeListener *l = nullptr, QQuickItemPrivate::ChangeTypes t = 0) : listener(l), types(t), gTypes(QQuickGeometryChange::All) {}
+ ChangeListener(QQuickItemChangeListener *l, QQuickGeometryChange gt) : listener(l), types(Geometry), gTypes(gt) {}
QQuickItemChangeListener *listener;
QQuickItemPrivate::ChangeTypes types;
- QQuickItemPrivate::GeometryChangeTypes gTypes; //NOTE: not used for ==
+ QQuickGeometryChange gTypes; //NOTE: not used for ==
bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
};
@@ -386,12 +371,12 @@ public:
inline Qt::MouseButtons acceptedMouseButtons() const;
- QPODVector<QQuickItemPrivate::ChangeListener,4> changeListeners;
+ QVector<QQuickItemPrivate::ChangeListener> changeListeners;
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types);
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types);
- void updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types);
- void updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types);
+ void updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, QQuickGeometryChange types);
+ void updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener, QQuickGeometryChange types);
QQuickStateGroup *_states();
QQuickStateGroup *_stateGroup;
@@ -427,9 +412,9 @@ public:
bool isAccessible:1;
bool culled:1;
bool hasCursor:1;
- bool hasCursorInChild:1;
+ bool subtreeCursorEnabled:1;
// Bit 32
- bool hasHoverInChild:1;
+ bool subtreeHoverEnabled:1;
bool activeFocusOnTab:1;
bool implicitAntialiasing:1;
bool antialiasingValid:1;
@@ -489,7 +474,6 @@ public:
inline QSGRenderContext *sceneGraphRenderContext() const;
QQuickItem *parentItem;
- QQmlNotifier parentNotifier;
QList<QQuickItem *> childItems;
mutable QList<QQuickItem *> *sortedChildItems;
@@ -611,6 +595,8 @@ public:
// recursive helper to let a visual parent mark its visual children
void markObjects(QV4::ExecutionEngine *e);
+
+ virtual void updatePolish() { }
};
/*
@@ -870,9 +856,9 @@ private:
void inputMethodEvent(QInputMethodEvent *, bool post) Q_DECL_OVERRIDE;
QVariant inputMethodQuery(Qt::InputMethodQuery query) const Q_DECL_OVERRIDE;
#endif
- const QByteArray keyToSignal(int key);
+ static QByteArray keyToSignal(int key);
- bool isConnected(const char *signalName);
+ bool isConnected(const char *signalName) const;
};
Qt::MouseButtons QQuickItemPrivate::acceptedMouseButtons() const
@@ -935,6 +921,7 @@ QSGNode *QQuickItemPrivate::childContainerNode()
}
Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickItemPrivate::ChangeTypes)
+Q_DECLARE_TYPEINFO(QQuickItemPrivate::ChangeListener, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp
index 962f410095..5c0caf5ca2 100644
--- a/src/quick/items/qquickitemanimation.cpp
+++ b/src/quick/items/qquickitemanimation.cpp
@@ -200,6 +200,27 @@ QPointF QQuickParentAnimationPrivate::computeTransformOrigin(QQuickItem::Transfo
}
}
+struct QQuickParentAnimationData : public QAbstractAnimationAction
+{
+ QQuickParentAnimationData() : reverse(false) {}
+ ~QQuickParentAnimationData() { qDeleteAll(pc); }
+
+ QQuickStateActions actions;
+ //### reverse should probably apply on a per-action basis
+ bool reverse;
+ QList<QQuickParentChange *> pc;
+ void doAction() Q_DECL_OVERRIDE
+ {
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ const QQuickStateAction &action = actions.at(ii);
+ if (reverse)
+ action.event->reverse();
+ else
+ action.event->execute();
+ }
+ }
+};
+
QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
@@ -207,27 +228,6 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act
{
Q_D(QQuickParentAnimation);
- struct QQuickParentAnimationData : public QAbstractAnimationAction
- {
- QQuickParentAnimationData() : reverse(false) {}
- ~QQuickParentAnimationData() { qDeleteAll(pc); }
-
- QQuickStateActions actions;
- //### reverse should probably apply on a per-action basis
- bool reverse;
- QList<QQuickParentChange *> pc;
- void doAction() Q_DECL_OVERRIDE
- {
- for (int ii = 0; ii < actions.count(); ++ii) {
- const QQuickStateAction &action = actions.at(ii);
- if (reverse)
- action.event->reverse();
- else
- action.event->execute();
- }
- }
- };
-
QQuickParentAnimationData *data = new QQuickParentAnimationData;
QQuickParentAnimationData *viaData = new QQuickParentAnimationData;
@@ -339,9 +339,9 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act
qreal w = target->width();
qreal h = target->height();
if (pc->widthIsSet() && i < actions.size() - 1)
- w = actions[++i].toValue.toReal();
+ w = actions.at(++i).toValue.toReal();
if (pc->heightIsSet() && i < actions.size() - 1)
- h = actions[++i].toValue.toReal();
+ h = actions.at(++i).toValue.toReal();
const QPointF &transformOrigin
= d->computeTransformOrigin(target->transformOrigin(), w,h);
qreal tempxt = transformOrigin.x();
diff --git a/src/quick/items/qquickitemanimation_p_p.h b/src/quick/items/qquickitemanimation_p_p.h
index 5b18e4b0ae..99c973eb25 100644
--- a/src/quick/items/qquickitemanimation_p_p.h
+++ b/src/quick/items/qquickitemanimation_p_p.h
@@ -93,7 +93,7 @@ public:
entryInterval(0), exitInterval(0) {}
~QQuickPathAnimationUpdater() {}
- void setValue(qreal v);
+ void setValue(qreal v) override;
QQuickPath *path;
@@ -129,7 +129,7 @@ public:
void clearTemplate() { animationTemplate = 0; }
- QQuickPathAnimationUpdater *pathUpdater() { return static_cast<QQuickPathAnimationUpdater*>(getAnimValue()); }
+ QQuickPathAnimationUpdater *pathUpdater() const { return static_cast<QQuickPathAnimationUpdater*>(getAnimValue()); }
private:
QQuickPathAnimationPrivate *animationTemplate;
};
diff --git a/src/quick/items/qquickitemchangelistener_p.h b/src/quick/items/qquickitemchangelistener_p.h
index 6e3ef25506..19ff73056b 100644
--- a/src/quick/items/qquickitemchangelistener_p.h
+++ b/src/quick/items/qquickitemchangelistener_p.h
@@ -58,12 +58,69 @@ QT_BEGIN_NAMESPACE
class QRectF;
class QQuickItem;
class QQuickAnchorsPrivate;
+
+class QQuickGeometryChange
+{
+public:
+ enum Kind: int {
+ Nothing = 0x00,
+ X = 0x01,
+ Y = 0x02,
+ Width = 0x04,
+ Height = 0x08,
+
+ Size = Width | Height,
+ All = X | Y | Size
+ };
+
+ QQuickGeometryChange(int change = Nothing)
+ : kind(change)
+ {}
+
+ bool noChange() const { return kind == Nothing; }
+ bool anyChange() const { return !noChange(); }
+
+ bool xChange() const { return kind & X; }
+ bool yChange() const { return kind & Y; }
+ bool widthChange() const { return kind & Width; }
+ bool heightChange() const { return kind & Height; }
+
+ bool positionChange() const { return xChange() || yChange(); }
+ bool sizeChange() const { return widthChange() || heightChange(); }
+
+ bool horizontalChange() const { return xChange() || widthChange(); }
+ bool verticalChange() const { return yChange() || heightChange(); }
+
+ void setXChange(bool enabled) { set(X, enabled); }
+ void setYChange(bool enabled) { set(Y, enabled); }
+ void setWidthChange(bool enabled) { set(Width, enabled); }
+ void setHeightChange(bool enabled) { set(Height, enabled); }
+ void setSizeChange(bool enabled) { set(Size, enabled); }
+ void setAllChanged(bool enabled) { set(All, enabled); }
+ void setHorizontalChange(bool enabled) { set(X | Width, enabled); }
+ void setVerticalChange(bool enabled) { set(Y | Height, enabled); }
+
+ void set(int bits, bool enabled)
+ {
+ if (enabled) {
+ kind |= bits;
+ } else {
+ kind &= ~bits;
+ }
+ }
+
+ bool matches(QQuickGeometryChange other) const { return kind & other.kind; }
+
+private:
+ int kind;
+};
+
class QQuickItemChangeListener
{
public:
virtual ~QQuickItemChangeListener() {}
- virtual void itemGeometryChanged(QQuickItem *, const QRectF & /* new */, const QRectF & /* old */ ) {}
+ virtual void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF & /* diff */) {}
virtual void itemSiblingOrderChanged(QQuickItem *) {}
virtual void itemVisibilityChanged(QQuickItem *) {}
virtual void itemOpacityChanged(QQuickItem *) {}
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index 019352c57a..6865ee2654 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -180,13 +180,26 @@ QQuickItemGrabResult::QQuickItemGrabResult(QObject *parent)
/*!
* Saves the grab result as an image to \a fileName. Returns true
* if successful; otherwise returns false.
+ *
+ * \note In Qt versions prior to 5.9, this function is marked as non-\c{const}.
*/
-bool QQuickItemGrabResult::saveToFile(const QString &fileName)
+bool QQuickItemGrabResult::saveToFile(const QString &fileName) const
{
- Q_D(QQuickItemGrabResult);
+ Q_D(const QQuickItemGrabResult);
return d->image.save(fileName);
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+/*!
+ * \overload
+ * \internal
+ */
+bool QQuickItemGrabResult::saveToFile(const QString &fileName)
+{
+ return qAsConst(*this).saveToFile(fileName);
+}
+#endif // < Qt 6
+
QUrl QQuickItemGrabResult::url() const
{
Q_D(const QQuickItemGrabResult);
@@ -299,7 +312,7 @@ QQuickItemGrabResult *QQuickItemGrabResultPrivate::create(QQuickItem *item, cons
* Use \a targetSize to specify the size of the target image. By default, the
* result will have the same size as item.
*
- * If the grab could not be initiated, the function returns a \c null.
+ * If the grab could not be initiated, the function returns \c null.
*
* \note This function will render the item to an offscreen surface and
* copy that surface from the GPU's memory into the CPU's memory, which can
@@ -326,7 +339,8 @@ QSharedPointer<QQuickItemGrabResult> QQuickItem::grabToImage(const QSize &target
* Grabs the item into an in-memory image.
*
* The grab happens asynchronously and the JavaScript function \a callback is
- * invoked when the grab is completed.
+ * invoked when the grab is completed. The callback takes one argument, which
+ * is the result of the grab operation; an \l ItemGrabResult object.
*
* Use \a targetSize to specify the size of the target image. By default, the result
* will have the same size as the item.
diff --git a/src/quick/items/qquickitemgrabresult.h b/src/quick/items/qquickitemgrabresult.h
index 42d71862de..30f8f0c2ef 100644
--- a/src/quick/items/qquickitemgrabresult.h
+++ b/src/quick/items/qquickitemgrabresult.h
@@ -64,10 +64,13 @@ public:
QImage image() const;
QUrl url() const;
- Q_INVOKABLE bool saveToFile(const QString &fileName);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ Q_INVOKABLE bool saveToFile(const QString &fileName); // ### Qt 6: remove
+#endif
+ Q_INVOKABLE bool saveToFile(const QString &fileName) const;
protected:
- bool event(QEvent *);
+ bool event(QEvent *) override;
Q_SIGNALS:
void ready();
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 8ed7f2bb05..1bc1aebe4f 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -73,11 +73,11 @@
//#include <private/qquickpincharea_p.h>
#include <QtQuick/private/qquickcanvasitem_p.h>
#include <QtQuick/private/qquickcontext2d_p.h>
-# include "qquickitemgrabresult.h"
+#include "qquickitemgrabresult.h"
+#include "qquicksprite_p.h"
+#include "qquickspritesequence_p.h"
+#include "qquickanimatedsprite_p.h"
#ifndef QT_NO_OPENGL
-# include "qquicksprite_p.h"
-# include "qquickspritesequence_p.h"
-# include "qquickanimatedsprite_p.h"
# include "qquickopenglinfo_p.h"
#endif
#include "qquickgraphicsinfo_p.h"
@@ -133,7 +133,6 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
{
QQmlPrivate::RegisterAutoParent autoparent = { 0, &qquickitem_autoParent };
QQmlPrivate::qmlregister(QQmlPrivate::AutoParentRegistration, &autoparent);
- QQuickItemPrivate::registerAccessorProperties();
#ifdef QT_NO_MOVIE
qmlRegisterTypeNotAvailable(uri,major,minor,"AnimatedImage", QCoreApplication::translate("QQuickAnimatedImage","Qt was built without support for QMovie"));
@@ -218,11 +217,11 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterUncreatableType<QQuickPaintedItem>("QtQuick", 2, 0, "PaintedItem", QQuickPaintedItem::tr("Cannot create instance of abstract class PaintedItem"));
qmlRegisterType<QQuickCanvasItem>("QtQuick", 2, 0, "Canvas");
-#ifndef QT_NO_OPENGL
+
qmlRegisterType<QQuickSprite>("QtQuick", 2, 0, "Sprite");
qmlRegisterType<QQuickAnimatedSprite>("QtQuick", 2, 0, "AnimatedSprite");
qmlRegisterType<QQuickSpriteSequence>("QtQuick", 2, 0, "SpriteSequence");
-#endif
+
qmlRegisterType<QQuickParentChange>(uri, major, minor,"ParentChange");
qmlRegisterType<QQuickAnchorChanges>(uri, major, minor,"AnchorChanges");
qmlRegisterType<QQuickAnchorSet>();
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index aff03b7539..d02ed07de0 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -181,7 +181,7 @@ void QQuickItemViewChangeSet::applyChanges(const QQmlChangeSet &changeSet)
int moveId = -1;
int moveOffset = 0;
- foreach (const QQmlChangeSet::Change &r, changeSet.removes()) {
+ for (const QQmlChangeSet::Change &r : changeSet.removes()) {
itemCount -= r.count;
if (moveId == -1 && newCurrentIndex >= r.index + r.count) {
newCurrentIndex -= r.count;
@@ -200,7 +200,7 @@ void QQuickItemViewChangeSet::applyChanges(const QQmlChangeSet &changeSet)
currentChanged = true;
}
}
- foreach (const QQmlChangeSet::Change &i, changeSet.inserts()) {
+ for (const QQmlChangeSet::Change &i : changeSet.inserts()) {
if (moveId == -1) {
if (itemCount && newCurrentIndex >= i.index) {
newCurrentIndex += i.count;
@@ -935,9 +935,11 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
return;
applyPendingChanges();
- int idx = qMax(qMin(index, model->count()-1), 0);
+ const int modelCount = model->count();
+ int idx = qMax(qMin(index, modelCount - 1), 0);
- qreal pos = isContentFlowReversed() ? -position() - size() : position();
+ const auto viewSize = size();
+ qreal pos = isContentFlowReversed() ? -position() - viewSize : position();
FxViewItem *item = visibleItem(idx);
qreal maxExtent = calculatedMaxExtent();
if (!item) {
@@ -961,22 +963,22 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
pos -= headerSize();
break;
case QQuickItemView::Center:
- pos = itemPos - (size() - item->size())/2;
+ pos = itemPos - (viewSize - item->size())/2;
break;
case QQuickItemView::End:
- pos = itemPos - size() + item->size();
- if (footer && (index >= model->count() || hasStickyFooter()))
+ pos = itemPos - viewSize + item->size();
+ if (footer && (index >= modelCount || hasStickyFooter()))
pos += footerSize();
break;
case QQuickItemView::Visible:
- if (itemPos > pos + size())
- pos = itemPos - size() + item->size();
+ if (itemPos > pos + viewSize)
+ pos = itemPos - viewSize + item->size();
else if (item->endPosition() <= pos)
pos = itemPos;
break;
case QQuickItemView::Contain:
- if (item->endPosition() >= pos + size())
- pos = itemPos - size() + item->size();
+ if (item->endPosition() >= pos + viewSize)
+ pos = itemPos - viewSize + item->size();
if (itemPos < pos)
pos = itemPos;
break;
@@ -1025,28 +1027,27 @@ void QQuickItemView::positionViewAtEnd()
d->positionViewAtIndex(d->model->count(), End);
}
-int QQuickItemView::indexAt(qreal x, qreal y) const
+static FxViewItem * fxViewItemAtPosition(const QList<FxViewItem *> &items, qreal x, qreal y)
{
- Q_D(const QQuickItemView);
- for (int i = 0; i < d->visibleItems.count(); ++i) {
- const FxViewItem *item = d->visibleItems.at(i);
+ for (FxViewItem *item : items) {
if (item->contains(x, y))
- return item->index;
+ return item;
}
+ return nullptr;
+}
- return -1;
+int QQuickItemView::indexAt(qreal x, qreal y) const
+{
+ Q_D(const QQuickItemView);
+ const FxViewItem *item = fxViewItemAtPosition(d->visibleItems, x, y);
+ return item ? item->index : -1;
}
QQuickItem *QQuickItemView::itemAt(qreal x, qreal y) const
{
Q_D(const QQuickItemView);
- for (int i = 0; i < d->visibleItems.count(); ++i) {
- const FxViewItem *item = d->visibleItems.at(i);
- if (item->contains(x, y))
- return item->item;
- }
-
- return 0;
+ const FxViewItem *item = fxViewItemAtPosition(d->visibleItems, x, y);
+ return item ? item->item : nullptr;
}
void QQuickItemView::forceLayout()
@@ -1199,16 +1200,17 @@ void QQuickItemViewPrivate::showVisibleItems() const
{
qDebug() << "Visible items:";
for (int i = 0; i < visibleItems.count(); ++i) {
- qDebug() << "\t" << visibleItems[i]->index
- << visibleItems[i]->item->objectName()
- << visibleItems[i]->position();
+ qDebug() << "\t" << visibleItems.at(i)->index
+ << visibleItems.at(i)->item->objectName()
+ << visibleItems.at(i)->position();
}
}
-void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
+ const QRectF &diff)
{
Q_Q(QQuickItemView);
- QQuickFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
+ QQuickFlickablePrivate::itemGeometryChanged(item, change, diff);
if (!q->isComponentComplete())
return;
@@ -1621,12 +1623,10 @@ qreal QQuickItemViewPrivate::contentStartOffset() const
int QQuickItemViewPrivate::findLastVisibleIndex(int defaultValue) const
{
- if (visibleItems.count()) {
- int i = visibleItems.count() - 1;
- while (i > 0 && visibleItems.at(i)->index == -1)
- --i;
- if (visibleItems.at(i)->index != -1)
- return visibleItems.at(i)->index;
+ for (auto it = visibleItems.rbegin(), end = visibleItems.rend(); it != end; ++it) {
+ auto item = *it;
+ if (item->index != -1)
+ return item->index;
}
return defaultValue;
}
@@ -1657,9 +1657,10 @@ FxViewItem *QQuickItemViewPrivate::firstVisibleItem() const {
int QQuickItemViewPrivate::findLastIndexInView() const
{
const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
- for (int i=visibleItems.count() - 1; i>=0; i--) {
- if (visibleItems.at(i)->position() <= viewEndPos && visibleItems.at(i)->index != -1)
- return visibleItems.at(i)->index;
+ for (auto it = visibleItems.rbegin(), end = visibleItems.rend(); it != end; ++it) {
+ auto item = *it;
+ if (item->index != -1 && item->position() <= viewEndPos)
+ return item->index;
}
return -1;
}
@@ -1787,10 +1788,11 @@ void QQuickItemViewPrivate::animationFinished(QAbstractAnimationJob *)
void QQuickItemViewPrivate::refill()
{
qreal s = qMax(size(), qreal(0.));
+ const auto pos = position();
if (isContentFlowReversed())
- refill(-position()-displayMarginBeginning-s, -position()+displayMarginEnd);
+ refill(-pos - displayMarginBeginning-s, -pos + displayMarginEnd);
else
- refill(position()-displayMarginBeginning, position()+displayMarginEnd+s);
+ refill(pos - displayMarginBeginning, pos + displayMarginEnd+s);
}
void QQuickItemViewPrivate::refill(qreal from, qreal to)
@@ -1997,7 +1999,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
prevViewPos = prevFirstVisible->position();
prevFirstVisibleIndex = prevFirstVisible->index;
}
- qreal prevVisibleItemsFirstPos = visibleItems.count() ? visibleItems.first()->position() : 0.0;
+ qreal prevVisibleItemsFirstPos = visibleItems.count() ? visibleItems.constFirst()->position() : 0.0;
totalInsertionResult->visiblePos = prevViewPos;
totalRemovalResult->visiblePos = prevViewPos;
@@ -2076,13 +2078,13 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
// can transition it from this "original" position to its new position in the view
if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true)) {
for (int i=0; i<movingIntoView.count(); i++) {
- int fromIndex = findMoveKeyIndex(movingIntoView[i].moveKey, removals);
+ int fromIndex = findMoveKeyIndex(movingIntoView.at(i).moveKey, removals);
if (fromIndex >= 0) {
if (prevFirstVisibleIndex >= 0 && fromIndex < prevFirstVisibleIndex)
- repositionItemAt(movingIntoView[i].item, fromIndex, -totalInsertionResult->sizeChangesAfterVisiblePos);
+ repositionItemAt(movingIntoView.at(i).item, fromIndex, -totalInsertionResult->sizeChangesAfterVisiblePos);
else
- repositionItemAt(movingIntoView[i].item, fromIndex, totalInsertionResult->sizeChangesAfterVisiblePos);
- movingIntoView[i].item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, true);
+ repositionItemAt(movingIntoView.at(i).item, fromIndex, totalInsertionResult->sizeChangesAfterVisiblePos);
+ movingIntoView.at(i).item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, true);
}
}
}
@@ -2128,11 +2130,11 @@ bool QQuickItemViewPrivate::applyRemovalChange(const QQmlChangeSet::Change &remo
Q_Q(QQuickItemView);
bool visibleAffected = false;
- if (visibleItems.count() && removal.index + removal.count > visibleItems.last()->index) {
- if (removal.index > visibleItems.last()->index)
+ if (visibleItems.count() && removal.index + removal.count > visibleItems.constLast()->index) {
+ if (removal.index > visibleItems.constLast()->index)
removeResult->countChangeAfterVisibleItems += removal.count;
else
- removeResult->countChangeAfterVisibleItems += ((removal.index + removal.count - 1) - visibleItems.last()->index);
+ removeResult->countChangeAfterVisibleItems += ((removal.index + removal.count - 1) - visibleItems.constLast()->index);
}
QList<FxViewItem*>::Iterator it = visibleItems.begin();
@@ -2222,10 +2224,11 @@ void QQuickItemViewPrivate::repositionFirstItem(FxViewItem *prevVisibleItemsFirs
qreal moveBackwardsBy = 0;
// shift visibleItems.first() relative to the number of added/removed items
- if (visibleItems.first()->position() > prevViewPos) {
+ const auto pos = visibleItems.constFirst()->position();
+ if (pos > prevViewPos) {
moveForwardsBy = insertionResult->sizeChangesAfterVisiblePos;
moveBackwardsBy = removalResult->sizeChangesAfterVisiblePos;
- } else if (visibleItems.first()->position() < prevViewPos) {
+ } else if (pos < prevViewPos) {
moveForwardsBy = removalResult->sizeChangesBeforeVisiblePos;
moveBackwardsBy = insertionResult->sizeChangesBeforeVisiblePos;
}
@@ -2303,7 +2306,7 @@ bool QQuickItemViewPrivate::prepareNonVisibleItemTransition(FxViewItem *item, co
void QQuickItemViewPrivate::viewItemTransitionFinished(QQuickItemViewTransitionableItem *item)
{
for (int i=0; i<releasePendingTransition.count(); i++) {
- if (releasePendingTransition[i]->transitionableItem == item) {
+ if (releasePendingTransition.at(i)->transitionableItem == item) {
releaseItem(releasePendingTransition.takeAt(i));
return;
}
@@ -2323,8 +2326,8 @@ FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
return 0;
for (int i=0; i<releasePendingTransition.count(); i++) {
- if (releasePendingTransition[i]->index == modelIndex
- && !releasePendingTransition[i]->isPendingRemoval()) {
+ if (releasePendingTransition.at(i)->index == modelIndex
+ && !releasePendingTransition.at(i)->isPendingRemoval()) {
releasePendingTransition[i]->releaseAfterTransition = false;
return releasePendingTransition.takeAt(i);
}
@@ -2427,14 +2430,14 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
return flags != QQmlInstanceModel::Referenced;
}
-QQuickItem *QQuickItemViewPrivate::createHighlightItem()
+QQuickItem *QQuickItemViewPrivate::createHighlightItem() const
{
return createComponentItem(highlightComponent, 0.0, true);
}
-QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault)
+QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault) const
{
- Q_Q(QQuickItemView);
+ Q_Q(const QQuickItemView);
QQuickItem *item = 0;
if (component) {
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index 1a28fc212b..0e9a2f31be 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -312,7 +312,7 @@ public:
: QObject(parent), m_isCurrent(false), m_delayRemove(false) {}
~QQuickItemViewAttached() {}
- QQuickItemView *view() { return m_view; }
+ QQuickItemView *view() const { return m_view; }
void setView(QQuickItemView *view) {
if (view != m_view) {
m_view = view;
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 5e104cf208..f3d39bd360 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -205,8 +205,8 @@ public:
FxViewItem *createItem(int modelIndex, bool asynchronous = false);
virtual bool releaseItem(FxViewItem *item);
- QQuickItem *createHighlightItem();
- QQuickItem *createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault = false);
+ QQuickItem *createHighlightItem() const;
+ QQuickItem *createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault = false) const;
void updateCurrent(int modelIndex);
void updateTrackedItem();
@@ -378,7 +378,7 @@ protected:
virtual void updateSectionCriteria() {}
virtual void updateSections() {}
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
};
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index 6d2421c3df..83c451613e 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -246,7 +246,7 @@ void QQuickItemViewTransitioner::resetTargetLists()
moveTransitionTargets.clear();
}
-QQuickTransition *QQuickItemViewTransitioner::transitionObject(QQuickItemViewTransitioner::TransitionType type, bool asTarget)
+QQuickTransition *QQuickItemViewTransitioner::transitionObject(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const
{
if (type == QQuickItemViewTransitioner::NoTransition)
return 0;
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 6641dada29..e79c3b26f6 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -94,7 +94,7 @@ public:
void addToTargetLists(QQuickItemViewTransitioner::TransitionType type, QQuickItemViewTransitionableItem *item, int index);
void resetTargetLists();
- QQuickTransition *transitionObject(QQuickItemViewTransitioner::TransitionType type, bool asTarget);
+ QQuickTransition *transitionObject(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const;
const QList<int> &targetIndexes(QQuickItemViewTransitioner::TransitionType type) const;
const QList<QObject *> &targetItems(QQuickItemViewTransitioner::TransitionType type) const;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index f843b09592..47efecdb2d 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -131,7 +131,7 @@ public:
void updateAverage();
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) Q_DECL_OVERRIDE;
void fixupPosition() Q_DECL_OVERRIDE;
void fixup(AxisData &data, qreal minExtent, qreal maxExtent) Q_DECL_OVERRIDE;
bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
@@ -400,7 +400,7 @@ FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
++idx;
}
if (lastIndex == modelIndex-1)
- return visibleItems.last();
+ return visibleItems.constLast();
return 0;
}
@@ -752,7 +752,7 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
}
}
- while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
+ while (visibleItems.count() > 1 && (item = visibleItems.constLast()) && item->position() > bufferTo) {
if (item->attached->delayRemove())
break;
qCDebug(lcItemViewDelegateLifecycle) << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position() << (QObject *)(item->item);
@@ -839,7 +839,7 @@ void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
void QQuickListViewPrivate::resetFirstItemPosition(qreal pos)
{
- FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.first());
+ FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.constFirst());
item->setPosition(pos);
}
@@ -848,12 +848,12 @@ void QQuickListViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int
if (!visibleItems.count())
return;
qreal diff = forwards - backwards;
- static_cast<FxListItemSG*>(visibleItems.first())->setPosition(visibleItems.first()->position() + diff);
+ static_cast<FxListItemSG*>(visibleItems.constFirst())->setPosition(visibleItems.constFirst()->position() + diff);
}
void QQuickListViewPrivate::updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult)
{
- if (item != visibleItems.first())
+ if (item != visibleItems.constFirst())
QQuickItemViewPrivate::updateSizeChangesBeforeVisiblePos(item, removeResult);
}
@@ -1270,7 +1270,7 @@ void QQuickListViewPrivate::initializeCurrentItem()
if (!actualItem) {
if (currentIndex == visibleIndex - 1 && visibleItems.count()) {
// We can calculate exact postion in this case
- listItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
+ listItem->setPosition(visibleItems.constFirst()->position() - currentItem->size() - spacing);
} else {
// Create current item now and position as best we can.
// Its position will be corrected when it becomes visible.
@@ -1400,10 +1400,12 @@ bool QQuickListViewPrivate::hasStickyFooter() const
return footer && footerPositioning != QQuickListView::InlineFooter;
}
-void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
+ const QRectF &diff)
{
Q_Q(QQuickListView);
- QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
+
+ QQuickItemViewPrivate::itemGeometryChanged(item, change, diff);
if (!q->isComponentComplete())
return;
@@ -1417,29 +1419,31 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &
}
if (item != contentItem && (!highlight || item != highlight->item)) {
- if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height())
- || (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
+ if ((orient == QQuickListView::Vertical && change.heightChange())
+ || (orient == QQuickListView::Horizontal && change.widthChange())) {
// if visibleItems.first() has resized, adjust its pos since it is used to
// position all subsequent items
- if (visibleItems.count() && item == visibleItems.first()->item) {
- FxListItemSG *listItem = static_cast<FxListItemSG*>(visibleItems.first());
+ if (visibleItems.count() && item == visibleItems.constFirst()->item) {
+ FxListItemSG *listItem = static_cast<FxListItemSG*>(visibleItems.constFirst());
+ const QRectF oldGeometry(item->x() - diff.x(),
+ item->y() - diff.y(),
+ item->width() - diff.width(),
+ item->height() - diff.height());
if (listItem->transitionScheduledOrRunning())
return;
if (orient == QQuickListView::Vertical) {
const qreal oldItemEndPosition = verticalLayoutDirection == QQuickItemView::BottomToTop ? -oldGeometry.y() : oldGeometry.y() + oldGeometry.height();
- qreal diff = newGeometry.height() - oldGeometry.height();
if (verticalLayoutDirection == QQuickListView::TopToBottom && oldItemEndPosition < q->contentY())
- listItem->setPosition(listItem->position() - diff, true);
+ listItem->setPosition(listItem->position() - diff.height(), true);
else if (verticalLayoutDirection == QQuickListView::BottomToTop && oldItemEndPosition > q->contentY())
- listItem->setPosition(listItem->position() + diff, true);
+ listItem->setPosition(listItem->position() + diff.height(), true);
} else {
const qreal oldItemEndPosition = q->effectiveLayoutDirection() == Qt::RightToLeft ? -oldGeometry.x() : oldGeometry.x() + oldGeometry.width();
- qreal diff = newGeometry.width() - oldGeometry.width();
if (q->effectiveLayoutDirection() == Qt::LeftToRight && oldItemEndPosition < q->contentX())
- listItem->setPosition(listItem->position() - diff, true);
+ listItem->setPosition(listItem->position() - diff.width(), true);
else if (q->effectiveLayoutDirection() == Qt::RightToLeft && oldItemEndPosition > q->contentX())
- listItem->setPosition(listItem->position() + diff, true);
+ listItem->setPosition(listItem->position() + diff.width(), true);
}
}
forceLayoutPolish();
@@ -2219,10 +2223,12 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
Note that cacheBuffer is not a pixel buffer - it only maintains additional
instantiated delegates.
- Setting this value can improve the smoothness of scrolling behavior at the expense
- of additional memory usage. It is not a substitute for creating efficient
- delegates; the fewer objects and bindings in a delegate, the faster a view can be
- scrolled.
+ \note Setting this property is not a replacement for creating efficient delegates.
+ It can improve the smoothness of scrolling behavior at the expense of additional
+ memory usage. The fewer objects and bindings in a delegate, the faster a
+ view can be scrolled. It is important to realize that setting a cacheBuffer
+ will only postpone issues caused by slow-loading delegates, it is not a
+ solution for this scenario.
The cacheBuffer operates outside of any display margins specified by
displayMarginBeginning or displayMarginEnd.
@@ -3105,7 +3111,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
int i = visibleItems.count() - 1;
while (i > 0 && visibleItems.at(i)->index == -1)
--i;
- if (i == 0 && visibleItems.first()->index == -1) {
+ if (i == 0 && visibleItems.constFirst()->index == -1) {
// there are no visible items except items marked for removal
index = visibleItems.count();
} else if (visibleItems.at(i)->index + 1 == modelIndex
@@ -3130,7 +3136,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
qreal pos = 0;
if (visibleItems.count()) {
pos = index < visibleItems.count() ? visibleItems.at(index)->position()
- : visibleItems.last()->endPosition()+spacing;
+ : visibleItems.constLast()->endPosition() + spacing;
}
// Update the indexes of the following visible items.
@@ -3145,7 +3151,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
}
}
- int prevVisibleCount = visibleItems.count();
+ bool visibleAffected = false;
if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
// Insert items before the visible item.
int insertionIdx = index;
@@ -3168,6 +3174,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
if (!item)
return false;
+ visibleAffected = true;
visibleItems.insert(insertionIdx, item);
if (insertionIdx == 0)
insertResult->changedFirstItem = true;
@@ -3199,6 +3206,9 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
} else {
qreal to = buffer + displayMarginEnd + tempPos + size();
+
+ visibleAffected = count > 0 && pos < to;
+
for (int i = 0; i < count && pos <= to; ++i) {
FxViewItem *item = 0;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
@@ -3249,7 +3259,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
updateVisibleIndex();
- return visibleItems.count() > prevVisibleCount;
+ return visibleAffected;
}
void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
@@ -3261,7 +3271,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
int markerItemIndex = -1;
for (int i=0; i<visibleItems.count(); i++) {
- if (visibleItems[i]->index == afterModelIndex) {
+ if (visibleItems.at(i)->index == afterModelIndex) {
markerItemIndex = i;
break;
}
@@ -3274,7 +3284,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
- (removalResult.countChangeAfterVisibleItems * (averageSize + spacing));
for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
- FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems[i]);
+ FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems.at(i));
if (!listItem->transitionScheduledOrRunning()) {
qreal pos = listItem->position();
listItem->setPosition(pos - sizeRemoved);
@@ -3342,7 +3352,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
*/
/*!
- \qmlmethod int QtQuick::ListView::indexAt(int x, int y)
+ \qmlmethod int QtQuick::ListView::indexAt(real x, real y)
Returns the index of the visible item containing the point \a x, \a y in content
coordinates. If there is no item at the point specified, or the item is
@@ -3355,7 +3365,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
*/
/*!
- \qmlmethod Item QtQuick::ListView::itemAt(int x, int y)
+ \qmlmethod Item QtQuick::ListView::itemAt(real x, real y)
Returns the visible item containing the point \a x, \a y in content
coordinates. If there is no item at the point specified, or the item is
diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h
index b8ab38bbba..f84478acbd 100644
--- a/src/quick/items/qquicklistview_p.h
+++ b/src/quick/items/qquicklistview_p.h
@@ -53,11 +53,13 @@
#include "qquickitemview_p.h"
+#include <private/qtquickglobal_p.h>
+
QT_BEGIN_NAMESPACE
class QQuickListView;
class QQuickListViewPrivate;
-class Q_AUTOTEST_EXPORT QQuickViewSection : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickViewSection : public QObject
{
Q_OBJECT
Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
@@ -82,7 +84,7 @@ public:
enum LabelPositioning { InlineLabels = 0x01, CurrentLabelAtStart = 0x02, NextLabelAtEnd = 0x04 };
Q_ENUM(LabelPositioning)
- int labelPositioning() { return m_labelPositioning; }
+ int labelPositioning() const { return m_labelPositioning; }
void setLabelPositioning(int pos);
Q_SIGNALS:
@@ -103,7 +105,7 @@ private:
class QQmlInstanceModel;
class QQuickListViewAttached;
-class Q_AUTOTEST_EXPORT QQuickListView : public QQuickItemView
+class Q_QUICK_PRIVATE_EXPORT QQuickListView : public QQuickItemView
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickListView)
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 63c9558d7a..9aea9c50df 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -65,11 +65,12 @@ QQuickLoaderPrivate::~QQuickLoaderPrivate()
disposeInitialPropertyValues();
}
-void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change
+ , const QRectF &diff)
{
if (resizeItem == item)
_q_updateSize(false);
- QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+ QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, diff);
}
void QQuickLoaderPrivate::itemImplicitWidthChanged(QQuickItem *)
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 9ef89a74d6..a0a9ca0601 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -84,7 +84,7 @@ public:
QQuickLoaderPrivate();
~QQuickLoaderPrivate();
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) Q_DECL_OVERRIDE;
void itemImplicitWidthChanged(QQuickItem *) Q_DECL_OVERRIDE;
void itemImplicitHeightChanged(QQuickItem *) Q_DECL_OVERRIDE;
void clear();
@@ -94,7 +94,7 @@ public:
void incubatorStateChanged(QQmlIncubator::Status status);
void setInitialState(QObject *o);
void disposeInitialPropertyValues();
- QUrl resolveSourceUrl(QQmlV4Function *args);
+ static QUrl resolveSourceUrl(QQmlV4Function *args);
QV4::ReturnedValue extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error);
qreal getImplicitWidth() const Q_DECL_OVERRIDE;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 66aff5c2f4..0118d882af 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -54,10 +54,12 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
+Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
+
QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
: enabled(true), scrollGestureEnabled(true), hovered(false), longPress(false),
moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
- propagateComposedEvents(false), pressed(0)
+ propagateComposedEvents(false), overThreshold(false), pressed(0)
#ifndef QT_NO_DRAGANDDROP
, drag(0)
#endif
@@ -403,8 +405,7 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
/*!
\qmlsignal QtQuick::MouseArea::canceled()
- This signal is emitted when mouse events have been canceled, either because an event was not accepted, or
- because another item stole the mouse event handling.
+ This signal is emitted when mouse events have been canceled, because another item stole the mouse event handling.
This signal is for advanced use: it is useful when there is more than one MouseArea
that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
@@ -720,7 +721,7 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
curLocalPos = event->windowPos();
}
- if (keepMouseGrab() && d->stealMouse && !d->drag->active())
+ if (keepMouseGrab() && d->stealMouse && d->overThreshold && !d->drag->active())
d->drag->setActive(true);
QPointF startPos = d->drag->target()->parentItem()
@@ -746,16 +747,19 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
if (d->drag->active())
d->drag->target()->setPosition(dragPos);
- if (!keepMouseGrab()
- && (QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(), Qt::XAxis, event, d->drag->threshold())
- || QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(), Qt::YAxis, event, d->drag->threshold()))) {
- setKeepMouseGrab(true);
- d->stealMouse = true;
-
+ if (!d->overThreshold && (QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(), Qt::XAxis, event, d->drag->threshold())
+ || QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(), Qt::YAxis, event, d->drag->threshold())))
+ {
+ d->overThreshold = true;
if (d->drag->smoothed())
d->startScene = event->windowPos();
}
+ if (!keepMouseGrab() && d->overThreshold) {
+ setKeepMouseGrab(true);
+ d->stealMouse = true;
+ }
+
d->moved = true;
}
#endif
@@ -774,6 +778,7 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickMouseArea);
d->stealMouse = false;
+ d->overThreshold = false;
if (!d->enabled && !d->pressed) {
QQuickItem::mouseReleaseEvent(event);
} else {
@@ -887,6 +892,7 @@ void QQuickMouseArea::ungrabMouse()
d->pressed = 0;
d->stealMouse = false;
d->doubleClick = false;
+ d->overThreshold = false;
setKeepMouseGrab(false);
#ifndef QT_NO_DRAGANDDROP
@@ -1124,6 +1130,7 @@ void QQuickMouseArea::setHovered(bool h)
{
Q_D(QQuickMouseArea);
if (d->hovered != h) {
+ qCDebug(DBG_HOVER_TRACE) << this << d->hovered << "->" << h;
d->hovered = h;
emit hoveredChanged();
d->hovered ? emit entered() : emit exited();
@@ -1190,6 +1197,11 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
emit mouseXChanged(&me);
me.setPosition(d->lastPos);
emit mouseYChanged(&me);
+
+ if (!me.isAccepted()) {
+ d->pressed = Qt::NoButton;
+ }
+
if (!oldPressed) {
emit pressedChanged();
emit containsPressChanged();
@@ -1346,8 +1358,8 @@ QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
if (!qmlVisualTouchDebugging())
return 0;
- QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
- if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
+ QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
+ if (!rectangle) rectangle = d->sceneGraphContext()->createInternalRectangleNode();
rectangle->setRect(QRectF(0, 0, width(), height()));
rectangle->setColor(QColor(255, 0, 0, 50));
diff --git a/src/quick/items/qquickmousearea_p_p.h b/src/quick/items/qquickmousearea_p_p.h
index 794a8cc6ff..b59e02910f 100644
--- a/src/quick/items/qquickmousearea_p_p.h
+++ b/src/quick/items/qquickmousearea_p_p.h
@@ -93,6 +93,7 @@ public:
bool doubleClick : 1;
bool preventStealing : 1;
bool propagateComposedEvents : 1;
+ bool overThreshold : 1;
Qt::MouseButtons pressed;
#ifndef QT_NO_DRAGANDDROP
QQuickDrag *drag;
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 9d8e7aedd4..d68cb8e3f6 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -362,7 +362,7 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent)
QQuickMultiPointTouchArea::~QQuickMultiPointTouchArea()
{
clearTouchLists();
- foreach (QObject *obj, _touchPoints) {
+ for (QObject *obj : qAsConst(_touchPoints)) {
QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj);
if (!dtp->isQmlDefined())
delete dtp;
@@ -448,20 +448,12 @@ void QQuickMultiPointTouchArea::touchEvent(QTouchEvent *event)
}
}
updateTouchData(event);
- if (event->type() == QEvent::TouchEnd) {
- //TODO: move to window
- _stealMouse = false;
- setKeepMouseGrab(false);
- setKeepTouchGrab(false);
- ungrabTouchPoints();
- }
+ if (event->type() == QEvent::TouchEnd)
+ ungrab();
break;
}
case QEvent::TouchCancel:
- _stealMouse = false;
- setKeepMouseGrab(false);
- setKeepTouchGrab(false);
- ungrabTouchPoints();
+ ungrab();
break;
default:
QQuickItem::touchEvent(event);
@@ -532,7 +524,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
}
int numTouchPoints = touchPoints.count();
//always remove released touches, and make sure we handle all releases before adds.
- foreach (const QTouchEvent::TouchPoint &p, touchPoints) {
+ for (const QTouchEvent::TouchPoint &p : qAsConst(touchPoints)) {
Qt::TouchPointState touchPointState = p.state();
int id = p.id();
if (touchPointState & Qt::TouchPointReleased) {
@@ -547,7 +539,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
}
}
if (numTouchPoints >= _minimumTouchPoints && numTouchPoints <= _maximumTouchPoints) {
- foreach (const QTouchEvent::TouchPoint &p, touchPoints) {
+ for (const QTouchEvent::TouchPoint &p : qAsConst(touchPoints)) {
Qt::TouchPointState touchPointState = p.state();
int id = p.id();
if (touchPointState & Qt::TouchPointReleased) {
@@ -557,13 +549,13 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
addTouchPoint(&p);
started = true;
} else if (touchPointState & Qt::TouchPointMoved) {
- QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints[id]);
+ QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
Q_ASSERT(dtp);
_movedTouchPoints.append(dtp);
updateTouchPoint(dtp,&p);
moved = true;
} else {
- QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints[id]);
+ QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
Q_ASSERT(dtp);
updateTouchPoint(dtp,&p);
}
@@ -573,7 +565,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
if (!_stealMouse /* !ignoring gesture*/) {
bool offerGrab = false;
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
- foreach (const QTouchEvent::TouchPoint &p, touchPoints) {
+ for (const QTouchEvent::TouchPoint &p : qAsConst(touchPoints)) {
if (p.state() == Qt::TouchPointReleased)
continue;
const QPointF &currentPos = p.scenePos();
@@ -607,7 +599,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
void QQuickMultiPointTouchArea::clearTouchLists()
{
- foreach (QObject *obj, _releasedTouchPoints) {
+ for (QObject *obj : qAsConst(_releasedTouchPoints)) {
QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj);
if (!dtp->isQmlDefined()) {
_touchPoints.remove(dtp->pointId());
@@ -624,7 +616,7 @@ void QQuickMultiPointTouchArea::clearTouchLists()
void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
{
QQuickTouchPoint *dtp = 0;
- foreach (QQuickTouchPoint* tp, _touchPrototypes) {
+ for (QQuickTouchPoint* tp : qAsConst(_touchPrototypes)) {
if (!tp->inUse()) {
tp->setInUse(true);
dtp = tp;
@@ -644,7 +636,7 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
void QQuickMultiPointTouchArea::addTouchPoint(const QMouseEvent *e)
{
QQuickTouchPoint *dtp = 0;
- foreach (QQuickTouchPoint *tp, _touchPrototypes)
+ for (QQuickTouchPoint *tp : qAsConst(_touchPrototypes))
if (!tp->inUse()) {
tp->setInUse(true);
dtp = tp;
@@ -784,18 +776,17 @@ void QQuickMultiPointTouchArea::mouseReleaseEvent(QMouseEvent *event)
void QQuickMultiPointTouchArea::ungrab()
{
+ _stealMouse = false;
+ setKeepMouseGrab(false);
+ setKeepTouchGrab(false);
+ ungrabTouchPoints();
+
if (_touchPoints.count()) {
- QQuickWindow *c = window();
- if (c && c->mouseGrabberItem() == this) {
- _stealMouse = false;
- setKeepMouseGrab(false);
- }
- setKeepTouchGrab(false);
- foreach (QObject *obj, _touchPoints)
+ for (QObject *obj : qAsConst(_touchPoints))
static_cast<QQuickTouchPoint*>(obj)->setPressed(false);
emit canceled(_touchPoints.values());
clearTouchLists();
- foreach (QObject *obj, _touchPoints) {
+ for (QObject *obj : qAsConst(_touchPoints)) {
QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj);
if (!dtp->isQmlDefined())
delete dtp;
@@ -881,11 +872,7 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *i, QEvent *eve
if (!shouldFilter(event))
return false;
updateTouchData(event);
- //TODO: verify this behavior
- _stealMouse = false;
- setKeepMouseGrab(false);
- setKeepTouchGrab(false);
- ungrabTouchPoints();
+ ungrab();
}
break;
default:
@@ -914,7 +901,7 @@ bool QQuickMultiPointTouchArea::shouldFilter(QEvent *event)
case QEvent::TouchUpdate:
case QEvent::TouchEnd: {
QTouchEvent *te = static_cast<QTouchEvent*>(event);
- foreach (const QTouchEvent::TouchPoint &point, te->touchPoints()) {
+ for (const QTouchEvent::TouchPoint &point : te->touchPoints()) {
if (contains(mapFromScene(point.scenePos()))) {
containsPoint = true;
break;
@@ -940,8 +927,8 @@ QSGNode *QQuickMultiPointTouchArea::updatePaintNode(QSGNode *oldNode, UpdatePain
if (!qmlVisualTouchDebugging())
return 0;
- QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
- if (!rectangle) rectangle = QQuickItemPrivate::get(this)->sceneGraphContext()->createRectangleNode();
+ QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
+ if (!rectangle) rectangle = QQuickItemPrivate::get(this)->sceneGraphContext()->createInternalRectangleNode();
rectangle->setRect(QRectF(0, 0, width(), height()));
rectangle->setColor(QColor(255, 0, 0, 50));
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index 52913f53f6..b9ef7816e0 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -231,7 +231,7 @@ public:
static QQuickTouchPoint* touchPoint_at(QQmlListProperty<QQuickTouchPoint> *list, int index) {
QQuickMultiPointTouchArea *q = static_cast<QQuickMultiPointTouchArea*>(list->object);
- return q->_touchPrototypes[index];
+ return q->_touchPrototypes.value(index);
}
Q_SIGNALS:
diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp
index 312721ed04..42fcee3c0d 100644
--- a/src/quick/items/qquickopenglshadereffect.cpp
+++ b/src/quick/items/qquickopenglshadereffect.cpp
@@ -51,7 +51,9 @@
#include "qquickshadereffectsource_p.h"
#include "qquickshadereffectmesh_p.h"
+#include <QtQml/qqmlfile.h>
#include <QtCore/qsignalmapper.h>
+#include <QtCore/qfileselector.h>
QT_BEGIN_NAMESPACE
@@ -177,12 +179,46 @@ namespace {
}
}
+namespace QtPrivate {
+class MappedSlotObject: public QtPrivate::QSlotObjectBase
+{
+public:
+ typedef std::function<void()> PropChangedFunc;
+
+ explicit MappedSlotObject(PropChangedFunc func)
+ : QSlotObjectBase(&impl), _signalIndex(-1), func(func)
+ { ref(); }
+
+ void setSignalIndex(int idx) { _signalIndex = idx; }
+ int signalIndex() const { return _signalIndex; }
+
+private:
+ int _signalIndex;
+ PropChangedFunc func;
+ static void impl(int which, QSlotObjectBase *this_, QObject *, void **a, bool *ret)
+ {
+ auto thiz = static_cast<MappedSlotObject*>(this_);
+ switch (which) {
+ case Destroy:
+ delete thiz;
+ break;
+ case Call:
+ thiz->func();
+ break;
+ case Compare:
+ *ret = thiz == reinterpret_cast<MappedSlotObject *>(a[0]);
+ break;
+ case NumOperations: ;
+ }
+ }
+};
+}
QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon()
{
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
- qDeleteAll(signalMappers[shaderType]);
+ clearSignalMappers(shaderType);
}
void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
@@ -191,9 +227,9 @@ void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item,
if (signalMappers[shaderType].at(i) == 0)
continue;
const UniformData &d = uniformData[shaderType].at(i);
- QSignalMapper *mapper = signalMappers[shaderType].at(i);
- QObject::disconnect(item, 0, mapper, SLOT(map()));
- QObject::disconnect(mapper, SIGNAL(mapped(int)), host, SLOT(propertyChanged(int)));
+ auto mapper = signalMappers[shaderType].at(i);
+ void *a = mapper;
+ QObjectPrivate::disconnect(item, mapper->signalIndex(), &a);
if (d.specialType == UniformData::Sampler) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
@@ -205,25 +241,30 @@ void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item,
}
}
-void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
+void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item,
+ const QMetaObject *itemMetaObject,
+ Key::ShaderType shaderType)
{
+ QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(qmlEngine(item), item);
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
if (signalMappers[shaderType].at(i) == 0)
continue;
const UniformData &d = uniformData[shaderType].at(i);
- int pi = item->metaObject()->indexOfProperty(d.name.constData());
- if (pi >= 0) {
- QMetaProperty mp = item->metaObject()->property(pi);
- if (!mp.hasNotifySignal())
+ QQmlPropertyData *pd = propCache->property(QString::fromUtf8(d.name), nullptr, nullptr);
+ if (pd && !pd->isFunction()) {
+ if (pd->notifyIndex() == -1) {
qWarning("QQuickOpenGLShaderEffect: property '%s' does not have notification method!", d.name.constData());
- const QByteArray signalName = '2' + mp.notifySignal().methodSignature();
- QSignalMapper *mapper = signalMappers[shaderType].at(i);
- QObject::connect(item, signalName, mapper, SLOT(map()));
- QObject::connect(mapper, SIGNAL(mapped(int)), host, SLOT(propertyChanged(int)));
+ } else {
+ auto *mapper = signalMappers[shaderType].at(i);
+ mapper->setSignalIndex(pd->notifyIndex());
+ Q_ASSERT(item->metaObject() == itemMetaObject);
+ QObjectPrivate::connectImpl(item, mapper->signalIndex(), item, nullptr, mapper,
+ Qt::AutoConnection, nullptr, itemMetaObject);
+ }
} else {
// If the source is set via a dynamic property, like the layer is, then we need this
// check to disable the warning.
- if (!item->property(d.name.constData()).isValid())
+ if (!item->property(d.name).isValid())
qWarning("QQuickOpenGLShaderEffect: '%s' does not have a matching property!", d.name.constData());
}
@@ -243,14 +284,14 @@ void QQuickOpenGLShaderEffectCommon::updateParseLog(bool ignoreAttributes)
parseLog.clear();
if (!ignoreAttributes) {
if (!attributes.contains(qtPositionAttributeName())) {
- parseLog += QLatin1String("Warning: Missing reference to \'");
- parseLog += QLatin1String(qtPositionAttributeName());
- parseLog += QLatin1String("\'.\n");
+ parseLog += QLatin1String("Warning: Missing reference to \'")
+ + QLatin1String(qtPositionAttributeName())
+ + QLatin1String("\'.\n");
}
if (!attributes.contains(qtTexCoordAttributeName())) {
- parseLog += QLatin1String("Warning: Missing reference to \'");
- parseLog += QLatin1String(qtTexCoordAttributeName());
- parseLog += QLatin1String("\'.\n");
+ parseLog += QLatin1String("Warning: Missing reference to \'")
+ + QLatin1String(qtTexCoordAttributeName())
+ + QLatin1String("\'.\n");
}
}
bool respectsMatrix = false;
@@ -267,8 +308,12 @@ void QQuickOpenGLShaderEffectCommon::updateParseLog(bool ignoreAttributes)
parseLog += QLatin1String("Warning: Shaders are missing reference to \'qt_Opacity\'.\n");
}
-void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code)
+void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item,
+ const QMetaObject *itemMetaObject,
+ Key::ShaderType shaderType,
+ const QByteArray &code)
{
+ QQmlPropertyCache *propCache = QQmlData::ensurePropertyCache(qmlEngine(item), item);
int index = 0;
int typeIndex = -1;
int typeLength = 0;
@@ -291,7 +336,7 @@ void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key
const int srLen = sizeof("qt_SubRect_") - 1;
UniformData d;
- QSignalMapper *mapper = 0;
+ QtPrivate::MappedSlotObject *mapper = nullptr;
d.name = QByteArray(s + nameIndex, nameLength);
if (nameLength == opLen && qstrncmp("qt_Opacity", s + nameIndex, opLen) == 0) {
d.specialType = UniformData::Opacity;
@@ -300,11 +345,17 @@ void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key
} else if (nameLength > srLen && qstrncmp("qt_SubRect_", s + nameIndex, srLen) == 0) {
d.specialType = UniformData::SubRect;
} else {
- mapper = new QSignalMapper;
- mapper->setMapping(item, uniformData[shaderType].size() | (shaderType << 16));
- d.value = item->property(d.name.constData());
+ if (QQmlPropertyData *pd = propCache->property(QString::fromUtf8(d.name), nullptr, nullptr)) {
+ if (!pd->isFunction())
+ d.propertyIndex = pd->coreIndex();
+ }
+ const int mappedId = uniformData[shaderType].size() | (shaderType << 16);
+ mapper = new QtPrivate::MappedSlotObject([this, mappedId](){
+ this->mappedPropertyChanged(mappedId);
+ });
bool sampler = typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0;
d.specialType = sampler ? UniformData::Sampler : UniformData::None;
+ d.setValueFromProperty(item, itemMetaObject);
}
uniformData[shaderType].append(d);
signalMappers[shaderType].append(mapper);
@@ -312,15 +363,39 @@ void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key
}
}
-void QQuickOpenGLShaderEffectCommon::updateShader(QQuickItem *item, Key::ShaderType shaderType)
+void QQuickOpenGLShaderEffectCommon::updateShader(QQuickItem *item,
+ const QMetaObject *itemMetaObject,
+ Key::ShaderType shaderType)
{
disconnectPropertySignals(item, shaderType);
- qDeleteAll(signalMappers[shaderType]);
uniformData[shaderType].clear();
- signalMappers[shaderType].clear();
+ clearSignalMappers(shaderType);
if (shaderType == Key::VertexShader)
attributes.clear();
+ // A qrc or file URL means the shader source is to be read from the specified file.
+ QUrl srcUrl(QString::fromUtf8(source.sourceCode[shaderType]));
+ if (!srcUrl.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) || srcUrl.isLocalFile()) {
+ if (!fileSelector) {
+ fileSelector = new QFileSelector(item);
+ // There may not be an OpenGL context accessible here. So rely on
+ // the window's requestedFormat().
+ if (item->window()
+ && item->window()->requestedFormat().profile() == QSurfaceFormat::CoreProfile) {
+ fileSelector->setExtraSelectors(QStringList() << QStringLiteral("glslcore"));
+ }
+ }
+ const QString fn = fileSelector->select(QQmlFile::urlToLocalFileOrQrc(srcUrl));
+ QFile f(fn);
+ if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ source.sourceCode[shaderType] = f.readAll();
+ f.close();
+ } else {
+ qWarning("ShaderEffect: Failed to read %s", qPrintable(fn));
+ source.sourceCode[shaderType] = QByteArray();
+ }
+ }
+
const QByteArray &code = source.sourceCode[shaderType];
if (code.isEmpty()) {
// Optimize for default code.
@@ -338,20 +413,20 @@ void QQuickOpenGLShaderEffectCommon::updateShader(QQuickItem *item, Key::ShaderT
d.specialType = UniformData::Opacity;
uniformData[Key::FragmentShader].append(d);
signalMappers[Key::FragmentShader].append(0);
- QSignalMapper *mapper = new QSignalMapper;
- mapper->setMapping(item, 1 | (Key::FragmentShader << 16));
+ const int mappedId = 1 | (Key::FragmentShader << 16);
+ auto mapper = new QtPrivate::MappedSlotObject([this, mappedId](){mappedPropertyChanged(mappedId);});
const char *sourceName = "source";
d.name = sourceName;
- d.value = item->property(sourceName);
+ d.setValueFromProperty(item, itemMetaObject);
d.specialType = UniformData::Sampler;
uniformData[Key::FragmentShader].append(d);
signalMappers[Key::FragmentShader].append(mapper);
}
} else {
- lookThroughShaderCode(item, shaderType, code);
+ lookThroughShaderCode(item, itemMetaObject, shaderType, code);
}
- connectPropertySignals(item, shaderType);
+ connectPropertySignals(item, itemMetaObject, shaderType);
}
void QQuickOpenGLShaderEffectCommon::updateMaterial(QQuickOpenGLShaderEffectNode *node,
@@ -482,8 +557,9 @@ static bool qquick_uniqueInUniformData(QQuickItem *source, const QVector<QQuickO
return true;
}
-void QQuickOpenGLShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
- bool *textureProviderChanged)
+void QQuickOpenGLShaderEffectCommon::propertyChanged(QQuickItem *item,
+ const QMetaObject *itemMetaObject,
+ int mappedId, bool *textureProviderChanged)
{
Key::ShaderType shaderType = Key::ShaderType(mappedId >> 16);
int index = mappedId & 0xffff;
@@ -502,7 +578,7 @@ void QQuickOpenGLShaderEffectCommon::propertyChanged(QQuickItem *item, int mappe
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
}
- d.value = item->property(d.name.constData());
+ d.setValueFromProperty(item, itemMetaObject);
source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
@@ -517,20 +593,30 @@ void QQuickOpenGLShaderEffectCommon::propertyChanged(QQuickItem *item, int mappe
if (textureProviderChanged)
*textureProviderChanged = true;
} else {
- d.value = item->property(d.name.constData());
+ d.setValueFromProperty(item, itemMetaObject);
if (textureProviderChanged)
*textureProviderChanged = false;
}
}
+void QQuickOpenGLShaderEffectCommon::clearSignalMappers(int shader)
+{
+ for (auto mapper : qAsConst(signalMappers[shader])) {
+ if (mapper)
+ mapper->destroyIfLastRef();
+ }
+ signalMappers[shader].clear();
+}
+
QQuickOpenGLShaderEffect::QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QObject *parent)
: QObject(parent)
, m_item(item)
+ , m_itemMetaObject(nullptr)
, m_meshResolution(1, 1)
, m_mesh(0)
, m_cullMode(QQuickShaderEffect::NoCulling)
, m_status(QQuickShaderEffect::Uncompiled)
- , m_common(this)
+ , m_common(this, [this](int mappedId){this->propertyChanged(mappedId);})
, m_blending(true)
, m_dirtyUniforms(true)
, m_dirtyUniformValues(true)
@@ -541,6 +627,8 @@ QQuickOpenGLShaderEffect::QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QOb
, m_dirtyGeometry(true)
, m_customVertexShader(false)
, m_supportsAtlasTextures(false)
+ , m_vertNeedsUpdate(true)
+ , m_fragNeedsUpdate(true)
{
}
@@ -558,8 +646,9 @@ void QQuickOpenGLShaderEffect::setFragmentShader(const QByteArray &code)
m_dirtyProgram = true;
m_dirtyParseLog = true;
+ m_fragNeedsUpdate = true;
if (m_item->isComponentComplete())
- m_common.updateShader(m_item, Key::FragmentShader);
+ maybeUpdateShaders();
m_item->update();
if (m_status != QQuickShaderEffect::Uncompiled) {
@@ -578,8 +667,9 @@ void QQuickOpenGLShaderEffect::setVertexShader(const QByteArray &code)
m_dirtyParseLog = true;
m_customVertexShader = true;
+ m_vertNeedsUpdate = true;
if (m_item->isComponentComplete())
- m_common.updateShader(m_item, Key::VertexShader);
+ maybeUpdateShaders();
m_item->update();
if (m_status != QQuickShaderEffect::Uncompiled) {
@@ -662,6 +752,8 @@ void QQuickOpenGLShaderEffect::setSupportsAtlasTextures(bool supports)
QString QQuickOpenGLShaderEffect::parseLog()
{
+ maybeUpdateShaders(true);
+
if (m_dirtyParseLog) {
m_common.updateParseLog(m_mesh != 0);
m_dirtyParseLog = false;
@@ -677,7 +769,8 @@ void QQuickOpenGLShaderEffect::handleEvent(QEvent *event)
for (int i = 0; i < m_common.uniformData[shaderType].size(); ++i) {
if (m_common.uniformData[shaderType].at(i).name == e->propertyName()) {
bool textureProviderChanged;
- m_common.propertyChanged(m_item, (shaderType << 16) | i, &textureProviderChanged);
+ m_common.propertyChanged(m_item, m_itemMetaObject,
+ (shaderType << 16) | i, &textureProviderChanged);
m_dirtyTextureProviders |= textureProviderChanged;
m_dirtyUniformValues = true;
m_item->update();
@@ -715,7 +808,7 @@ void QQuickOpenGLShaderEffect::sourceDestroyed(QObject *object)
void QQuickOpenGLShaderEffect::propertyChanged(int mappedId)
{
bool textureProviderChanged;
- m_common.propertyChanged(m_item, mappedId, &textureProviderChanged);
+ m_common.propertyChanged(m_item, m_itemMetaObject, mappedId, &textureProviderChanged);
m_dirtyTextureProviders |= textureProviderChanged;
m_dirtyUniformValues = true;
m_item->update();
@@ -825,9 +918,7 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic
if (!mesh->validateAttributes(m_common.attributes, &posIndex)) {
QString log = mesh->log();
if (!log.isNull()) {
- m_log = parseLog();
- m_log += QLatin1String("*** Mesh ***\n");
- m_log += log;
+ m_log = parseLog() + QLatin1String("*** Mesh ***\n") + log;
m_status = QQuickShaderEffect::Error;
emit m_item->logChanged();
emit m_item->statusChanged();
@@ -847,10 +938,28 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic
return node;
}
-void QQuickOpenGLShaderEffect::handleComponentComplete()
+void QQuickOpenGLShaderEffect::maybeUpdateShaders(bool force)
{
- m_common.updateShader(m_item, Key::VertexShader);
- m_common.updateShader(m_item, Key::FragmentShader);
+ if (!m_itemMetaObject)
+ m_itemMetaObject = m_item->metaObject();
+
+ // Defer processing if a window is not yet associated with the item. This
+ // is because the actual scenegraph backend is not known so conditions
+ // based on GraphicsInfo.shaderType and similar evaluate to wrong results.
+ if (!m_item->window() && !force) {
+ m_item->polish();
+ return;
+ }
+
+ if (m_vertNeedsUpdate) {
+ m_vertNeedsUpdate = false;
+ m_common.updateShader(m_item, m_itemMetaObject, Key::VertexShader);
+ }
+
+ if (m_fragNeedsUpdate) {
+ m_fragNeedsUpdate = false;
+ m_common.updateShader(m_item, m_itemMetaObject, Key::FragmentShader);
+ }
}
void QQuickOpenGLShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
diff --git a/src/quick/items/qquickopenglshadereffect_p.h b/src/quick/items/qquickopenglshadereffect_p.h
index 0e54813443..ed56a76409 100644
--- a/src/quick/items/qquickopenglshadereffect_p.h
+++ b/src/quick/items/qquickopenglshadereffect_p.h
@@ -61,40 +61,54 @@
#include "qquickshadereffectmesh_p.h"
#include <QtCore/qpointer.h>
+#include <functional>
QT_BEGIN_NAMESPACE
class QSGContext;
class QSignalMapper;
+class QFileSelector;
class QQuickOpenGLCustomMaterialShader;
+namespace QtPrivate {
+class MappedSlotObject;
+}
+
// Common class for QQuickOpenGLShaderEffect and QQuickCustomParticle.
struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
{
typedef QQuickOpenGLShaderEffectMaterialKey Key;
typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
- QQuickOpenGLShaderEffectCommon(QObject *host) : host(host) { }
+ QQuickOpenGLShaderEffectCommon(QObject *host, std::function<void(int)> mappedPropertyChanged)
+ : host(host), mappedPropertyChanged(mappedPropertyChanged), fileSelector(nullptr)
+ { }
+
~QQuickOpenGLShaderEffectCommon();
+
void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
- void connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
+ void connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType);
void updateParseLog(bool ignoreAttributes);
- void lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code);
- void updateShader(QQuickItem *item, Key::ShaderType shaderType);
+ void lookThroughShaderCode(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType, const QByteArray &code);
+ void updateShader(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType);
void updateMaterial(QQuickOpenGLShaderEffectNode *node, QQuickOpenGLShaderEffectMaterial *material,
bool updateUniforms, bool updateUniformValues, bool updateTextureProviders);
void updateWindow(QQuickWindow *window);
// Called by slots in QQuickOpenGLShaderEffect:
void sourceDestroyed(QObject *object);
- void propertyChanged(QQuickItem *item, int mappedId, bool *textureProviderChanged);
+ void propertyChanged(QQuickItem *item, const QMetaObject *itemMetaObject, int mappedId, bool *textureProviderChanged);
+
+ void clearSignalMappers(int shader);
QObject *host;
+ std::function<void(int)> mappedPropertyChanged;
Key source;
QVector<QByteArray> attributes;
QVector<UniformData> uniformData[Key::ShaderTypeCount];
- QVector<QSignalMapper *> signalMappers[Key::ShaderTypeCount];
+ QVector<QtPrivate::MappedSlotObject *> signalMappers[Key::ShaderTypeCount];
QString parseLog;
+ QFileSelector *fileSelector;
};
@@ -132,17 +146,18 @@ public:
void handleEvent(QEvent *);
void handleGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
QSGNode *handleUpdatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *);
- void handleComponentComplete();
void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value);
+ void maybeUpdateShaders(bool force = false);
private Q_SLOTS:
void updateGeometry();
void updateGeometryIfAtlased();
void updateLogAndStatus(const QString &log, int status);
void sourceDestroyed(QObject *object);
- void propertyChanged(int mappedId);
private:
+ void propertyChanged(int mappedId);
+
friend class QQuickCustomMaterialShader;
friend class QQuickOpenGLShaderEffectNode;
@@ -150,6 +165,7 @@ private:
typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
QQuickShaderEffect *m_item;
+ const QMetaObject *m_itemMetaObject;
QSize m_meshResolution;
QQuickShaderEffectMesh *m_mesh;
QQuickGridMesh m_defaultMesh;
@@ -169,6 +185,8 @@ private:
uint m_dirtyGeometry : 1;
uint m_customVertexShader : 1;
uint m_supportsAtlasTextures : 1;
+ uint m_vertNeedsUpdate : 1;
+ uint m_fragNeedsUpdate : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp
index 02b76b2dbc..e01ecc59e3 100644
--- a/src/quick/items/qquickopenglshadereffectnode.cpp
+++ b/src/quick/items/qquickopenglshadereffectnode.cpp
@@ -261,13 +261,11 @@ void QQuickCustomMaterialShader::compile()
m_log.clear();
m_compiled = true;
if (!program()->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader())) {
- m_log += QLatin1String("*** Vertex shader ***\n");
- m_log += program()->log();
+ m_log += QLatin1String("*** Vertex shader ***\n") + program()->log();
m_compiled = false;
}
if (!program()->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader())) {
- m_log += QLatin1String("*** Fragment shader ***\n");
- m_log += program()->log();
+ m_log += QLatin1String("*** Fragment shader ***\n") + program()->log();
m_compiled = false;
}
diff --git a/src/quick/items/qquickopenglshadereffectnode_p.h b/src/quick/items/qquickopenglshadereffectnode_p.h
index adf5ef730b..5abe3ae3d0 100644
--- a/src/quick/items/qquickopenglshadereffectnode_p.h
+++ b/src/quick/items/qquickopenglshadereffectnode_p.h
@@ -90,9 +90,19 @@ public:
QByteArray name;
QVariant value;
+ int propertyIndex = -1;
SpecialType specialType;
bool operator == (const UniformData &other) const;
+
+ void setValueFromProperty(QObject *item, const QMetaObject *itemMetaObject)
+ {
+ if (propertyIndex == -1) {
+ value = item->property(name);
+ } else {
+ value = itemMetaObject->property(propertyIndex).read(item);
+ }
+ }
};
explicit QQuickOpenGLShaderEffectMaterial(QQuickOpenGLShaderEffectNode *node = 0);
diff --git a/src/quick/items/qquickpainteditem.cpp b/src/quick/items/qquickpainteditem.cpp
index d21eb93dbf..bc89de5a1c 100644
--- a/src/quick/items/qquickpainteditem.cpp
+++ b/src/quick/items/qquickpainteditem.cpp
@@ -52,7 +52,7 @@ class QQuickPaintedItemTextureProvider : public QSGTextureProvider
{
public:
QSGPainterNode *node;
- QSGTexture *texture() const { return node ? node->texture() : 0; }
+ QSGTexture *texture() const override { return node ? node->texture() : 0; }
void fireTextureChanged() { emit textureChanged(); }
};
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index e3d218ff01..11881ae0ab 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -63,13 +63,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcItemViewDelegateLifecycle)
const qreal MinimumFlickVelocity = 75.0;
-inline qreal qmlMod(qreal x, qreal y)
-{
- using std::fmod;
- return fmod(x, y);
-}
-
-static QQmlOpenMetaObjectType *qPathViewAttachedType = 0;
+static QQmlOpenMetaObjectType *qPathViewAttachedType = nullptr;
QQuickPathViewAttached::QQuickPathViewAttached(QObject *parent)
: QObject(parent), m_percent(-1), m_view(0), m_onPath(false), m_isCurrent(false)
@@ -96,7 +90,7 @@ void QQuickPathViewAttached::setValue(const QByteArray &name, const QVariant &va
}
QQuickPathViewPrivate::QQuickPathViewPrivate()
- : path(0), currentIndex(0), currentItemOffset(0.0), startPc(0)
+ : path(nullptr), currentIndex(0), currentItemOffset(0.0), startPc(0)
, offset(0.0), offsetAdj(0.0), mappedRange(1.0), mappedCache(0.0)
, stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true)
, autoHighlight(true), highlightUp(false), layoutScheduled(false)
@@ -106,7 +100,7 @@ QQuickPathViewPrivate::QQuickPathViewPrivate()
, moveOffset(this, &QQuickPathViewPrivate::setAdjustedOffset), flickDuration(0)
, pathItems(-1), requestedIndex(-1), cacheSize(0), requestedZ(0)
, moveReason(Other), movementDirection(QQuickPathView::Shortest), moveDirection(QQuickPathView::Shortest)
- , attType(0), highlightComponent(0), highlightItem(0)
+ , attType(nullptr), highlightComponent(nullptr), highlightItem(nullptr)
, moveHighlight(this, &QQuickPathViewPrivate::setHighlightPosition)
, highlightPosition(0)
, highlightRangeStart(0), highlightRangeEnd(0)
@@ -163,7 +157,7 @@ void QQuickPathView::createdItem(int index, QObject *object)
if (d->requestedIndex != index) {
qPathViewAttachedType = d->attachedType();
QQuickPathViewAttached *att = static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
- qPathViewAttachedType = 0;
+ qPathViewAttachedType = nullptr;
if (att) {
att->m_view = this;
att->setOnPath(false);
@@ -186,12 +180,13 @@ void QQuickPathView::initItem(int index, QObject *object)
item->setParentItem(this);
qPathViewAttachedType = d->attachedType();
QQuickPathViewAttached *att = static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
- qPathViewAttachedType = 0;
+ qPathViewAttachedType = nullptr;
if (att) {
att->m_view = this;
qreal percent = d->positionOfIndex(index);
if (percent < 1.0 && d->path) {
- foreach (const QString &attr, d->path->attributes())
+ const auto attributes = d->path->attributes();
+ for (const QString &attr : attributes)
att->setValue(attr.toUtf8(), d->path->attributeAt(attr, percent));
item->setZ(d->requestedZ);
}
@@ -214,7 +209,7 @@ void QQuickPathViewPrivate::releaseItem(QQuickItem *item)
att->setOnPath(false);
} else if (flags & QQmlInstanceModel::Destroyed) {
// but we still reference it
- item->setParentItem(0);
+ item->setParentItem(nullptr);
}
}
@@ -230,7 +225,8 @@ QQmlOpenMetaObjectType *QQuickPathViewPrivate::attachedType()
// pre-create one metatype to share with all attached objects
attType = new QQmlOpenMetaObjectType(&QQuickPathViewAttached::staticMetaObject, qmlEngine(q));
if (path) {
- foreach (const QString &attr, path->attributes())
+ const auto attributes = path->attributes();
+ for (const QString &attr : attributes)
attType->createProperty(attr.toUtf8());
}
}
@@ -242,12 +238,11 @@ void QQuickPathViewPrivate::clear()
{
if (currentItem) {
releaseItem(currentItem);
- currentItem = 0;
+ currentItem = nullptr;
}
- for (int i=0; i<items.count(); i++){
- QQuickItem *p = items[i];
+ for (QQuickItem *p : qAsConst(items))
releaseItem(p);
- }
+
if (requestedIndex >= 0) {
if (model)
model->cancel(requestedIndex);
@@ -279,13 +274,13 @@ qreal QQuickPathViewPrivate::positionOfIndex(qreal index) const
|| snapMode != QQuickPathView::NoSnap))
start = highlightRangeStart;
qreal globalPos = index + offset;
- globalPos = qmlMod(globalPos, qreal(modelCount)) / modelCount;
+ globalPos = std::fmod(globalPos, qreal(modelCount)) / modelCount;
if (pathItems != -1 && pathItems < modelCount) {
globalPos += start / mappedRange;
- globalPos = qmlMod(globalPos, 1.0);
+ globalPos = std::fmod(globalPos, qreal(1.0));
pos = globalPos * mappedRange;
} else {
- pos = qmlMod(globalPos + start, 1.0);
+ pos = std::fmod(globalPos + start, qreal(1.0));
}
}
@@ -296,6 +291,8 @@ qreal QQuickPathViewPrivate::positionOfIndex(qreal index) const
// account the circular space.
bool QQuickPathViewPrivate::isInBound(qreal position, qreal lower, qreal upper) const
{
+ if (lower == upper)
+ return true;
if (lower > upper) {
if (position > upper && position > lower)
position -= mappedRange;
@@ -312,13 +309,13 @@ void QQuickPathViewPrivate::createHighlight()
bool changed = false;
if (highlightItem) {
- highlightItem->setParentItem(0);
+ highlightItem->setParentItem(nullptr);
highlightItem->deleteLater();
- highlightItem = 0;
+ highlightItem = nullptr;
changed = true;
}
- QQuickItem *item = 0;
+ QQuickItem *item = nullptr;
if (highlightComponent) {
QQmlContext *creationContext = highlightComponent->creationContext();
QQmlContext *highlightContext = new QQmlContext(
@@ -394,7 +391,7 @@ void QQuickPathViewPrivate::setHighlightPosition(qreal pos)
qreal range = qreal(modelCount);
// calc normalized position of highlight relative to offset
- qreal relativeHighlight = qmlMod(pos + offset, range) / range;
+ qreal relativeHighlight = std::fmod(pos + offset, range) / range;
if (!highlightUp && relativeHighlight > end / mappedRange) {
qreal diff = 1.0 - relativeHighlight;
@@ -415,12 +412,9 @@ void QQuickPathViewPrivate::setHighlightPosition(qreal pos)
void QQuickPathView::pathUpdated()
{
Q_D(QQuickPathView);
- QList<QQuickItem*>::iterator it = d->items.begin();
- while (it != d->items.end()) {
- QQuickItem *item = *it;
+ for (QQuickItem *item : qAsConst(d->items)) {
if (QQuickPathViewAttached *att = d->attached(item))
att->m_percent = -1;
- ++it;
}
refill();
}
@@ -433,7 +427,8 @@ void QQuickPathViewPrivate::updateItem(QQuickItem *item, qreal percent)
if (qFuzzyCompare(att->m_percent, percent))
return;
att->m_percent = percent;
- foreach (const QString &attr, path->attributes())
+ const auto attributes = path->attributes();
+ for (const QString &attr : attributes)
att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
att->setOnPath(percent < 1.0);
}
@@ -635,7 +630,7 @@ void QQuickPathView::setModel(const QVariant &m)
d->modelVariant = model;
QObject *object = qvariant_cast<QObject*>(model);
- QQmlInstanceModel *vim = 0;
+ QQmlInstanceModel *vim = nullptr;
if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
if (d->ownModel) {
delete d->model;
@@ -715,7 +710,7 @@ void QQuickPathView::setPath(QQuickPath *path)
d->clear();
if (d->attType) {
d->attType->release();
- d->attType = 0;
+ d->attType = nullptr;
}
d->regenerate();
}
@@ -754,7 +749,7 @@ void QQuickPathView::setCurrentIndex(int idx)
}
int oldCurrentIdx = d->currentIndex;
QQuickItem *oldCurrentItem = d->currentItem;
- d->currentItem = 0;
+ d->currentItem = nullptr;
d->moveReason = QQuickPathViewPrivate::SetIndex;
d->currentIndex = idx;
if (d->modelCount) {
@@ -835,7 +830,7 @@ void QQuickPathViewPrivate::setOffset(qreal o)
if (offset != o) {
if (isValid() && q->isComponentComplete()) {
qreal oldOffset = offset;
- offset = qmlMod(o, qreal(modelCount));
+ offset = std::fmod(o, qreal(modelCount));
if (offset < 0)
offset += qreal(modelCount);
qCDebug(lcItemViewDelegateLifecycle) << o << "was" << oldOffset << "now" << offset;
@@ -901,7 +896,7 @@ void QQuickPathView::setHighlight(QQmlComponent *highlight)
\sa highlight
*/
-QQuickItem *QQuickPathView::highlightItem()
+QQuickItem *QQuickPathView::highlightItem() const
{
Q_D(const QQuickPathView);
return d->highlightItem;
@@ -1026,7 +1021,7 @@ void QQuickPathView::setHighlightMoveDuration(int duration)
/*!
\qmlproperty real QtQuick::PathView::dragMargin
- This property holds the maximum distance from the path that initiate mouse dragging.
+ This property holds the maximum distance from the path that initiates mouse dragging.
By default the path can only be dragged by clicking on an item. If
dragMargin is greater than zero, a drag can be initiated by clicking
@@ -1236,7 +1231,7 @@ QQmlComponent *QQuickPathView::delegate() const
return dataModel->delegate();
}
- return 0;
+ return nullptr;
}
void QQuickPathView::setDelegate(QQmlComponent *delegate)
@@ -1313,10 +1308,12 @@ void QQuickPathView::resetPathItemCount()
allowing creation to occur across multiple frames and reducing the
likelihood of skipping frames.
- Setting this value can improve the smoothness of scrolling behavior at the expense
- of additional memory usage. It is not a substitute for creating efficient
- delegates; the fewer objects and bindings in a delegate, the faster a view can be
- moved.
+ \note Setting this property is not a replacement for creating efficient delegates.
+ It can improve the smoothness of scrolling behavior at the expense of additional
+ memory usage. The fewer objects and bindings in a delegate, the faster a
+ view can be scrolled. It is important to realize that setting cacheItemCount
+ will only postpone issues caused by slow-loading delegates, it is not a
+ solution for this scenario.
\sa pathItemCount
*/
@@ -1465,7 +1462,7 @@ void QQuickPathView::positionViewAtIndex(int index, int mode)
// Small offset since the last point coincides with the first and
// this the only "end" position that gives the expected visual result.
qreal adj = sizeof(qreal) == sizeof(float) ? 0.00001f : 0.000000000001;
- endOffset = qmlMod(beginOffset + count, d->modelCount) - adj;
+ endOffset = std::fmod(beginOffset + count, qreal(d->modelCount)) - adj;
}
qreal offset = d->offset;
switch (mode) {
@@ -1486,8 +1483,8 @@ void QQuickPathView::positionViewAtIndex(int index, int mode)
case Contain:
if ((beginOffset < endOffset && (d->offset < beginOffset || d->offset > endOffset))
|| (d->offset < beginOffset && d->offset > endOffset)) {
- qreal diff1 = qmlMod(beginOffset - d->offset + d->modelCount, d->modelCount);
- qreal diff2 = qmlMod(d->offset - endOffset + d->modelCount, d->modelCount);
+ qreal diff1 = std::fmod(beginOffset - d->offset + d->modelCount, qreal(d->modelCount));
+ qreal diff2 = std::fmod(d->offset - endOffset + d->modelCount, qreal(d->modelCount));
if (diff1 < diff2)
offset = beginOffset;
else
@@ -1504,7 +1501,7 @@ void QQuickPathView::positionViewAtIndex(int index, int mode)
}
/*!
- \qmlmethod int QtQuick::PathView::indexAt(int x, int y)
+ \qmlmethod int QtQuick::PathView::indexAt(real x, real y)
Returns the index of the item containing the point \a x, \a y in content
coordinates. If there is no item at the point specified, -1 is returned.
@@ -1514,21 +1511,12 @@ void QQuickPathView::positionViewAtIndex(int index, int mode)
int QQuickPathView::indexAt(qreal x, qreal y) const
{
Q_D(const QQuickPathView);
- if (!d->isValid())
- return -1;
-
- for (int idx = 0; idx < d->items.count(); ++idx) {
- QQuickItem *item = d->items.at(idx);
- QPointF p = item->mapFromItem(this, QPointF(x, y));
- if (item->contains(p))
- return d->model->indexOf(item, 0);
- }
-
- return -1;
+ QQuickItem *item = itemAt(x, y);
+ return item ? d->model->indexOf(item, nullptr) : -1;
}
/*!
- \qmlmethod Item QtQuick::PathView::itemAt(int x, int y)
+ \qmlmethod Item QtQuick::PathView::itemAt(real x, real y)
Returns the item containing the point \a x, \a y in content
coordinates. If there is no item at the point specified, null is returned.
@@ -1539,22 +1527,22 @@ QQuickItem *QQuickPathView::itemAt(qreal x, qreal y) const
{
Q_D(const QQuickPathView);
if (!d->isValid())
- return 0;
+ return nullptr;
- for (int idx = 0; idx < d->items.count(); ++idx) {
- QQuickItem *item = d->items.at(idx);
+ for (QQuickItem *item : d->items) {
QPointF p = item->mapFromItem(this, QPointF(x, y));
if (item->contains(p))
return item;
}
- return 0;
+ return nullptr;
}
QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
{
- qreal samples = qMin(path->path().length()/5, qreal(500.0));
- qreal res = path->path().length()/samples;
+ const auto pathLength = path->path().length();
+ qreal samples = qMin(pathLength / 5, qreal(500.0));
+ qreal res = pathLength / samples;
qreal mindist = 1e10; // big number
QPointF nearPoint = path->pointAt(0);
@@ -1612,7 +1600,7 @@ qreal QQuickPathViewPrivate::calcVelocity() const
return velocity;
}
-qint64 QQuickPathViewPrivate::computeCurrentTime(QInputEvent *event)
+qint64 QQuickPathViewPrivate::computeCurrentTime(QInputEvent *event) const
{
if (0 != event->timestamp())
return event->timestamp();
@@ -1751,12 +1739,13 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
qreal velocity = calcVelocity();
qreal count = pathItems == -1 ? modelCount : qMin(pathItems, modelCount);
- qreal pixelVelocity = (path->path().length()/count) * velocity;
+ const auto averageItemLength = path->path().length() / count;
+ qreal pixelVelocity = averageItemLength * velocity;
if (qAbs(pixelVelocity) > MinimumFlickVelocity) {
if (qAbs(pixelVelocity) > maximumFlickVelocity || snapMode == QQuickPathView::SnapOneItem) {
// limit velocity
qreal maxVel = velocity < 0 ? -maximumFlickVelocity : maximumFlickVelocity;
- velocity = maxVel / (path->path().length()/count);
+ velocity = maxVel / averageItemLength;
}
// Calculate the distance to be travelled
qreal v2 = velocity*velocity;
@@ -1815,7 +1804,7 @@ bool QQuickPathView::sendMouseEvent(QMouseEvent *event)
QPointF localPos = mapFromScene(event->windowPos());
QQuickWindow *c = window();
- QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
+ QQuickItem *grabber = c ? c->mouseGrabberItem() : nullptr;
if (grabber == this && d->stealMouse) {
// we are already the grabber and we do want the mouse event to ourselves.
return true;
@@ -1841,7 +1830,7 @@ bool QQuickPathView::sendMouseEvent(QMouseEvent *event)
default:
break;
}
- grabber = c ? c->mouseGrabberItem() : 0;
+ grabber = c ? c->mouseGrabberItem() : nullptr;
if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || grabberDisabled) {
grabMouse();
}
@@ -1901,6 +1890,14 @@ void QQuickPathView::updatePolish()
refill();
}
+static inline int currentIndexRemainder(int currentIndex, int modelCount) Q_DECL_NOTHROW
+{
+ if (currentIndex < 0)
+ return modelCount + currentIndex % modelCount;
+ else
+ return currentIndex % modelCount;
+}
+
void QQuickPathView::componentComplete()
{
Q_D(QQuickPathView);
@@ -1912,7 +1909,7 @@ void QQuickPathView::componentComplete()
if (d->model) {
d->modelCount = d->model->count();
if (d->modelCount && d->currentIndex != 0) // an initial value has been provided for currentIndex
- d->offset = qmlMod(d->modelCount - d->currentIndex, d->modelCount);
+ d->offset = std::fmod(qreal(d->modelCount - currentIndexRemainder(d->currentIndex, d->modelCount)), qreal(d->modelCount));
}
d->createHighlight();
@@ -1948,7 +1945,7 @@ void QQuickPathView::refill()
QList<QQuickItem*>::iterator it = d->items.begin();
while (it != d->items.end()) {
QQuickItem *item = *it;
- int idx = d->model->indexOf(item, 0);
+ int idx = d->model->indexOf(item, nullptr);
qreal pos = d->positionOfIndex(idx);
if (lcItemViewDelegateLifecycle().isDebugEnabled()) {
QQuickText *text = qmlobject_cast<QQuickText*>(item);
@@ -1986,13 +1983,14 @@ void QQuickPathView::refill()
qreal endPos;
int startIdx = 0;
qreal startPos = 0.0;
- if (d->items.count()) {
+ const bool wasEmpty = d->items.isEmpty();
+ if (!wasEmpty) {
//Find the beginning and end, items may not be in sorted order
endPos = -1.0;
startPos = 2.0;
- for (int i = 0; i < d->items.count(); i++) {
- int idx = d->model->indexOf(d->items[i], 0);
+ for (QQuickItem * item : qAsConst(d->items)) {
+ int idx = d->model->indexOf(item, nullptr);
qreal curPos = d->positionOfIndex(idx);
if (curPos > endPos) {
endPos = curPos;
@@ -2045,7 +2043,8 @@ void QQuickPathView::refill()
}
//Prepend
- idx = startIdx - 1;
+ idx = (wasEmpty ? d->calcCurrentIndex() : startIdx) - 1;
+
if (idx < 0)
idx = d->modelCount - 1;
nextPos = d->positionOfIndex(idx);
@@ -2082,29 +2081,35 @@ void QQuickPathView::refill()
if (!waiting && d->items.count() < count+d->cacheSize) {
qCDebug(lcItemViewDelegateLifecycle) << "Checking for pathview middle inserts, items count was" << d->items.count();
idx = startIdx;
- QQuickItem *lastItem = d->items[0];
+ QQuickItem *lastItem = d->items.at(0);
while (idx != endIdx) {
- //This gets the reference from the delegate model, and will not re-create
- QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0);
- if (!item) {
- waiting = true;
- break;
- }
- if (!d->items.contains(item)) { //We found a hole
- nextPos = d->positionOfIndex(idx);
- qCDebug(lcItemViewDelegateLifecycle) << "middle insert" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count();
- if (d->currentIndex == idx) {
- currentVisible = true;
- d->currentItemOffset = nextPos;
+ nextPos = d->positionOfIndex(idx);
+ if (d->isInBound(nextPos, d->mappedRange - d->mappedCache, 1.0 + d->mappedCache)) {
+ //This gets the reference from the delegate model, and will not re-create
+ QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0);
+ if (!item) {
+ waiting = true;
+ break;
}
- int lastListIdx = d->items.indexOf(lastItem);
- d->items.insert(lastListIdx + 1, item);
- d->updateItem(item, nextPos);
- } else {
- d->releaseItem(item);
+
+ if (!d->items.contains(item)) { //We found a hole
+ qCDebug(lcItemViewDelegateLifecycle) << "middle insert" << idx << "@" << nextPos
+ << (d->currentIndex == idx ? "current" : "")
+ << "items count was" << d->items.count();
+ if (d->currentIndex == idx) {
+ currentVisible = true;
+ d->currentItemOffset = nextPos;
+ }
+ int lastListIdx = d->items.indexOf(lastItem);
+ d->items.insert(lastListIdx + 1, item);
+ d->updateItem(item, nextPos);
+ } else {
+ d->releaseItem(item);
+ }
+
+ lastItem = item;
}
- lastItem = item;
++idx;
if (idx >= d->modelCount)
idx = 0;
@@ -2144,8 +2149,9 @@ void QQuickPathView::refill()
if (QQuickPathViewAttached *att = d->attached(d->highlightItem))
att->setOnPath(currentVisible);
}
- while (d->itemCache.count())
- d->releaseItem(d->itemCache.takeLast());
+ for (QQuickItem *item : qAsConst(d->itemCache))
+ d->releaseItem(item);
+ d->itemCache.clear();
d->inRefill = false;
if (currentChanged)
@@ -2173,7 +2179,7 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
int moveOffset = 0;
bool currentChanged = false;
bool changedOffset = false;
- foreach (const QQmlChangeSet::Change &r, changeSet.removes()) {
+ for (const QQmlChangeSet::Change &r : changeSet.removes()) {
if (moveId == -1 && d->currentIndex >= r.index + r.count) {
d->currentIndex -= r.count;
currentChanged = true;
@@ -2186,7 +2192,7 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setIsCurrentItem(true);
d->releaseItem(d->currentItem);
- d->currentItem = 0;
+ d->currentItem = nullptr;
}
d->currentIndex = qMin(r.index, d->modelCount - r.count - 1);
currentChanged = true;
@@ -2199,7 +2205,7 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
}
d->modelCount -= r.count;
}
- foreach (const QQmlChangeSet::Change &i, changeSet.inserts()) {
+ for (const QQmlChangeSet::Change &i : changeSet.inserts()) {
if (d->modelCount) {
if (moveId == -1 && i.index <= d->currentIndex) {
d->currentIndex += i.count;
@@ -2219,7 +2225,7 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
d->modelCount += i.count;
}
- d->offset = qmlMod(d->offset, d->modelCount);
+ d->offset = std::fmod(d->offset, qreal(d->modelCount));
if (d->offset < 0)
d->offset += d->modelCount;
if (d->currentIndex == -1)
@@ -2229,14 +2235,15 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
d->items.clear();
if (!d->modelCount) {
- while (d->itemCache.count())
- d->releaseItem(d->itemCache.takeLast());
+ for (QQuickItem * item : qAsConst(d->itemCache))
+ d->releaseItem(item);
+ d->itemCache.clear();
d->offset = 0;
changedOffset = true;
d->tl.reset(d->moveOffset);
} else {
if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
- d->offset = qmlMod(d->modelCount - d->currentIndex, d->modelCount);
+ d->offset = std::fmod(qreal(d->modelCount - d->currentIndex), qreal(d->modelCount));
changedOffset = true;
}
d->updateMappedRange();
@@ -2282,10 +2289,10 @@ int QQuickPathViewPrivate::calcCurrentIndex()
{
int current = 0;
if (modelCount && model && items.count()) {
- offset = qmlMod(offset, modelCount);
+ offset = std::fmod(offset, qreal(modelCount));
if (offset < 0)
offset += modelCount;
- current = qRound(qAbs(qmlMod(modelCount - offset, modelCount)));
+ current = qRound(qAbs(std::fmod(modelCount - offset, qreal(modelCount))));
current = current % modelCount;
}
@@ -2298,8 +2305,8 @@ void QQuickPathViewPrivate::createCurrentItem()
return;
bool inItems = false;
- for (int i = 0; i < items.count(); i++) {
- if (model->indexOf(items[i], 0) == currentIndex) {
+ for (QQuickItem *item : qAsConst(items)) {
+ if (model->indexOf(item, nullptr) == currentIndex) {
inItems = true;
break;
}
@@ -2337,7 +2344,7 @@ void QQuickPathViewPrivate::updateCurrent()
}
int oldCurrentIndex = currentIndex;
currentIndex = idx;
- currentItem = 0;
+ currentItem = nullptr;
createCurrentItem();
if (oldCurrentIndex != currentIndex)
emit q->currentIndexChanged();
@@ -2370,7 +2377,7 @@ void QQuickPathViewPrivate::snapToIndex(int index, MovementReason reason)
if (!model || modelCount <= 0)
return;
- qreal targetOffset = qmlMod(modelCount - index, modelCount);
+ qreal targetOffset = std::fmod(qreal(modelCount - index), qreal(modelCount));
if (offset == targetOffset)
return;
diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h
index daec965f02..1232f72935 100644
--- a/src/quick/items/qquickpathview_p.h
+++ b/src/quick/items/qquickpathview_p.h
@@ -53,6 +53,7 @@
#include "qquickitem.h"
+#include <private/qtquickglobal_p.h>
#include <private/qquickpath_p.h>
QT_BEGIN_NAMESPACE
@@ -61,7 +62,7 @@ class QQmlChangeSet;
class QQuickPathViewPrivate;
class QQuickPathViewAttached;
-class Q_AUTOTEST_EXPORT QQuickPathView : public QQuickItem
+class Q_QUICK_PRIVATE_EXPORT QQuickPathView : public QQuickItem
{
Q_OBJECT
@@ -97,7 +98,7 @@ class Q_AUTOTEST_EXPORT QQuickPathView : public QQuickItem
Q_PROPERTY(int cacheItemCount READ cacheItemCount WRITE setCacheItemCount NOTIFY cacheItemCountChanged)
public:
- QQuickPathView(QQuickItem *parent=0);
+ QQuickPathView(QQuickItem *parent = nullptr);
virtual ~QQuickPathView();
QVariant model() const;
@@ -116,7 +117,7 @@ public:
QQmlComponent *highlight() const;
void setHighlight(QQmlComponent *highlight);
- QQuickItem *highlightItem();
+ QQuickItem *highlightItem() const;
enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange };
Q_ENUM(HighlightRangeMode)
@@ -254,7 +255,7 @@ public:
QQuickPathViewAttached(QObject *parent);
~QQuickPathViewAttached();
- QQuickPathView *view() { return m_view; }
+ QQuickPathView *view() const { return m_view; }
bool isCurrentItem() const { return m_isCurrent; }
void setIsCurrentItem(bool c) {
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index d9c4baf572..571bb2e9e2 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -61,6 +61,7 @@
#include <private/qquickanimation_p_p.h>
#include <private/qqmldelegatemodel_p.h>
#include <private/qquicktimeline_p_p.h>
+#include <private/qpodvector_p.h>
QT_BEGIN_NAMESPACE
@@ -75,9 +76,8 @@ public:
void init();
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE {
- if ((newGeometry.size() != oldGeometry.size())
- && (!highlightItem || item != highlightItem)) {
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE {
+ if (change.sizeChange() && (!highlightItem || item != highlightItem)) {
if (QQuickPathViewAttached *att = attached(item))
att->m_percent = -1;
scheduleLayout();
@@ -125,7 +125,7 @@ public:
QPointF pointNear(const QPointF &point, qreal *nearPercent=0) const;
void addVelocitySample(qreal v);
qreal calcVelocity() const;
- qint64 computeCurrentTime(QInputEvent *event);
+ qint64 computeCurrentTime(QInputEvent *event) const;
void setDragging(bool d);
QQuickPath *path;
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index f3791a49ee..fd8971c845 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -245,7 +245,7 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate()
\since 5.5
This signal is emitted when the pinch area detects the smart zoom gesture.
- This gesture occurs only on certain operating systems such as OS X.
+ This gesture occurs only on certain operating systems such as \macos.
The \l {PinchEvent}{pinch} parameter provides information about the pinch
gesture, including the location where the gesture occurred. \c pinch.scale
diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h
index f0fbac2df7..d18f9b3724 100644
--- a/src/quick/items/qquickpositioners_p_p.h
+++ b/src/quick/items/qquickpositioners_p_p.h
@@ -137,9 +137,9 @@ public:
setPositioningDirty();
}
- void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE
{
- if (newGeometry.size() != oldGeometry.size())
+ if (change.sizeChange())
setPositioningDirty();
}
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index b8c680433e..9e747f2c47 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -72,7 +72,7 @@ QT_BEGIN_NAMESPACE
QQuickPen::QQuickPen(QObject *parent)
: QObject(parent)
, m_width(1)
- , m_color("#000000")
+ , m_color(Qt::black)
, m_aligned(true)
, m_valid(false)
{
@@ -482,8 +482,8 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
return 0;
}
- QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
- if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
+ QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
+ if (!rectangle) rectangle = d->sceneGraphContext()->createInternalRectangleNode();
rectangle->setRect(QRectF(0, 0, width(), height()));
rectangle->setColor(d->color);
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index dbe1add345..8b69447002 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -56,9 +56,9 @@
#include <QtQuick/QQuickWindow>
#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQuick/private/qsgsoftwarerenderer_p.h>
#include <QtCore/private/qobject_p.h>
-
QT_BEGIN_NAMESPACE
#ifndef QT_NO_OPENGL
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@@ -124,6 +124,10 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_
To send events, for example mouse or keyboard events, to the scene, use
QCoreApplication::sendEvent() with the QQuickWindow instance as the receiver.
+ \note In general QQuickRenderControl is supported in combination with all Qt
+ Quick backends. However, some functionality, in particular grab(), may not be
+ available in all cases.
+
\inmodule QtQuick
*/
@@ -209,8 +213,9 @@ void QQuickRenderControl::prepareThread(QThread *targetThread)
}
/*!
- Initializes the scene graph resources. The context \a gl has to
- be the current context.
+ Initializes the scene graph resources. The context \a gl has to be the
+ current OpenGL context or null if it is not relevant because a Qt Quick
+ backend other than OpenGL is in use.
\note Qt Quick does not take ownership of the context. It is up to the
application to destroy it after a call to invalidate() or after the
@@ -369,12 +374,31 @@ QImage QQuickRenderControl::grab()
if (!d->window)
return QImage();
- render();
+ QImage grabContent;
+
+ if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL) {
#ifndef QT_NO_OPENGL
- QImage grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
-#else
- QImage grabContent = d->window->grabWindow();
+ render();
+ grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
#endif
+ } else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
+ QSGSoftwareRenderer *softwareRenderer = static_cast<QSGSoftwareRenderer *>(cd->renderer);
+ if (softwareRenderer) {
+ const qreal dpr = d->window->effectiveDevicePixelRatio();
+ const QSize imageSize = d->window->size() * dpr;
+ grabContent = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
+ grabContent.setDevicePixelRatio(dpr);
+ QPaintDevice *prevDev = softwareRenderer->currentPaintDevice();
+ softwareRenderer->setCurrentPaintDevice(&grabContent);
+ softwareRenderer->markDirty();
+ render();
+ softwareRenderer->setCurrentPaintDevice(prevDev);
+ }
+ } else {
+ qWarning("QQuickRenderControl: grabs are not supported with the current Qt Quick backend");
+ }
+
return grabContent;
}
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 198573fda5..4f46f41b0d 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -461,7 +461,7 @@ void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
int difference = 0;
QHash<int, QVector<QPointer<QQuickItem> > > moved;
- foreach (const QQmlChangeSet::Change &remove, changeSet.removes()) {
+ for (const QQmlChangeSet::Change &remove : changeSet.removes()) {
int index = qMin(remove.index, d->deletables.count());
int count = qMin(remove.index + remove.count, d->deletables.count()) - index;
if (remove.isMove()) {
@@ -483,7 +483,7 @@ void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
difference -= remove.count;
}
- foreach (const QQmlChangeSet::Change &insert, changeSet.inserts()) {
+ for (const QQmlChangeSet::Change &insert : changeSet.inserts()) {
int index = qMin(insert.index, d->deletables.count());
if (insert.isMove()) {
QVector<QPointer<QQuickItem> > items = moved.value(insert.moveId);
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 5d01a2af9d..9347b55c70 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -207,100 +207,181 @@ QT_BEGIN_NAMESPACE
By default it is set to the value of the QScreen that the window uses.
*/
-QQuickScreenAttached::QQuickScreenAttached(QObject* attachee)
- : QObject(attachee)
- , m_screen(NULL)
- , m_window(NULL)
- , m_updateMask(0)
- , m_updateMaskSet(false)
+QQuickScreenInfo::QQuickScreenInfo(QObject *parent)
+ : QObject(parent),
+ m_screen(nullptr)
{
- m_attachee = qobject_cast<QQuickItem*>(attachee);
-
- if (m_attachee) {
- QQuickItemPrivate::get(m_attachee)->extra.value().screenAttached = this;
-
- if (m_attachee->window()) //It might not be assigned to a window yet
- windowChanged(m_attachee->window());
- } else {
- QQuickWindow *window = qobject_cast<QQuickWindow*>(attachee);
- if (window)
- windowChanged(window);
- }
-
- if (!m_screen)
- screenChanged(QGuiApplication::primaryScreen());
}
-QString QQuickScreenAttached::name() const
+QString QQuickScreenInfo::name() const
{
if (!m_screen)
return QString();
return m_screen->name();
}
-int QQuickScreenAttached::width() const
+int QQuickScreenInfo::width() const
{
if (!m_screen)
return 0;
return m_screen->size().width();
}
-int QQuickScreenAttached::height() const
+int QQuickScreenInfo::height() const
{
if (!m_screen)
return 0;
return m_screen->size().height();
}
-int QQuickScreenAttached::desktopAvailableWidth() const
+int QQuickScreenInfo::desktopAvailableWidth() const
{
if (!m_screen)
return 0;
return m_screen->availableVirtualSize().width();
}
-int QQuickScreenAttached::desktopAvailableHeight() const
+int QQuickScreenInfo::desktopAvailableHeight() const
{
if (!m_screen)
return 0;
return m_screen->availableVirtualSize().height();
}
-qreal QQuickScreenAttached::logicalPixelDensity() const
+qreal QQuickScreenInfo::logicalPixelDensity() const
{
if (!m_screen)
return 0.0;
return m_screen->logicalDotsPerInch() / 25.4;
}
-qreal QQuickScreenAttached::pixelDensity() const
+qreal QQuickScreenInfo::pixelDensity() const
{
if (!m_screen)
return 0.0;
return m_screen->physicalDotsPerInch() / 25.4;
}
-qreal QQuickScreenAttached::devicePixelRatio() const
+qreal QQuickScreenInfo::devicePixelRatio() const
{
if (!m_screen)
return 1.0;
return m_screen->devicePixelRatio();
}
-Qt::ScreenOrientation QQuickScreenAttached::primaryOrientation() const
+Qt::ScreenOrientation QQuickScreenInfo::primaryOrientation() const
{
if (!m_screen)
return Qt::PrimaryOrientation;
return m_screen->primaryOrientation();
}
-Qt::ScreenOrientation QQuickScreenAttached::orientation() const
+Qt::ScreenOrientation QQuickScreenInfo::orientation() const
{
if (!m_screen)
return Qt::PrimaryOrientation;
return m_screen->orientation();
}
+int QQuickScreenInfo::virtualX() const
+{
+ if (!m_screen)
+ return 0;
+ return m_screen->geometry().topLeft().x();
+}
+
+int QQuickScreenInfo::virtualY() const
+{
+ if (!m_screen)
+ return 0;
+ return m_screen->geometry().topLeft().y();
+}
+
+void QQuickScreenInfo::setWrappedScreen(QScreen *screen)
+{
+ if (screen == m_screen)
+ return;
+
+ QScreen *oldScreen = m_screen;
+ m_screen = screen;
+
+ if (oldScreen)
+ oldScreen->disconnect(this);
+
+ if (!screen) //Don't bother emitting signals, because the new values are garbage anyways
+ return;
+
+ if (!oldScreen || screen->geometry() != oldScreen->geometry()) {
+ emit virtualXChanged();
+ emit virtualYChanged();
+ }
+ if (!oldScreen || screen->size() != oldScreen->size()) {
+ emit widthChanged();
+ emit heightChanged();
+ }
+ if (!oldScreen || screen->name() != oldScreen->name())
+ emit nameChanged();
+ if (!oldScreen || screen->orientation() != oldScreen->orientation())
+ emit orientationChanged();
+ if (!oldScreen || screen->primaryOrientation() != oldScreen->primaryOrientation())
+ emit primaryOrientationChanged();
+ if (!oldScreen || screen->availableVirtualGeometry() != oldScreen->availableVirtualGeometry())
+ emit desktopGeometryChanged();
+ if (!oldScreen || screen->logicalDotsPerInch() != oldScreen->logicalDotsPerInch())
+ emit logicalPixelDensityChanged();
+ if (!oldScreen || screen->physicalDotsPerInch() != oldScreen->physicalDotsPerInch())
+ emit pixelDensityChanged();
+ if (!oldScreen || screen->devicePixelRatio() != oldScreen->devicePixelRatio())
+ emit devicePixelRatioChanged();
+
+ connect(screen, SIGNAL(geometryChanged(QRect)),
+ this, SIGNAL(widthChanged()));
+ connect(screen, SIGNAL(geometryChanged(QRect)),
+ this, SIGNAL(heightChanged()));
+ connect(screen, SIGNAL(geometryChanged(QRect)),
+ this, SIGNAL(virtualXChanged()));
+ connect(screen, SIGNAL(geometryChanged(QRect)),
+ this, SIGNAL(virtualYChanged()));
+ connect(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation)),
+ this, SIGNAL(orientationChanged()));
+ connect(screen, SIGNAL(primaryOrientationChanged(Qt::ScreenOrientation)),
+ this, SIGNAL(primaryOrientationChanged()));
+ connect(screen, SIGNAL(virtualGeometryChanged(QRect)),
+ this, SIGNAL(desktopGeometryChanged()));
+ connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)),
+ this, SIGNAL(logicalPixelDensityChanged()));
+ connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)),
+ this, SIGNAL(pixelDensityChanged()));
+}
+
+QScreen *QQuickScreenInfo::wrappedScreen() const
+{
+ return m_screen;
+}
+
+QQuickScreenAttached::QQuickScreenAttached(QObject* attachee)
+ : QQuickScreenInfo(attachee)
+ , m_window(NULL)
+ , m_updateMask(0)
+ , m_updateMaskSet(false)
+{
+ m_attachee = qobject_cast<QQuickItem*>(attachee);
+
+ if (m_attachee) {
+ QQuickItemPrivate::get(m_attachee)->extra.value().screenAttached = this;
+
+ if (m_attachee->window()) //It might not be assigned to a window yet
+ windowChanged(m_attachee->window());
+ } else {
+ QQuickWindow *window = qobject_cast<QQuickWindow*>(attachee);
+ if (window)
+ windowChanged(window);
+ }
+
+ if (!m_screen)
+ screenChanged(QGuiApplication::primaryScreen());
+}
+
Qt::ScreenOrientations QQuickScreenAttached::orientationUpdateMask() const
{
return m_updateMask;
@@ -341,55 +422,15 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
{
//qDebug() << "QQuickScreenAttached::screenChanged" << (screen ? screen->name() : QString::fromLatin1("null"));
if (screen != m_screen) {
- QScreen* oldScreen = m_screen;
- m_screen = screen;
-
- if (oldScreen)
- oldScreen->disconnect(this);
-
- if (!screen)
- return; //Don't bother emitting signals, because the new values are garbage anyways
-
+ setWrappedScreen(screen);
+ if (!m_screen)
+ return;
if (m_updateMaskSet) {
- screen->setOrientationUpdateMask(m_updateMask);
- } else if (m_updateMask != screen->orientationUpdateMask()) {
- m_updateMask = screen->orientationUpdateMask();
+ m_screen->setOrientationUpdateMask(m_updateMask);
+ } else if (m_updateMask != m_screen->orientationUpdateMask()) {
+ m_updateMask = m_screen->orientationUpdateMask();
emit orientationUpdateMaskChanged();
}
-
- if (!oldScreen || screen->size() != oldScreen->size()) {
- emit widthChanged();
- emit heightChanged();
- }
- if (!oldScreen || screen->name() != oldScreen->name())
- emit nameChanged();
- if (!oldScreen || screen->orientation() != oldScreen->orientation())
- emit orientationChanged();
- if (!oldScreen || screen->primaryOrientation() != oldScreen->primaryOrientation())
- emit primaryOrientationChanged();
- if (!oldScreen || screen->availableVirtualGeometry() != oldScreen->availableVirtualGeometry())
- emit desktopGeometryChanged();
- if (!oldScreen || screen->logicalDotsPerInch() != oldScreen->logicalDotsPerInch())
- emit logicalPixelDensityChanged();
- if (!oldScreen || screen->physicalDotsPerInch() != oldScreen->physicalDotsPerInch())
- emit pixelDensityChanged();
- if (!oldScreen || screen->devicePixelRatio() != oldScreen->devicePixelRatio())
- emit devicePixelRatioChanged();
-
- connect(screen, SIGNAL(geometryChanged(QRect)),
- this, SIGNAL(widthChanged()));
- connect(screen, SIGNAL(geometryChanged(QRect)),
- this, SIGNAL(heightChanged()));
- connect(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation)),
- this, SIGNAL(orientationChanged()));
- connect(screen, SIGNAL(primaryOrientationChanged(Qt::ScreenOrientation)),
- this, SIGNAL(primaryOrientationChanged()));
- connect(screen, SIGNAL(virtualGeometryChanged(QRect)),
- this, SIGNAL(desktopGeometryChanged()));
- connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)),
- this, SIGNAL(logicalPixelDensityChanged()));
- connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)),
- this, SIGNAL(pixelDensityChanged()));
}
}
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index 06d9a06070..06efb3ab45 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -63,10 +63,10 @@ class QQuickItem;
class QQuickWindow;
class QScreen;
-class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject
+
+class Q_AUTOTEST_EXPORT QQuickScreenInfo : public QObject
{
Q_OBJECT
-
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(int width READ width NOTIFY widthChanged)
Q_PROPERTY(int height READ height NOTIFY heightChanged)
@@ -79,11 +79,12 @@ class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject
Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY primaryOrientationChanged)
// TODO Qt 6 Remove this orientation -> incomplete device orientation -> better use OrientationSensor
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
- Q_PROPERTY(Qt::ScreenOrientations orientationUpdateMask READ orientationUpdateMask
- WRITE setOrientationUpdateMask NOTIFY orientationUpdateMaskChanged)
+
+ Q_PROPERTY(int virtualX READ virtualX NOTIFY virtualXChanged REVISION 1)
+ Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 1)
public:
- QQuickScreenAttached(QObject* attachee);
+ QQuickScreenInfo(QObject *parent = nullptr);
QString name() const;
int width() const;
@@ -95,13 +96,11 @@ public:
qreal devicePixelRatio() const;
Qt::ScreenOrientation primaryOrientation() const;
Qt::ScreenOrientation orientation() const;
- Qt::ScreenOrientations orientationUpdateMask() const;
- void setOrientationUpdateMask(Qt::ScreenOrientations mask);
+ int virtualX() const;
+ int virtualY() const;
- //Treats int as Qt::ScreenOrientation, due to QTBUG-20639
- Q_INVOKABLE int angleBetween(int a, int b);
-
- void windowChanged(QQuickWindow*);
+ void setWrappedScreen(QScreen *screen);
+ QScreen *wrappedScreen() const;
Q_SIGNALS:
void nameChanged();
@@ -113,13 +112,37 @@ Q_SIGNALS:
void devicePixelRatioChanged();
void primaryOrientationChanged();
void orientationChanged();
+ Q_REVISION(1) void virtualXChanged();
+ Q_REVISION(1) void virtualYChanged();
+
+protected:
+ QPointer<QScreen> m_screen;
+};
+
+class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QQuickScreenInfo
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::ScreenOrientations orientationUpdateMask READ orientationUpdateMask
+ WRITE setOrientationUpdateMask NOTIFY orientationUpdateMaskChanged)
+
+public:
+ QQuickScreenAttached(QObject* attachee);
+
+ Qt::ScreenOrientations orientationUpdateMask() const;
+ void setOrientationUpdateMask(Qt::ScreenOrientations mask);
+
+ //Treats int as Qt::ScreenOrientation, due to QTBUG-20639
+ Q_INVOKABLE int angleBetween(int a, int b);
+
+ void windowChanged(QQuickWindow*);
+
+Q_SIGNALS:
void orientationUpdateMaskChanged();
protected Q_SLOTS:
void screenChanged(QScreen*);
private:
- QPointer<QScreen> m_screen;
QQuickWindow* m_window;
QQuickItem* m_attachee;
Qt::ScreenOrientations m_updateMask;
@@ -136,5 +159,6 @@ public:
QT_END_NAMESPACE
QML_DECLARE_TYPEINFO(QQuickScreen, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QQuickScreenInfo)
#endif
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index f7fc7880ed..5670696ce2 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -39,6 +39,7 @@
#include <private/qquickshadereffect_p.h>
#include <private/qsgcontextplugin_p.h>
+#include <private/qquickitem_p.h>
#ifndef QT_NO_OPENGL
#include <private/qquickopenglshadereffect_p.h>
#endif
@@ -168,7 +169,12 @@ QT_BEGIN_NAMESPACE
\note Scene Graph textures have origin in the top-left corner rather than
bottom-left which is common in OpenGL.
- For information about the GLSL version being used, see \l QtQuick::OpenGLInfo.
+ For information about the GLSL version being used, see \l QtQuick::GraphicsInfo.
+
+ Starting from Qt 5.8 ShaderEffect also supports reading the GLSL source
+ code from files. Whenever the fragmentShader or vertexShader property value
+ is a URL with the \c file or \c qrc schema, it is treated as a file
+ reference and the source code is read from the specified file.
\section1 Direct3D and HLSL
@@ -209,17 +215,43 @@ QT_BEGIN_NAMESPACE
it is the textures that map to properties referencing \l Image or
\l ShaderEffectSource items.
- Unlike with OpenGL, runtime compilation of shader source code may not be
- supported. Backends for modern APIs are likely to prefer offline
+ Unlike OpenGL, backends for modern APIs will typically prefer offline
compilation and shipping pre-compiled bytecode with applications instead of
- inlined shader source strings. To check what is expected at runtime, use the
- GraphicsInfo.shaderSourceType and GraphicsInfo.shaderCompilationType properties.
+ inlined shader source strings. In this case the string properties for
+ vertex and fragment shaders are treated as URLs referring to local files or
+ files shipped via the Qt resource system.
+
+ To check at runtime what is supported, use the
+ GraphicsInfo.shaderSourceType and GraphicsInfo.shaderCompilationType
+ properties. Note that these are bitmasks, because some backends may support
+ multiple approaches.
+
+ In case of Direct3D 12, all combinations are supported. If the vertexShader
+ and fragmentShader properties form a valid URL with the \c file or \c qrc
+ schema, the bytecode or HLSL source code is read from the specified file.
+ The type of the file contents is detected automatically. Otherwise, the
+ string is treated as HLSL source code and is compiled at runtime, assuming
+ Shader Model 5.0 and an entry point of \c{"main"}. This allows dynamically
+ constructing shader strings. However, whenever the shader source code is
+ static, it is strongly recommended to pre-compile to bytecode using the
+ \c fxc tool and refer to these files from QML. This will be a lot more
+ efficient at runtime and allows catching syntax errors in the shaders at
+ compile time.
+
+ Unlike OpenGL, the Direct3D backend is able to perform runtime shader
+ compilation on dedicated threads. This is managed transparently to the
+ applications, and means that ShaderEffect items that contain HLSL source
+ strings do not block the rendering or other parts of the application until
+ the bytecode is ready.
+
+ Using files with bytecode is more flexible also when it comes to the entry
+ point name (it can be anything, not limited to \c main) and the shader
+ model (it can be something newer than 5.0, for instance 5.1).
\table 70%
\row
- \li \image declarative-shadereffectitem.png
\li \qml
- import QtQuick 2.8
+ import QtQuick 2.0
Rectangle {
width: 200; height: 100
@@ -259,6 +291,14 @@ QT_BEGIN_NAMESPACE
in the constant buffer at offset 0, even though the pixel shader does not
use the value.
+ If desired, the HLSL source code can be placed directly into the QML
+ source, similarly to how its done with GLSL. The only difference in this
+ case is the entry point name, which must be \c main when using inline
+ source strings.
+
+ Alternatively, we could also have referred to a file containing the source
+ of the effect instead of the compiled bytecode version.
+
Some effects will want to provide a vertex shader as well. Below is a
similar effect with both the vertex and fragment shader provided by the
application. This time the colorization factor is provided by the QML item
@@ -267,9 +307,8 @@ QT_BEGIN_NAMESPACE
\table 70%
\row
- \li \image declarative-shadereffectitem.png
\li \qml
- import QtQuick 2.8
+ import QtQuick 2.0
Rectangle {
width: 200; height: 100
@@ -327,6 +366,94 @@ QT_BEGIN_NAMESPACE
appropriate, meaning texture coordinates in HLSL version of the shaders
will not need any adjustments compared to the equivalent GLSL code.
+ \section1 Cross-platform, Cross-API ShaderEffect Items
+
+ Some applications will want to be functional with multiple accelerated
+ graphics backends. This has consequences for ShaderEffect items because the
+ supported shading languages may vary from backend to backend.
+
+ There are two approaches to handle this: either write conditional property
+ values based on GraphicsInfo.shaderType, or use file selectors. In practice
+ the latter is strongly recommended as it leads to more concise and cleaner
+ application code. The only case it is not suitable is when the source
+ strings are constructed dynamically.
+
+ \table 70%
+ \row
+ \li \qml
+ import QtQuick 2.8 // for GraphicsInfo
+
+ Rectangle {
+ width: 200; height: 100
+ Row {
+ Image { id: img;
+ sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
+ ShaderEffect {
+ width: 100; height: 100
+ property variant src: img
+ property variant color: Qt.vector3d(0.344, 0.5, 0.156)
+ fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.GLSL ?
+ "varying highp vec2 coord;
+ uniform sampler2D src;
+ uniform lowp float qt_Opacity;
+ void main() {
+ lowp vec4 tex = texture2D(src, coord);
+ gl_FragColor = vec4(vec3(dot(tex.rgb,
+ vec3(0.344, 0.5, 0.156))),
+ tex.a) * qt_Opacity;"
+ : GraphicsInfo.shaderType === GraphicsInfo.HLSL ?
+ "cbuffer ConstantBuffer : register(b0)
+ {
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ };
+ Texture2D src : register(t0);
+ SamplerState srcSampler : register(s0);
+ float4 ExamplePixelShader(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
+ {
+ float4 tex = src.Sample(srcSampler, coord);
+ float3 col = dot(tex.rgb, float3(0.344, 0.5, 0.156));
+ return float4(col, tex.a) * qt_Opacity;
+ }"
+ : ""
+ }
+ }
+ }
+ \endqml
+ \row
+
+ \li This is the first approach based on GraphicsInfo. Note that the value
+ reported by GraphicsInfo is not up-to-date until the ShaderEffect item gets
+ associated with a QQuickWindow. Before that, the reported value is
+ GraphicsInfo.UnknownShadingLanguage. The alternative is to place the GLSL
+ source code and the compiled D3D bytecode into the files
+ \c{shaders/effect.frag} and \c{shaders/+hlsl/effect.frag}, include them in
+ the Qt resource system, and let the ShaderEffect's internal QFileSelector
+ do its job. The selector-less version is the GLSL source, while the \c hlsl
+ selector is used when running on the D3D12 backend. The file under
+ \c{+hlsl} can then contain either HLSL source code or compiled bytecode
+ from the \c fxc tool. Additionally, when using a version 3.2 or newer core
+ profile context with OpenGL, GLSL sources with a core profile compatible
+ syntax can be placed under \c{+glslcore}.
+ \qml
+ import QtQuick 2.8 // for GraphicsInfo
+
+ Rectangle {
+ width: 200; height: 100
+ Row {
+ Image { id: img;
+ sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
+ ShaderEffect {
+ width: 100; height: 100
+ property variant src: img
+ property variant color: Qt.vector3d(0.344, 0.5, 0.156)
+ fragmentShader: "qrc:shaders/effect.frag" // selects the correct variant automatically
+ }
+ }
+ }
+ \endqml
+ \endtable
+
\section1 ShaderEffect and Item Layers
The ShaderEffect type can be combined with \l {Item Layers} {layered items}.
@@ -360,10 +487,18 @@ QT_BEGIN_NAMESPACE
\sa {Item Layers}
*/
+class QQuickShaderEffectPrivate : public QQuickItemPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickShaderEffect)
+
+public:
+ void updatePolish() override;
+};
+
QSGContextFactoryInterface::Flags qsg_backend_flags();
QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
- : QQuickItem(parent),
+ : QQuickItem(*new QQuickShaderEffectPrivate, parent),
#ifndef QT_NO_OPENGL
m_glImpl(nullptr),
#endif
@@ -690,12 +825,12 @@ void QQuickShaderEffect::componentComplete()
{
#ifndef QT_NO_OPENGL
if (m_glImpl) {
- m_glImpl->handleComponentComplete();
+ m_glImpl->maybeUpdateShaders();
QQuickItem::componentComplete();
return;
}
#endif
- m_impl->handleComponentComplete();
+ m_impl->maybeUpdateShaders();
QQuickItem::componentComplete();
}
@@ -723,7 +858,19 @@ QString QQuickShaderEffect::parseLog() // for OpenGL-based autotests
if (m_glImpl)
return m_glImpl->parseLog();
#endif
- return QString();
+ return m_impl->parseLog();
+}
+
+void QQuickShaderEffectPrivate::updatePolish()
+{
+ Q_Q(QQuickShaderEffect);
+#ifndef QT_NO_OPENGL
+ if (q->m_glImpl) {
+ q->m_glImpl->maybeUpdateShaders();
+ return;
+ }
+#endif
+ q->m_impl->maybeUpdateShaders();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 62d7e6fe5f..17b009039a 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE
class QQuickOpenGLShaderEffect;
class QQuickGenericShaderEffect;
+class QQuickShaderEffectPrivate;
class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
{
@@ -134,6 +135,8 @@ private:
QQuickOpenGLShaderEffect *m_glImpl;
#endif
QQuickGenericShaderEffect *m_impl;
+
+ Q_DECLARE_PRIVATE(QQuickShaderEffect)
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectmesh.cpp b/src/quick/items/qquickshadereffectmesh.cpp
index f5cc19c877..20b8d23af3 100644
--- a/src/quick/items/qquickshadereffectmesh.cpp
+++ b/src/quick/items/qquickshadereffectmesh.cpp
@@ -42,7 +42,7 @@
#include "qquickshadereffect_p.h"
#include "qquickscalegrid_p_p.h"
#include "qquickborderimage_p_p.h"
-#include <QtQuick/private/qsgbasicimagenode_p.h>
+#include <QtQuick/private/qsgbasicinternalimagenode_p.h>
QT_BEGIN_NAMESPACE
@@ -95,9 +95,8 @@ bool QQuickGridMesh::validateAttributes(const QVector<QByteArray> &attributes, i
return false;
case 1:
if (positionIndex != 0) {
- m_log = QLatin1String("Error: Missing \'");
- m_log += QLatin1String(qtPositionAttributeName());
- m_log += QLatin1String("\' attribute.\n");
+ m_log = QLatin1String("Error: Missing \'") + QLatin1String(qtPositionAttributeName())
+ + QLatin1String("\' attribute.\n");
return false;
}
break;
@@ -105,14 +104,12 @@ bool QQuickGridMesh::validateAttributes(const QVector<QByteArray> &attributes, i
if (positionIndex == -1 || texCoordIndex == -1) {
m_log.clear();
if (positionIndex == -1) {
- m_log = QLatin1String("Error: Missing \'");
- m_log += QLatin1String(qtPositionAttributeName());
- m_log += QLatin1String("\' attribute.\n");
+ m_log = QLatin1String("Error: Missing \'") + QLatin1String(qtPositionAttributeName())
+ + QLatin1String("\' attribute.\n");
}
if (texCoordIndex == -1) {
- m_log += QLatin1String("Error: Missing \'");
- m_log += QLatin1String(qtTexCoordAttributeName());
- m_log += QLatin1String("\' attribute.\n");
+ m_log += QLatin1String("Error: Missing \'") + QLatin1String(qtTexCoordAttributeName())
+ + QLatin1String("\' attribute.\n");
}
return false;
}
@@ -335,8 +332,8 @@ QSGGeometry *QQuickBorderImageMesh::updateGeometry(QSGGeometry *geometry, int at
innerSourceRect.width() * sourceRect.width(),
innerSourceRect.height() * sourceRect.height());
- geometry = QSGBasicImageNode::updateGeometry(targetRect, innerTargetRect, sourceRect,
- modifiedInnerSourceRect, subSourceRect, geometry);
+ geometry = QSGBasicInternalImageNode::updateGeometry(targetRect, innerTargetRect, sourceRect,
+ modifiedInnerSourceRect, subSourceRect, geometry);
return geometry;
}
@@ -367,7 +364,7 @@ QSGGeometry *QQuickBorderImageMesh::updateGeometry(QSGGeometry *geometry, int at
}
\endqml
*/
-QQuickScaleGrid *QQuickBorderImageMesh::border()
+QQuickScaleGrid *QQuickBorderImageMesh::border() const
{
return m_border;
}
diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h
index c5f1d19866..5e255e73a3 100644
--- a/src/quick/items/qquickshadereffectmesh_p.h
+++ b/src/quick/items/qquickshadereffectmesh_p.h
@@ -123,7 +123,7 @@ public:
QSGGeometry *updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
const QRectF &srcRect, const QRectF &rect) override;
- QQuickScaleGrid *border();
+ QQuickScaleGrid *border() const;
enum TileMode { Stretch = Qt::StretchTile, Repeat = Qt::RepeatTile, Round = Qt::RoundTile };
Q_ENUM(TileMode)
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 338e4dc3a7..1b37a746d3 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -64,7 +64,7 @@ public:
{
}
- QSGTexture *texture() const {
+ QSGTexture *texture() const override {
sourceTexture->setMipmapFiltering(mipmapFiltering);
sourceTexture->setFiltering(filtering);
sourceTexture->setHorizontalWrapMode(horizontalWrap);
@@ -308,11 +308,11 @@ QQuickItem *QQuickShaderEffectSource::sourceItem() const
return m_sourceItem;
}
-void QQuickShaderEffectSource::itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect)
+void QQuickShaderEffectSource::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
{
Q_ASSERT(item == m_sourceItem);
Q_UNUSED(item);
- if (newRect.size() != oldRect.size())
+ if (change.sizeChange())
update();
}
@@ -708,9 +708,9 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
return 0;
}
- QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
+ QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
- node = d->sceneGraphContext()->createImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode();
node->setFlag(QSGNode::UsePreprocess);
node->setTexture(m_texture);
QQuickShaderSourceAttachedNode *attached = new QQuickShaderSourceAttachedNode;
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 680ba85aa1..ee18bf195a 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -55,7 +55,7 @@
#include <QtQuick/qsgtextureprovider.h>
#include <private/qsgadaptationlayer_p.h>
#include <QtQuick/private/qsgcontext_p.h>
-#include <private/qsgdefaultimagenode_p.h>
+#include <private/qsgdefaultinternalimagenode_p.h>
#include <private/qquickitemchangelistener_p.h>
#include "qpointer.h"
@@ -168,7 +168,7 @@ protected:
void releaseResources() Q_DECL_OVERRIDE;
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
- void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
private:
diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h
index 1b8c8cee84..684d432f39 100644
--- a/src/quick/items/qquicksprite_p.h
+++ b/src/quick/items/qquicksprite_p.h
@@ -300,7 +300,7 @@ private Q_SLOTS:
private:
friend class QQuickImageParticle;
- friend class QQuickSpriteSequence;
+ //friend class QQuickSpriteSequence;
friend class QQuickAnimatedSprite;
friend class QQuickSpriteEngine;
friend class QQuickStochasticEngine;
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index c82966cf6b..74b04a75ad 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -94,7 +94,7 @@ QQuickStochasticEngine::QQuickStochasticEngine(QObject *parent) :
setCount(1);
}
-QQuickStochasticEngine::QQuickStochasticEngine(QList<QQuickStochasticState*> states, QObject *parent) :
+QQuickStochasticEngine::QQuickStochasticEngine(const QList<QQuickStochasticState *> &states, QObject *parent) :
QObject(parent), m_states(states), m_timeOffset(0), m_addAdvance(false)
{
//Default size 1
@@ -110,10 +110,10 @@ QQuickSpriteEngine::QQuickSpriteEngine(QObject *parent)
{
}
-QQuickSpriteEngine::QQuickSpriteEngine(QList<QQuickSprite*> sprites, QObject *parent)
+QQuickSpriteEngine::QQuickSpriteEngine(const QList<QQuickSprite *> &sprites, QObject *parent)
: QQuickSpriteEngine(parent)
{
- foreach (QQuickSprite* sprite, sprites)
+ for (QQuickSprite* sprite : sprites)
m_states << (QQuickStochasticState*)sprite;
}
@@ -122,7 +122,7 @@ QQuickSpriteEngine::~QQuickSpriteEngine()
}
-int QQuickSpriteEngine::maxFrames()
+int QQuickSpriteEngine::maxFrames() const
{
return m_maxFrames;
}
@@ -140,7 +140,7 @@ TODO: Above idea needs to have the varying duration offset added to it
m_startTimes will be set in advance/restart to 0->(m_framesPerRow-1) and can be used directly as extra.
This makes it 'frame' instead, but is more memory efficient than two arrays and less hideous than a vector of unions.
*/
-int QQuickSpriteEngine::pseudospriteProgress(int sprite, int state, int* rowDuration)
+int QQuickSpriteEngine::pseudospriteProgress(int sprite, int state, int* rowDuration) const
{
int myRowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames;
if (rowDuration)
@@ -153,7 +153,7 @@ int QQuickSpriteEngine::pseudospriteProgress(int sprite, int state, int* rowDura
return (m_timeOffset - m_startTimes[sprite]) / myRowDuration;
}
-int QQuickSpriteEngine::spriteState(int sprite)
+int QQuickSpriteEngine::spriteState(int sprite) const
{
if (!m_loaded)
return 0;
@@ -174,7 +174,7 @@ int QQuickSpriteEngine::spriteState(int sprite)
return state + extra;
}
-int QQuickSpriteEngine::spriteStart(int sprite)
+int QQuickSpriteEngine::spriteStart(int sprite) const
{
if (!m_duration[sprite] || !m_loaded)
return m_timeOffset;
@@ -188,7 +188,7 @@ int QQuickSpriteEngine::spriteStart(int sprite)
return m_startTimes[sprite] + extra*rowDuration;
}
-int QQuickSpriteEngine::spriteFrames(int sprite)
+int QQuickSpriteEngine::spriteFrames(int sprite) const
{
if (!m_loaded)
return 1;
@@ -215,7 +215,7 @@ int QQuickSpriteEngine::spriteFrames(int sprite)
return m_sprites[state]->m_framesPerRow;
}
-int QQuickSpriteEngine::spriteDuration(int sprite)//Full duration, not per frame
+int QQuickSpriteEngine::spriteDuration(int sprite) const //Full duration, not per frame
{
if (!m_duration[sprite] || !m_loaded)
return m_duration[sprite];
@@ -235,7 +235,7 @@ int QQuickSpriteEngine::spriteDuration(int sprite)//Full duration, not per frame
return rowDuration;
}
-int QQuickSpriteEngine::spriteY(int sprite)
+int QQuickSpriteEngine::spriteY(int sprite) const
{
if (!m_loaded)
return 0;
@@ -257,7 +257,7 @@ int QQuickSpriteEngine::spriteY(int sprite)
return m_sprites[state]->m_rowY + m_sprites[state]->m_frameHeight * extra;
}
-int QQuickSpriteEngine::spriteX(int sprite)
+int QQuickSpriteEngine::spriteX(int sprite) const
{
if (!m_loaded)
return 0;
@@ -280,24 +280,24 @@ int QQuickSpriteEngine::spriteX(int sprite)
return m_sprites[state]->m_rowStartX;
}
-QQuickSprite* QQuickSpriteEngine::sprite(int sprite)
+QQuickSprite* QQuickSpriteEngine::sprite(int sprite) const
{
return m_sprites[m_things[sprite]];
}
-int QQuickSpriteEngine::spriteWidth(int sprite)
+int QQuickSpriteEngine::spriteWidth(int sprite) const
{
int state = m_things[sprite];
return m_sprites[state]->m_frameWidth;
}
-int QQuickSpriteEngine::spriteHeight(int sprite)
+int QQuickSpriteEngine::spriteHeight(int sprite) const
{
int state = m_things[sprite];
return m_sprites[state]->m_frameHeight;
}
-int QQuickSpriteEngine::spriteCount()//TODO: Actually image state count, need to rename these things to make sense together
+int QQuickSpriteEngine::spriteCount() const //TODO: Actually image state count, need to rename these things to make sense together
{
return m_imageStateCount;
}
@@ -312,24 +312,24 @@ void QQuickStochasticEngine::setGoal(int state, int sprite, bool jump)
return;
}
- if (m_things[sprite] == state)
+ if (m_things.at(sprite) == state)
return;//Already there
m_things[sprite] = state;
- m_duration[sprite] = m_states[state]->variedDuration();
+ m_duration[sprite] = m_states.at(state)->variedDuration();
m_goals[sprite] = -1;
restart(sprite);
emit stateChanged(sprite);
- emit m_states[state]->entered();
+ emit m_states.at(state)->entered();
return;
}
-QQuickPixmap::Status QQuickSpriteEngine::status()//Composed status of all Sprites
+QQuickPixmap::Status QQuickSpriteEngine::status() const //Composed status of all Sprites
{
if (!m_startedImageAssembly)
return QQuickPixmap::Null;
int null, loading, ready;
null = loading = ready = 0;
- foreach (QQuickSprite* s, m_sprites) {
+ for (QQuickSprite* s : m_sprites) {
switch (s->m_pix.status()) {
// ### Maybe add an error message here, because this null shouldn't be reached but when it does, the image fails without an error message.
case QQuickPixmap::Null : null++; break;
@@ -358,7 +358,7 @@ void QQuickSpriteEngine::startAssemblingImage()
QList<QQuickStochasticState*> removals;
- foreach (QQuickStochasticState* s, m_states){
+ for (QQuickStochasticState* s : qAsConst(m_states)) {
QQuickSprite* sprite = qobject_cast<QQuickSprite*>(s);
if (sprite) {
m_sprites << sprite;
@@ -367,16 +367,16 @@ void QQuickSpriteEngine::startAssemblingImage()
qDebug() << "Error: Non-sprite in QQuickSpriteEngine";
}
}
- foreach (QQuickStochasticState* s, removals)
+ for (QQuickStochasticState* s : qAsConst(removals))
m_states.removeAll(s);
m_startedImageAssembly = true;
}
-QImage QQuickSpriteEngine::assembledImage()
+QImage QQuickSpriteEngine::assembledImage(int maxSize)
{
QQuickPixmap::Status stat = status();
if (!m_errorsPrinted && stat == QQuickPixmap::Error) {
- foreach (QQuickSprite* s, m_sprites)
+ for (QQuickSprite* s : qAsConst(m_sprites))
if (s->m_pix.isError())
qmlInfo(s) << s->m_pix.error();
m_errorsPrinted = true;
@@ -389,25 +389,22 @@ QImage QQuickSpriteEngine::assembledImage()
int w = 0;
m_maxFrames = 0;
m_imageStateCount = 0;
- int maxSize = 0;
-#ifndef QT_NO_OPENGL
- //If there is no current OpenGL Context
- if (!QOpenGLContext::currentContext())
- return QImage();
- QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
-#else
- maxSize = 2048;
-#endif
-#ifdef SPRITE_IMAGE_DEBUG
- qDebug() << "MAX TEXTURE SIZE" << maxSize;
-#endif
- foreach (QQuickSprite* state, m_sprites){
+ for (QQuickSprite* state : qAsConst(m_sprites)) {
if (state->frames() > m_maxFrames)
m_maxFrames = state->frames();
QImage img = state->m_pix.image();
+ {
+ const QSize frameSize(state->m_frameWidth, state->m_frameHeight);
+ if (!(img.size() - frameSize).isValid()) {
+ qmlInfo(state).nospace() << "SpriteEngine: Invalid frame size " << frameSize << "."
+ " It's bigger than image size " << img.size() << ".";
+ return QImage();
+ }
+ }
+
//Check that the frame sizes are the same within one sprite
if (!state->m_frameWidth)
state->m_frameWidth = img.width() / state->frames();
@@ -444,7 +441,7 @@ QImage QQuickSpriteEngine::assembledImage()
image.fill(0);
QPainter p(&image);
int y = 0;
- foreach (QQuickSprite* state, m_sprites){
+ for (QQuickSprite* state : qAsConst(m_sprites)) {
QImage img(state->m_pix.image());
int frameWidth = state->m_frameWidth;
int frameHeight = state->m_frameHeight;
@@ -519,8 +516,8 @@ void QQuickStochasticEngine::start(int index, int state)
if (index >= m_things.count())
return;
m_things[index] = state;
- m_duration[index] = m_states[state]->variedDuration();
- if (m_states[state]->randomStart())
+ m_duration[index] = m_states.at(state)->variedDuration();
+ if (m_states.at(state)->randomStart())
m_startTimes[index] = NINF;
else
m_startTimes[index] = 0;
@@ -541,33 +538,33 @@ void QQuickStochasticEngine::stop(int index)
void QQuickStochasticEngine::restart(int index)
{
- bool randomStart = (m_startTimes[index] == NINF);
+ bool randomStart = (m_startTimes.at(index) == NINF);
m_startTimes[index] = m_timeOffset;
if (m_addAdvance)
m_startTimes[index] += m_advanceTime.elapsed();
if (randomStart)
- m_startTimes[index] -= qrand() % m_duration[index];
- int time = m_duration[index] + m_startTimes[index];
+ m_startTimes[index] -= qrand() % m_duration.at(index);
+ int time = m_duration.at(index) + m_startTimes.at(index);
for (int i=0; i<m_stateUpdates.count(); i++)
m_stateUpdates[i].second.removeAll(index);
- if (m_duration[index] >= 0)
+ if (m_duration.at(index) >= 0)
addToUpdateList(time, index);
}
void QQuickSpriteEngine::restart(int index) //Reimplemented to recognize and handle pseudostates
{
- bool randomStart = (m_startTimes[index] == NINF);
- if (m_loaded && m_sprites[m_things[index]]->frameSync()) {//Manually advanced
+ bool randomStart = (m_startTimes.at(index) == NINF);
+ if (m_loaded && m_sprites.at(m_things.at(index))->frameSync()) {//Manually advanced
m_startTimes[index] = 0;
- if (randomStart && m_sprites[m_things[index]]->m_generatedCount)
- m_startTimes[index] += qrand() % m_sprites[m_things[index]]->m_generatedCount;
+ if (randomStart && m_sprites.at(m_things.at(index))->m_generatedCount)
+ m_startTimes[index] += qrand() % m_sprites.at(m_things.at(index))->m_generatedCount;
} else {
m_startTimes[index] = m_timeOffset;
if (m_addAdvance)
m_startTimes[index] += m_advanceTime.elapsed();
if (randomStart)
- m_startTimes[index] -= qrand() % m_duration[index];
- int time = spriteDuration(index) + m_startTimes[index];
+ m_startTimes[index] -= qrand() % m_duration.at(index);
+ int time = spriteDuration(index) + m_startTimes.at(index);
if (randomStart) {
int curTime = m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0);
while (time < curTime) //Fast forward through psuedostates as needed
@@ -584,11 +581,11 @@ void QQuickStochasticEngine::advance(int idx)
{
if (idx >= m_things.count())
return;//TODO: Proper fix(because this has happened and I just ignored it)
- int nextIdx = nextState(m_things[idx],idx);
+ int nextIdx = nextState(m_things.at(idx), idx);
m_things[idx] = nextIdx;
- m_duration[idx] = m_states[nextIdx]->variedDuration();
+ m_duration[idx] = m_states.at(nextIdx)->variedDuration();
restart(idx);
- emit m_states[nextIdx]->entered();
+ emit m_states.at(nextIdx)->entered();
emit stateChanged(idx);
}
@@ -601,29 +598,29 @@ void QQuickSpriteEngine::advance(int idx) //Reimplemented to recognize and handl
if (idx >= m_things.count())
return;//TODO: Proper fix(because this has happened and I just ignored it)
- if (m_duration[idx] == 0) {
- if (m_sprites[m_things[idx]]->frameSync()) {
+ if (m_duration.at(idx) == 0) {
+ if (m_sprites.at(m_things.at(idx))->frameSync()) {
//Manually called, advance inner substate count
m_startTimes[idx]++;
- if (m_startTimes[idx] < m_sprites[m_things[idx]]->m_generatedCount) {
+ if (m_startTimes.at(idx) < m_sprites.at(m_things.at(idx))->m_generatedCount) {
//only a pseudostate ended
emit stateChanged(idx);
return;
}
}
//just go past the pseudostate logic
- } else if (m_startTimes[idx] + m_duration[idx]
+ } else if (m_startTimes.at(idx) + m_duration.at(idx)
> int(m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0))) {
//only a pseduostate ended
emit stateChanged(idx);
addToUpdateList(spriteStart(idx) + spriteDuration(idx) + (m_addAdvance ? m_advanceTime.elapsed() : 0), idx);
return;
}
- int nextIdx = nextState(m_things[idx],idx);
+ int nextIdx = nextState(m_things.at(idx), idx);
m_things[idx] = nextIdx;
- m_duration[idx] = m_states[nextIdx]->variedDuration();
+ m_duration[idx] = m_states.at(nextIdx)->variedDuration();
restart(idx);
- emit m_states[nextIdx]->entered();
+ emit m_states.at(nextIdx)->entered();
emit stateChanged(idx);
}
@@ -634,16 +631,16 @@ int QQuickStochasticEngine::nextState(int curState, int curThing)
if (goalPath == -1){//Random
qreal r =(qreal) qrand() / (qreal) RAND_MAX;
qreal total = 0.0;
- for (QVariantMap::const_iterator iter=m_states[curState]->m_to.constBegin();
- iter!=m_states[curState]->m_to.constEnd(); ++iter)
+ for (QVariantMap::const_iterator iter=m_states.at(curState)->m_to.constBegin();
+ iter!=m_states.at(curState)->m_to.constEnd(); ++iter)
total += (*iter).toReal();
r*=total;
- for (QVariantMap::const_iterator iter= m_states[curState]->m_to.constBegin();
- iter!=m_states[curState]->m_to.constEnd(); ++iter){
+ for (QVariantMap::const_iterator iter= m_states.at(curState)->m_to.constBegin();
+ iter!=m_states.at(curState)->m_to.constEnd(); ++iter){
if (r < (*iter).toReal()){
bool superBreak = false;
for (int i=0; i<m_states.count(); i++){
- if (m_states[i]->name() == iter.key()){
+ if (m_states.at(i)->name() == iter.key()){
nextIdx = i;
superBreak = true;
break;
@@ -667,8 +664,9 @@ uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a lis
//Sprite State Update;
m_timeOffset = time;
m_addAdvance = false;
- while (!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){
- foreach (int idx, m_stateUpdates.first().second)
+ while (!m_stateUpdates.isEmpty() && time >= m_stateUpdates.constFirst().first){
+ const auto copy = m_stateUpdates.constFirst().second;
+ for (int idx : copy)
advance(idx);
m_stateUpdates.pop_front();
}
@@ -677,14 +675,14 @@ uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a lis
m_addAdvance = true;
if (m_stateUpdates.isEmpty())
return uint(-1);
- return m_stateUpdates.first().first;
+ return m_stateUpdates.constFirst().first;
}
int QQuickStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist)
{
QString goalName;
- if (m_goals[spriteIdx] != -1)
- goalName = m_states[m_goals[spriteIdx]]->name();
+ if (m_goals.at(spriteIdx) != -1)
+ goalName = m_states.at(m_goals.at(spriteIdx))->name();
else
goalName = m_globalGoal;
if (goalName.isEmpty())
@@ -692,16 +690,16 @@ int QQuickStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist)
//TODO: caching instead of excessively redoing iterative deepening (which was chosen arbitrarily anyways)
// Paraphrased - implement in an *efficient* manner
for (int i=0; i<m_states.count(); i++)
- if (m_states[curIdx]->name() == goalName)
+ if (m_states.at(curIdx)->name() == goalName)
return curIdx;
if (dist < 0)
dist = m_states.count();
- QQuickStochasticState* curState = m_states[curIdx];
+ QQuickStochasticState* curState = m_states.at(curIdx);
for (QVariantMap::const_iterator iter = curState->m_to.constBegin();
iter!=curState->m_to.constEnd(); ++iter){
if (iter.key() == goalName)
for (int i=0; i<m_states.count(); i++)
- if (m_states[i]->name() == goalName)
+ if (m_states.at(i)->name() == goalName)
return i;
}
QSet<int> options;
@@ -710,7 +708,7 @@ int QQuickStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist)
iter!=curState->m_to.constEnd(); ++iter){
int option = -1;
for (int j=0; j<m_states.count(); j++)//One place that could be a lot more efficient...
- if (m_states[j]->name() == iter.key())
+ if (m_states.at(j)->name() == iter.key())
if (goalSeek(j, spriteIdx, i) != -1)
option = j;
if (option != -1)
@@ -724,13 +722,13 @@ int QQuickStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist)
qreal total = 0;
for (QSet<int>::const_iterator iter=options.constBegin();
iter!=options.constEnd(); ++iter)
- total += curState->m_to.value(m_states[(*iter)]->name()).toReal();
+ total += curState->m_to.value(m_states.at((*iter))->name()).toReal();
r *= total;
for (QVariantMap::const_iterator iter = curState->m_to.constBegin();
iter!=curState->m_to.constEnd(); ++iter){
bool superContinue = true;
for (int j=0; j<m_states.count(); j++)
- if (m_states[j]->name() == iter.key())
+ if (m_states.at(j)->name() == iter.key())
if (options.contains(j))
superContinue = false;
if (superContinue)
@@ -738,7 +736,7 @@ int QQuickStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist)
if (r < (*iter).toReal()){
bool superBreak = false;
for (int j=0; j<m_states.count(); j++){
- if (m_states[j]->name() == iter.key()){
+ if (m_states.at(j)->name() == iter.key()){
option = j;
superBreak = true;
break;
@@ -758,10 +756,10 @@ int QQuickStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist)
void QQuickStochasticEngine::addToUpdateList(uint t, int idx)
{
for (int i=0; i<m_stateUpdates.count(); i++){
- if (m_stateUpdates[i].first==t){
+ if (m_stateUpdates.at(i).first == t){
m_stateUpdates[i].second << idx;
return;
- }else if (m_stateUpdates[i].first > t){
+ } else if (m_stateUpdates.at(i).first > t) {
QList<int> tmpList;
tmpList << idx;
m_stateUpdates.insert(i, qMakePair(t, tmpList));
diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h
index 65f58fafcb..5154dd7a31 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -189,7 +189,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickStochasticEngine : public QObject
Q_PROPERTY(QQmlListProperty<QQuickStochasticState> states READ states)
public:
explicit QQuickStochasticEngine(QObject *parent = 0);
- QQuickStochasticEngine(QList<QQuickStochasticState*> states, QObject *parent=0);
+ QQuickStochasticEngine(const QList<QQuickStochasticState*> &states, QObject *parent = 0);
~QQuickStochasticEngine();
QQmlListProperty<QQuickStochasticState> states()
@@ -210,11 +210,11 @@ public:
virtual void restart(int index=0);
virtual void advance(int index=0);//Sends state to the next chosen state, unlike goal.
void stop(int index=0);
- int curState(int index=0) {return m_things[index];}
+ int curState(int index=0) const {return m_things[index];}
- QQuickStochasticState* state(int idx){return m_states[idx];}
- int stateIndex(QQuickStochasticState* s){return m_states.indexOf(s);}
- int stateIndex(const QString& s) {
+ QQuickStochasticState* state(int idx) const {return m_states[idx];}
+ int stateIndex(QQuickStochasticState* s) const {return m_states.indexOf(s);}
+ int stateIndex(const QString& s) const {
for (int i=0; i<m_states.count(); i++)
if (m_states[i]->name() == s)
return i;
@@ -266,39 +266,39 @@ class Q_QUICK_PRIVATE_EXPORT QQuickSpriteEngine : public QQuickStochasticEngine
Q_PROPERTY(QQmlListProperty<QQuickSprite> sprites READ sprites)
public:
explicit QQuickSpriteEngine(QObject *parent = 0);
- QQuickSpriteEngine(QList<QQuickSprite*> sprites, QObject *parent=0);
+ QQuickSpriteEngine(const QList<QQuickSprite*> &sprites, QObject *parent = 0);
~QQuickSpriteEngine();
QQmlListProperty<QQuickSprite> sprites()
{
return QQmlListProperty<QQuickSprite>(this, m_sprites);
}
- QQuickSprite* sprite(int sprite=0);
- int spriteState(int sprite=0);
- int spriteStart(int sprite=0);
- int spriteFrames(int sprite=0);
- int spriteDuration(int sprite=0);
- int spriteX(int sprite=0);
- int spriteY(int sprite=0);
- int spriteWidth(int sprite=0);
- int spriteHeight(int sprite=0);
- int spriteCount();//Like state count
- int maxFrames();
+ QQuickSprite* sprite(int sprite = 0) const;
+ int spriteState(int sprite = 0) const;
+ int spriteStart(int sprite = 0) const;
+ int spriteFrames(int sprite = 0) const;
+ int spriteDuration(int sprite = 0) const;
+ int spriteX(int sprite = 0) const;
+ int spriteY(int sprite = 0) const;
+ int spriteWidth(int sprite = 0) const;
+ int spriteHeight(int sprite = 0) const;
+ int spriteCount() const;//Like state count
+ int maxFrames() const;
void restart(int index=0) Q_DECL_OVERRIDE;
void advance(int index=0) Q_DECL_OVERRIDE;
//Similar API to QQuickPixmap for async loading convenience
- bool isNull() { return status() == QQuickPixmap::Null; }
- bool isReady() { return status() == QQuickPixmap::Ready; }
- bool isLoading() { return status() == QQuickPixmap::Loading; }
- bool isError() { return status() == QQuickPixmap::Error; }
- QQuickPixmap::Status status();//Composed status of all Sprites
+ bool isNull() const { return status() == QQuickPixmap::Null; }
+ bool isReady() const { return status() == QQuickPixmap::Ready; }
+ bool isLoading() const { return status() == QQuickPixmap::Loading; }
+ bool isError() const { return status() == QQuickPixmap::Error; }
+ QQuickPixmap::Status status() const; //Composed status of all Sprites
void startAssemblingImage();
- QImage assembledImage();
+ QImage assembledImage(int maxSize = 2048);
private:
- int pseudospriteProgress(int,int,int*rd=0);
+ int pseudospriteProgress(int, int, int *rd = 0) const;
QList<QQuickSprite*> m_sprites;
bool m_startedImageAssembly;
bool m_loaded;
diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp
index f32e1afd50..25a39f951a 100644
--- a/src/quick/items/qquickspritesequence.cpp
+++ b/src/quick/items/qquickspritesequence.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qquickspritesequence_p.h"
+#include "qquickspritesequence_p_p.h"
#include "qquicksprite_p.h"
#include "qquickspriteengine_p.h"
#include <QtQuick/private/qsgcontext_p.h>
@@ -54,111 +55,6 @@
QT_BEGIN_NAMESPACE
-class QQuickSpriteSequenceMaterial : public QSGMaterial
-{
-public:
- QQuickSpriteSequenceMaterial();
- ~QQuickSpriteSequenceMaterial();
- QSGMaterialType *type() const Q_DECL_OVERRIDE{ static QSGMaterialType type; return &type; }
- QSGMaterialShader *createShader() const Q_DECL_OVERRIDE;
- int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE
- {
- return this - static_cast<const QQuickSpriteSequenceMaterial *>(other);
- }
-
- QSGTexture *texture;
-
- float animT;
- float animX1;
- float animY1;
- float animX2;
- float animY2;
- float animW;
- float animH;
-};
-
-QQuickSpriteSequenceMaterial::QQuickSpriteSequenceMaterial()
- : texture(0)
- , animT(0.0f)
- , animX1(0.0f)
- , animY1(0.0f)
- , animX2(0.0f)
- , animY2(0.0f)
- , animW(1.0f)
- , animH(1.0f)
-{
- setFlag(Blending, true);
-}
-
-QQuickSpriteSequenceMaterial::~QQuickSpriteSequenceMaterial()
-{
- delete texture;
-}
-
-class SpriteSequenceMaterialData : public QSGMaterialShader
-{
-public:
- SpriteSequenceMaterialData()
- : QSGMaterialShader()
- {
- setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/items/shaders/sprite.vert"));
- setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/items/shaders/sprite.frag"));
- }
-
- void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE
- {
- QQuickSpriteSequenceMaterial *m = static_cast<QQuickSpriteSequenceMaterial *>(newEffect);
- m->texture->bind();
-
- program()->setUniformValue(m_opacity_id, state.opacity());
- program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT);
- program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2);
-
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrix_id, state.combinedMatrix());
- }
-
- void initialize() Q_DECL_OVERRIDE {
- m_matrix_id = program()->uniformLocation("qt_Matrix");
- m_opacity_id = program()->uniformLocation("qt_Opacity");
- m_animData_id = program()->uniformLocation("animData");
- m_animPos_id = program()->uniformLocation("animPos");
- }
-
- char const *const *attributeNames() const Q_DECL_OVERRIDE {
- static const char *attr[] = {
- "vPos",
- "vTex",
- 0
- };
- return attr;
- }
-
- int m_matrix_id;
- int m_opacity_id;
- int m_animData_id;
- int m_animPos_id;
-};
-
-QSGMaterialShader *QQuickSpriteSequenceMaterial::createShader() const
-{
- return new SpriteSequenceMaterialData;
-}
-
-struct SpriteVertex {
- float x;
- float y;
- float tx;
- float ty;
-};
-
-struct SpriteVertices {
- SpriteVertex v1;
- SpriteVertex v2;
- SpriteVertex v3;
- SpriteVertex v4;
-};
-
/*!
\qmltype SpriteSequence
\instantiates QQuickSpriteSequence
@@ -218,213 +114,185 @@ struct SpriteVertices {
//TODO: Implicitly size element to size of first sprite?
QQuickSpriteSequence::QQuickSpriteSequence(QQuickItem *parent) :
- QQuickItem(parent)
- , m_node(0)
- , m_material(0)
- , m_spriteEngine(0)
- , m_curFrame(0)
- , m_pleaseReset(false)
- , m_running(true)
- , m_interpolate(true)
- , m_curStateIdx(0)
+ QQuickItem(*(new QQuickSpriteSequencePrivate), parent)
{
setFlag(ItemHasContents);
connect(this, SIGNAL(runningChanged(bool)),
this, SLOT(update()));
- connect(this, SIGNAL(widthChanged()),
- this, SLOT(sizeVertices()));
- connect(this, SIGNAL(heightChanged()),
- this, SLOT(sizeVertices()));
}
void QQuickSpriteSequence::jumpTo(const QString &sprite)
{
- if (!m_spriteEngine)
+ Q_D(QQuickSpriteSequence);
+ if (!d->m_spriteEngine)
return;
- m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite), 0, true);
+ d->m_spriteEngine->setGoal(d->m_spriteEngine->stateIndex(sprite), 0, true);
}
void QQuickSpriteSequence::setGoalSprite(const QString &sprite)
{
- if (m_goalState != sprite){
- m_goalState = sprite;
+ Q_D(QQuickSpriteSequence);
+ if (d->m_goalState != sprite){
+ d->m_goalState = sprite;
emit goalSpriteChanged(sprite);
- if (m_spriteEngine)
- m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite));
+ if (d->m_spriteEngine)
+ d->m_spriteEngine->setGoal(d->m_spriteEngine->stateIndex(sprite));
}
}
-QQmlListProperty<QQuickSprite> QQuickSpriteSequence::sprites()
+void QQuickSpriteSequence::setRunning(bool arg)
{
- return QQmlListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+ Q_D(QQuickSpriteSequence);
+ if (d->m_running != arg) {
+ d->m_running = arg;
+ Q_EMIT runningChanged(arg);
+ }
}
-void QQuickSpriteSequence::createEngine()
+void QQuickSpriteSequence::setInterpolate(bool arg)
{
- //TODO: delay until component complete
- if (m_spriteEngine)
- delete m_spriteEngine;
- if (m_sprites.count()) {
- m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
- if (!m_goalState.isEmpty())
- m_spriteEngine->setGoal(m_spriteEngine->stateIndex(m_goalState));
- } else {
- m_spriteEngine = 0;
+ Q_D(QQuickSpriteSequence);
+ if (d->m_interpolate != arg) {
+ d->m_interpolate = arg;
+ Q_EMIT interpolateChanged(arg);
}
- reset();
}
-static QSGGeometry::Attribute SpriteSequence_Attributes[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // pos
- QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // tex
-};
-
-static QSGGeometry::AttributeSet SpriteSequence_AttributeSet =
+QQmlListProperty<QQuickSprite> QQuickSpriteSequence::sprites()
{
- 2, // Attribute Count
- (2+2) * sizeof(float),
- SpriteSequence_Attributes
-};
+ Q_D(QQuickSpriteSequence);
+ return QQmlListProperty<QQuickSprite>(this, &d->m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+}
-void QQuickSpriteSequence::sizeVertices()
+bool QQuickSpriteSequence::running() const
{
- if (!m_node)
- return;
+ Q_D(const QQuickSpriteSequence);
+ return d->m_running;
+}
- SpriteVertices *p = (SpriteVertices *) m_node->geometry()->vertexData();
- p->v1.x = 0;
- p->v1.y = 0;
+bool QQuickSpriteSequence::interpolate() const
+{
+ Q_D(const QQuickSpriteSequence);
+ return d->m_interpolate;
+}
- p->v2.x = width();
- p->v2.y = 0;
+QString QQuickSpriteSequence::goalSprite() const
+{
+ Q_D(const QQuickSpriteSequence);
+ return d->m_goalState;
+}
- p->v3.x = 0;
- p->v3.y = height();
+QString QQuickSpriteSequence::currentSprite() const
+{
+ Q_D(const QQuickSpriteSequence);
+ return d->m_curState;
+}
- p->v4.x = width();
- p->v4.y = height();
+void QQuickSpriteSequence::createEngine()
+{
+ Q_D(QQuickSpriteSequence);
+ //TODO: delay until component complete
+ if (d->m_spriteEngine)
+ delete d->m_spriteEngine;
+ if (d->m_sprites.count()) {
+ d->m_spriteEngine = new QQuickSpriteEngine(d->m_sprites, this);
+ if (!d->m_goalState.isEmpty())
+ d->m_spriteEngine->setGoal(d->m_spriteEngine->stateIndex(d->m_goalState));
+ } else {
+ d->m_spriteEngine = 0;
+ }
+ reset();
}
-QSGGeometryNode* QQuickSpriteSequence::buildNode()
+QSGSpriteNode *QQuickSpriteSequence::initNode()
{
- if (!m_spriteEngine) {
+ Q_D(QQuickSpriteSequence);
+
+ if (!d->m_spriteEngine) {
qmlInfo(this) << "No sprite engine...";
- return 0;
- } else if (m_spriteEngine->status() == QQuickPixmap::Null) {
- m_spriteEngine->startAssemblingImage();
+ return nullptr;
+ } else if (d->m_spriteEngine->status() == QQuickPixmap::Null) {
+ d->m_spriteEngine->startAssemblingImage();
update();//Schedule another update, where we will check again
- return 0;
- } else if (m_spriteEngine->status() == QQuickPixmap::Loading) {
+ return nullptr;
+ } else if (d->m_spriteEngine->status() == QQuickPixmap::Loading) {
update();//Schedule another update, where we will check again
- return 0;
+ return nullptr;
}
- m_material = new QQuickSpriteSequenceMaterial();
-
- QImage image = m_spriteEngine->assembledImage();
+ QImage image = d->m_spriteEngine->assembledImage(d->sceneGraphRenderContext()->maxTextureSize());
if (image.isNull())
- return 0;
- m_sheetSize = QSizeF(image.size());
- m_material->texture = window()->createTextureFromImage(image);
- m_material->texture->setFiltering(QSGTexture::Linear);
- m_spriteEngine->start(0);
- m_material->animT = 0;
- m_material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width();
- m_material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height();
- m_material->animX2 = m_material->animX1;
- m_material->animY2 = m_material->animY1;
- m_material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width();
- m_material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height();
- m_curState = m_spriteEngine->state(m_spriteEngine->curState())->name();
- emit currentSpriteChanged(m_curState);
-
- int vCount = 4;
- int iCount = 6;
- QSGGeometry *g = new QSGGeometry(SpriteSequence_AttributeSet, vCount, iCount);
- g->setDrawingMode(GL_TRIANGLES);
-
- SpriteVertices *p = (SpriteVertices *) g->vertexData();
- QRectF texRect = m_material->texture->normalizedTextureSubRect();
-
- p->v1.tx = texRect.topLeft().x();
- p->v1.ty = texRect.topLeft().y();
-
- p->v2.tx = texRect.topRight().x();
- p->v2.ty = texRect.topRight().y();
-
- p->v3.tx = texRect.bottomLeft().x();
- p->v3.ty = texRect.bottomLeft().y();
-
- p->v4.tx = texRect.bottomRight().x();
- p->v4.ty = texRect.bottomRight().y();
-
- quint16 *indices = g->indexDataAsUShort();
- indices[0] = 0;
- indices[1] = 1;
- indices[2] = 2;
- indices[3] = 1;
- indices[4] = 3;
- indices[5] = 2;
-
-
- m_timestamp.start();
- m_node = new QSGGeometryNode();
- m_node->setGeometry(g);
- m_node->setMaterial(m_material);
- m_node->setFlag(QSGGeometryNode::OwnsMaterial);
- sizeVertices();
- return m_node;
+ return nullptr;
+
+ QSGSpriteNode *node = d->sceneGraphContext()->createSpriteNode();
+
+ d->m_sheetSize = QSize(image.size());
+ node->setTexture(window()->createTextureFromImage(image));
+ d->m_spriteEngine->start(0);
+ node->setTime(0.0f);
+ node->setSourceA(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY()));
+ node->setSourceB(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY()));
+ node->setSpriteSize(QSize(d->m_spriteEngine->spriteWidth(), d->m_spriteEngine->spriteHeight()));
+ node->setSheetSize(d->m_sheetSize);
+ node->setSize(QSizeF(width(), height()));
+
+ d->m_curState = d->m_spriteEngine->state(d->m_spriteEngine->curState())->name();
+ emit currentSpriteChanged(d->m_curState);
+ d->m_timestamp.start();
+ return node;
}
void QQuickSpriteSequence::reset()
{
- m_pleaseReset = true;
+ Q_D(QQuickSpriteSequence);
+ d->m_pleaseReset = true;
}
-QSGNode *QQuickSpriteSequence::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+QSGNode *QQuickSpriteSequence::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
- if (m_pleaseReset) {
- delete m_node;
+ Q_D(QQuickSpriteSequence);
- m_node = 0;
- m_material = 0;
- m_pleaseReset = false;
+ if (d->m_pleaseReset) {
+ delete oldNode;
+
+ oldNode = nullptr;
+ d->m_pleaseReset = false;
}
- prepareNextFrame();
+ QSGSpriteNode *node = static_cast<QSGSpriteNode *>(oldNode);
+ if (!node)
+ node = initNode();
+
+ if (node)
+ prepareNextFrame(node);
- if (m_running) {
+ if (d->m_running) {
update();
- if (m_node)
- m_node->markDirty(QSGNode::DirtyMaterial);
}
- return m_node;
+ return node;
}
-void QQuickSpriteSequence::prepareNextFrame()
+void QQuickSpriteSequence::prepareNextFrame(QSGSpriteNode *node)
{
- if (m_node == 0)
- m_node = buildNode();
- if (m_node == 0) //error creating node
- return;
+ Q_D(QQuickSpriteSequence);
- uint timeInt = m_timestamp.elapsed();
+ uint timeInt = d->m_timestamp.elapsed();
qreal time = timeInt / 1000.;
//Advance State
- m_spriteEngine->updateSprites(timeInt);
- if (m_curStateIdx != m_spriteEngine->curState()) {
- m_curStateIdx = m_spriteEngine->curState();
- m_curState = m_spriteEngine->state(m_spriteEngine->curState())->name();
- emit currentSpriteChanged(m_curState);
- m_curFrame= -1;
+ d->m_spriteEngine->updateSprites(timeInt);
+ if (d->m_curStateIdx != d->m_spriteEngine->curState()) {
+ d->m_curStateIdx = d->m_spriteEngine->curState();
+ d->m_curState = d->m_spriteEngine->state(d->m_spriteEngine->curState())->name();
+ emit currentSpriteChanged(d->m_curState);
+ d->m_curFrame= -1;
}
//Advance Sprite
- qreal animT = m_spriteEngine->spriteStart()/1000.0;
- qreal frameCount = m_spriteEngine->spriteFrames();
- qreal frameDuration = m_spriteEngine->spriteDuration()/frameCount;
+ qreal animT = d->m_spriteEngine->spriteStart()/1000.0;
+ qreal frameCount = d->m_spriteEngine->spriteFrames();
+ qreal frameDuration = d->m_spriteEngine->spriteDuration()/frameCount;
double frameAt;
qreal progress;
if (frameDuration > 0) {
@@ -432,32 +300,32 @@ void QQuickSpriteSequence::prepareNextFrame()
frame = qBound(qreal(0.0), frame, frameCount - qreal(1.0));//Stop at count-1 frames until we have between anim interpolation
progress = std::modf(frame,&frameAt);
} else {
- m_curFrame++;
- if (m_curFrame >= frameCount){
- m_curFrame = 0;
- m_spriteEngine->advance();
+ d->m_curFrame++;
+ if (d->m_curFrame >= frameCount){
+ d->m_curFrame = 0;
+ d->m_spriteEngine->advance();
}
- frameAt = m_curFrame;
+ frameAt = d->m_curFrame;
progress = 0;
}
- if (m_spriteEngine->sprite()->reverse())
- frameAt = (m_spriteEngine->spriteFrames() - 1) - frameAt;
- qreal y = m_spriteEngine->spriteY() / m_sheetSize.height();
- qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width();
- qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height();
- qreal x1 = m_spriteEngine->spriteX() / m_sheetSize.width();
+ if (d->m_spriteEngine->sprite()->reverse())
+ frameAt = (d->m_spriteEngine->spriteFrames() - 1) - frameAt;
+ int y = d->m_spriteEngine->spriteY();
+ int w = d->m_spriteEngine->spriteWidth();
+ int h = d->m_spriteEngine->spriteHeight();
+ int x1 = d->m_spriteEngine->spriteX();
x1 += frameAt * w;
- qreal x2 = x1;
+ int x2 = x1;
if (frameAt < (frameCount-1))
x2 += w;
- m_material->animX1 = x1;
- m_material->animY1 = y;
- m_material->animX2 = x2;
- m_material->animY2 = y;
- m_material->animW = w;
- m_material->animH = h;
- m_material->animT = m_interpolate ? progress : 0.0;
+ node->setSourceA(QPoint(x1, y));
+ node->setSourceB(QPoint(x2, y));
+ node->setSpriteSize(QSize(w, h));
+ node->setTime(d->m_interpolate ? progress : 0.0);
+ node->setSize(QSizeF(width(), height()));
+ node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
+ node->update();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickspritesequence_p.h b/src/quick/items/qquickspritesequence_p.h
index b4cc133821..34af110a98 100644
--- a/src/quick/items/qquickspritesequence_p.h
+++ b/src/quick/items/qquickspritesequence_p.h
@@ -59,8 +59,8 @@ QT_BEGIN_NAMESPACE
class QSGContext;
class QQuickSprite;
class QQuickSpriteEngine;
-class QSGGeometryNode;
-class QQuickSpriteSequenceMaterial;
+class QQuickSpriteSequencePrivate;
+class QSGSpriteNode;
class Q_AUTOTEST_EXPORT QQuickSpriteSequence : public QQuickItem
{
Q_OBJECT
@@ -77,25 +77,10 @@ public:
QQmlListProperty<QQuickSprite> sprites();
- bool running() const
- {
- return m_running;
- }
-
- bool interpolate() const
- {
- return m_interpolate;
- }
-
- QString goalSprite() const
- {
- return m_goalState;
- }
-
- QString currentSprite() const
- {
- return m_curState;
- }
+ bool running() const;
+ bool interpolate() const;
+ QString goalSprite() const;
+ QString currentSprite() const;
Q_SIGNALS:
@@ -108,46 +93,23 @@ public Q_SLOTS:
void jumpTo(const QString &sprite);
void setGoalSprite(const QString &sprite);
-
- void setRunning(bool arg)
- {
- if (m_running != arg) {
- m_running = arg;
- Q_EMIT runningChanged(arg);
- }
- }
-
- void setInterpolate(bool arg)
- {
- if (m_interpolate != arg) {
- m_interpolate = arg;
- Q_EMIT interpolateChanged(arg);
- }
- }
+ void setRunning(bool arg);
+ void setInterpolate(bool arg);
private Q_SLOTS:
void createEngine();
- void sizeVertices();
protected:
void reset();
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
private:
- void prepareNextFrame();
- QSGGeometryNode* buildNode();
- QSGGeometryNode *m_node;
- QQuickSpriteSequenceMaterial *m_material;
- QList<QQuickSprite*> m_sprites;
- QQuickSpriteEngine* m_spriteEngine;
- QTime m_timestamp;
- int m_curFrame;
- bool m_pleaseReset;
- bool m_running;
- bool m_interpolate;
- QString m_goalState;
- QString m_curState;
- int m_curStateIdx;
- QSizeF m_sheetSize;
+ void prepareNextFrame(QSGSpriteNode *node);
+ QSGSpriteNode* initNode();
+
+
+private:
+ Q_DISABLE_COPY(QQuickSpriteSequence)
+ Q_DECLARE_PRIVATE(QQuickSpriteSequence)
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickspritesequence_p_p.h b/src/quick/items/qquickspritesequence_p_p.h
new file mode 100644
index 0000000000..4f352b5b69
--- /dev/null
+++ b/src/quick/items/qquickspritesequence_p_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSPRITESEQUENCE_P_P_H
+#define QQUICKSPRITESEQUENCE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickitem_p.h"
+#include "qquicksprite_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSpriteSequence;
+
+class QQuickSpriteSequencePrivate :public QQuickItemPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSpriteSequence)
+public:
+ QQuickSpriteSequencePrivate()
+ : m_spriteEngine(nullptr)
+ , m_curFrame(0)
+ , m_pleaseReset(false)
+ , m_running(true)
+ , m_interpolate(true)
+ , m_curStateIdx(0)
+ {
+
+ }
+ QList<QQuickSprite*> m_sprites;
+ QQuickSpriteEngine* m_spriteEngine;
+ QTime m_timestamp;
+ int m_curFrame;
+ bool m_pleaseReset;
+ bool m_running;
+ bool m_interpolate;
+ QString m_goalState;
+ QString m_curState;
+ int m_curStateIdx;
+ QSize m_sheetSize;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSPRITESEQUENCE_P_P_H
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index 73b1680305..9cd3b6a5f5 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -359,8 +359,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
QQuickStateAction xa(d->target, QLatin1String("x"), x);
actions << xa;
} else {
- QQmlBinding *newBinding = new QQmlBinding(d->xString.value, d->target, qmlContext(this));
QQmlProperty property(d->target, QLatin1String("x"));
+ QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->xString.value, d->target, qmlContext(this));
newBinding->setTarget(property);
QQuickStateAction xa;
xa.property = property;
@@ -378,8 +378,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
QQuickStateAction ya(d->target, QLatin1String("y"), y);
actions << ya;
} else {
- QQmlBinding *newBinding = new QQmlBinding(d->yString.value, d->target, qmlContext(this));
QQmlProperty property(d->target, QLatin1String("y"));
+ QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->yString.value, d->target, qmlContext(this));
newBinding->setTarget(property);
QQuickStateAction ya;
ya.property = property;
@@ -397,8 +397,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
QQuickStateAction sa(d->target, QLatin1String("scale"), scale);
actions << sa;
} else {
- QQmlBinding *newBinding = new QQmlBinding(d->scaleString.value, d->target, qmlContext(this));
QQmlProperty property(d->target, QLatin1String("scale"));
+ QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->scaleString.value, d->target, qmlContext(this));
newBinding->setTarget(property);
QQuickStateAction sa;
sa.property = property;
@@ -416,8 +416,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
QQuickStateAction ra(d->target, QLatin1String("rotation"), rotation);
actions << ra;
} else {
- QQmlBinding *newBinding = new QQmlBinding(d->rotationString.value, d->target, qmlContext(this));
QQmlProperty property(d->target, QLatin1String("rotation"));
+ QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->rotationString.value, d->target, qmlContext(this));
newBinding->setTarget(property);
QQuickStateAction ra;
ra.property = property;
@@ -435,8 +435,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
QQuickStateAction wa(d->target, QLatin1String("width"), width);
actions << wa;
} else {
- QQmlBinding *newBinding = new QQmlBinding(d->widthString.value, d->target, qmlContext(this));
QQmlProperty property(d->target, QLatin1String("width"));
+ QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->widthString.value, d->target, qmlContext(this));
newBinding->setTarget(property);
QQuickStateAction wa;
wa.property = property;
@@ -454,8 +454,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
QQuickStateAction ha(d->target, QLatin1String("height"), height);
actions << ha;
} else {
- QQmlBinding *newBinding = new QQmlBinding(d->heightString.value, d->target, qmlContext(this));
QQmlProperty property(d->target, QLatin1String("height"));
+ QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->heightString.value, d->target, qmlContext(this));
newBinding->setTarget(property);
QQuickStateAction ha;
ha.property = property;
@@ -866,31 +866,31 @@ QQuickAnchorChanges::ActionList QQuickAnchorChanges::actions()
d->baselineProp = QQmlProperty(d->target, QLatin1String("anchors.baseline"));
if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::LeftAnchor) {
- d->leftBinding = new QQmlBinding(d->anchorSet->d_func()->leftScript, d->target, qmlContext(this));
+ d->leftBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->leftProp)->core, d->anchorSet->d_func()->leftScript, d->target, qmlContext(this));
d->leftBinding->setTarget(d->leftProp);
}
if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::RightAnchor) {
- d->rightBinding = new QQmlBinding(d->anchorSet->d_func()->rightScript, d->target, qmlContext(this));
+ d->rightBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->rightProp)->core, d->anchorSet->d_func()->rightScript, d->target, qmlContext(this));
d->rightBinding->setTarget(d->rightProp);
}
if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::HCenterAnchor) {
- d->hCenterBinding = new QQmlBinding(d->anchorSet->d_func()->hCenterScript, d->target, qmlContext(this));
+ d->hCenterBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->hCenterProp)->core, d->anchorSet->d_func()->hCenterScript, d->target, qmlContext(this));
d->hCenterBinding->setTarget(d->hCenterProp);
}
if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::TopAnchor) {
- d->topBinding = new QQmlBinding(d->anchorSet->d_func()->topScript, d->target, qmlContext(this));
+ d->topBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->topProp)->core, d->anchorSet->d_func()->topScript, d->target, qmlContext(this));
d->topBinding->setTarget(d->topProp);
}
if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::BottomAnchor) {
- d->bottomBinding = new QQmlBinding(d->anchorSet->d_func()->bottomScript, d->target, qmlContext(this));
+ d->bottomBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->bottomProp)->core, d->anchorSet->d_func()->bottomScript, d->target, qmlContext(this));
d->bottomBinding->setTarget(d->bottomProp);
}
if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::VCenterAnchor) {
- d->vCenterBinding = new QQmlBinding(d->anchorSet->d_func()->vCenterScript, d->target, qmlContext(this));
+ d->vCenterBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->vCenterProp)->core, d->anchorSet->d_func()->vCenterScript, d->target, qmlContext(this));
d->vCenterBinding->setTarget(d->vCenterProp);
}
if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::BaselineAnchor) {
- d->baselineBinding = new QQmlBinding(d->anchorSet->d_func()->baselineScript, d->target, qmlContext(this));
+ d->baselineBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->baselineProp)->core, d->anchorSet->d_func()->baselineScript, d->target, qmlContext(this));
d->baselineBinding->setTarget(d->baselineProp);
}
@@ -899,9 +899,9 @@ QQuickAnchorChanges::ActionList QQuickAnchorChanges::actions()
return ActionList() << a;
}
-QQuickAnchorSet *QQuickAnchorChanges::anchors()
+QQuickAnchorSet *QQuickAnchorChanges::anchors() const
{
- Q_D(QQuickAnchorChanges);
+ Q_D(const QQuickAnchorChanges);
return d->anchorSet;
}
@@ -1134,9 +1134,9 @@ QQuickStateActionEvent::EventType QQuickAnchorChanges::type() const
return AnchorChanges;
}
-QList<QQuickStateAction> QQuickAnchorChanges::additionalActions()
+QList<QQuickStateAction> QQuickAnchorChanges::additionalActions() const
{
- Q_D(QQuickAnchorChanges);
+ Q_D(const QQuickAnchorChanges);
QList<QQuickStateAction> extra;
QQuickAnchors::Anchors combined = d->anchorSet->d_func()->usedAnchors | d->anchorSet->d_func()->resetAnchors;
diff --git a/src/quick/items/qquickstateoperations_p.h b/src/quick/items/qquickstateoperations_p.h
index 29dec218fa..48b4b23a76 100644
--- a/src/quick/items/qquickstateoperations_p.h
+++ b/src/quick/items/qquickstateoperations_p.h
@@ -192,7 +192,7 @@ public:
ActionList actions() Q_DECL_OVERRIDE;
- QQuickAnchorSet *anchors();
+ QQuickAnchorSet *anchors() const;
QQuickItem *object() const;
void setObject(QQuickItem *);
@@ -210,7 +210,7 @@ public:
void rewind() Q_DECL_OVERRIDE;
void saveCurrentValues() Q_DECL_OVERRIDE;
- QList<QQuickStateAction> additionalActions();
+ QList<QQuickStateAction> additionalActions() const;
void saveTargetValues() Q_DECL_OVERRIDE;
};
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 648929c8cd..14268b472e 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -69,6 +69,7 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
@@ -321,7 +322,7 @@ void QQuickText::imageDownloadFinished()
if (d->extra.isAllocated() && d->extra->nbActiveDownloads == 0) {
bool needToUpdateLayout = false;
- foreach (QQuickStyledTextImgTag *img, d->extra->visibleImgTags) {
+ for (QQuickStyledTextImgTag *img : qAsConst(d->extra->visibleImgTags)) {
if (!img->size.isValid()) {
img->size = img->pix->implicitSize();
needToUpdateLayout = true;
@@ -1114,7 +1115,7 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
QList<QQuickStyledTextImgTag *> imagesInLine;
if (extra.isAllocated()) {
- foreach (QQuickStyledTextImgTag *image, extra->imgTags) {
+ for (QQuickStyledTextImgTag *image : qAsConst(extra->imgTags)) {
if (image->position >= line.textStart() &&
image->position < line.textStart() + line.textLength()) {
@@ -1151,9 +1152,12 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
}
}
- foreach (QQuickStyledTextImgTag *image, imagesInLine) {
+ for (QQuickStyledTextImgTag *image : qAsConst(imagesInLine)) {
totalLineHeight = qMax(totalLineHeight, textTop + image->pos.y() + image->size.height());
- image->pos.setX(line.cursorToX(image->position));
+ const int leadX = line.cursorToX(image->position);
+ const int trailX = line.cursorToX(image->position, QTextLine::Trailing);
+ const bool rtl = trailX < leadX;
+ image->pos.setX(leadX + (rtl ? (-image->offset - image->size.width()) : image->offset));
image->pos.setY(image->pos.y() + height + textTop);
extra->visibleImgTags << image;
}
@@ -2058,6 +2062,7 @@ void QQuickText::setTextFormat(TextFormat format)
}
d->updateLayout();
setAcceptHoverEvents(d->richText || d->styledText);
+ setAcceptedMouseButtons(d->richText || d->styledText ? Qt::LeftButton : Qt::NoButton);
emit textFormatChanged(d->format);
}
@@ -2337,7 +2342,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
node->addTextLayout(QPointF(dx, dy), d->elideLayout, color, d->style, styleColor, linkColor);
if (d->extra.isAllocated()) {
- foreach (QQuickStyledTextImgTag *img, d->extra->visibleImgTags) {
+ for (QQuickStyledTextImgTag *img : qAsConst(d->extra->visibleImgTags)) {
QQuickPixmap *pix = img->pix;
if (pix && pix->isReady())
node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, pix->width(), pix->height()), pix->image());
@@ -2591,7 +2596,8 @@ QString QQuickTextPrivate::anchorAt(const QTextLayout *layout, const QPointF &mo
QTextLine line = layout->lineAt(i);
if (line.naturalTextRect().contains(mousePos)) {
int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter);
- foreach (const QTextLayout::FormatRange &formatRange, layout->formats()) {
+ const auto formats = layout->formats();
+ for (const QTextLayout::FormatRange &formatRange : formats) {
if (formatRange.format.isAnchor()
&& charPos >= formatRange.start
&& charPos < formatRange.start + formatRange.length) {
@@ -2720,6 +2726,7 @@ QString QQuickText::hoveredLink() const
void QQuickTextPrivate::processHoverEvent(QHoverEvent *event)
{
Q_Q(QQuickText);
+ qCDebug(DBG_HOVER_TRACE) << q;
QString link;
if (isLinkHoveredConnected()) {
if (event->type() != QEvent::HoverLeave)
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 45238e2d0c..fe29249934 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -58,6 +58,7 @@
#include "qtextlist.h"
#include "qtextdocumentwriter.h"
#include "private/qtextcursor_p.h"
+#include <QtCore/qloggingcategory.h>
#include <qtextformat.h>
#include <qdatetime.h>
@@ -76,6 +77,7 @@
const int textCursorWidth = 1;
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
#ifndef QT_NO_CONTEXTMENU
#endif
@@ -1513,6 +1515,7 @@ void QQuickTextControlPrivate::hoverEvent(QHoverEvent *e, const QPointF &pos)
hoveredLink = link;
emit q->linkHovered(link);
}
+ qCDebug(DBG_HOVER_TRACE) << q << e->type() << pos << "hoveredLink" << hoveredLink;
}
bool QQuickTextControl::hasImState() const
@@ -1661,8 +1664,8 @@ void QQuickTextControl::insertFromMimeData(const QMimeData *source)
#ifndef QT_NO_TEXTHTMLPARSER
if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
// x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
- QString richtext = QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
- richtext.prepend(QLatin1String("<meta name=\"qrichtext\" content=\"1\" />"));
+ const QString richtext = QLatin1String("<meta name=\"qrichtext\" content=\"1\" />")
+ + QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
hasData = true;
} else if (source->hasHtml() && d->acceptRichText) {
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index 602e457cb8..e06e3b8b29 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -193,9 +193,11 @@ class QQuickTextEditMimeData : public QMimeData
public:
inline QQuickTextEditMimeData(const QTextDocumentFragment &aFragment) : fragment(aFragment) {}
- virtual QStringList formats() const;
+ QStringList formats() const override;
+
protected:
- virtual QVariant retrieveData(const QString &mimeType, QVariant::Type type) const;
+ QVariant retrieveData(const QString &mimeType, QVariant::Type type) const override;
+
private:
void setup() const;
diff --git a/src/quick/items/qquicktextdocument.cpp b/src/quick/items/qquicktextdocument.cpp
index 3eacfd61bc..287e07e980 100644
--- a/src/quick/items/qquicktextdocument.cpp
+++ b/src/quick/items/qquicktextdocument.cpp
@@ -179,7 +179,7 @@ void QQuickTextDocumentWithImageResources::drawObject(
{
}
-QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format)
+QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format) const
{
QVariant res = resource(QTextDocument::ImageResource, QUrl(format.name()));
return res.value<QImage>();
@@ -219,7 +219,7 @@ QQuickPixmap *QQuickTextDocumentWithImageResources::loadPixmap(
void QQuickTextDocumentWithImageResources::clearResources()
{
- foreach (QQuickPixmap *pixmap, m_resources)
+ for (QQuickPixmap *pixmap : qAsConst(m_resources))
pixmap->clear(this);
qDeleteAll(m_resources);
m_resources.clear();
diff --git a/src/quick/items/qquicktextdocument_p.h b/src/quick/items/qquicktextdocument_p.h
index 3ffedb5b96..1218b12b89 100644
--- a/src/quick/items/qquicktextdocument_p.h
+++ b/src/quick/items/qquicktextdocument_p.h
@@ -75,10 +75,10 @@ public:
void setText(const QString &);
int resourcesLoading() const { return outstanding; }
- QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format);
- void drawObject(QPainter *p, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format);
+ QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) override;
+ void drawObject(QPainter *p, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) override;
- QImage image(const QTextImageFormat &format);
+ QImage image(const QTextImageFormat &format) const;
public Q_SLOTS:
void clearResources();
@@ -87,7 +87,7 @@ Q_SIGNALS:
void imagesLoaded();
protected:
- QVariant loadResource(int type, const QUrl &name);
+ QVariant loadResource(int type, const QUrl &name) override;
QQuickPixmap *loadPixmap(QQmlContext *context, const QUrl &name);
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 36eb5d3cde..c81544cbdb 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -153,7 +153,7 @@ namespace {
newNode->setFlag(QSGNode::OwnedByParent);
}
- void resetCursorNode(QSGRectangleNode* newNode)
+ void resetCursorNode(QSGInternalRectangleNode* newNode)
{
if (cursorNode)
removeChildNode(cursorNode);
@@ -165,7 +165,7 @@ namespace {
}
}
- QSGRectangleNode *cursorNode;
+ QSGInternalRectangleNode *cursorNode;
QQuickTextNode* frameDecorationsNode;
};
@@ -1489,8 +1489,8 @@ void QQuickTextEdit::setSelectByKeyboard(bool on)
If true, the user can use the mouse to select text in some
platform-specific way. Note that for some platforms this may
- not be an appropriate interaction (eg. may conflict with how
- the text needs to behave inside a Flickable.
+ not be an appropriate interaction; it may conflict with how
+ the text needs to behave inside a Flickable, for example.
*/
bool QQuickTextEdit::selectByMouse() const
{
@@ -2065,7 +2065,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
// Having nodes spanning across frame boundaries will break the current bookkeeping mechanism. We need to prevent that.
QList<int> frameBoundaries;
frameBoundaries.reserve(frames.size());
- Q_FOREACH (QTextFrame *frame, frames)
+ for (QTextFrame *frame : qAsConst(frames))
frameBoundaries.append(frame->firstPosition());
std::sort(frameBoundaries.begin(), frameBoundaries.end());
@@ -2125,9 +2125,9 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
}
if (d->cursorComponent == 0) {
- QSGRectangleNode* cursor = 0;
+ QSGInternalRectangleNode* cursor = 0;
if (!isReadOnly() && d->cursorVisible && d->control->cursorOn())
- cursor = d->sceneGraphContext()->createRectangleNode(d->control->cursorRect(), d->color);
+ cursor = d->sceneGraphContext()->createInternalRectangleNode(d->control->cursorRect(), d->color);
rootNode->resetCursorNode(cursor);
}
@@ -2499,7 +2499,7 @@ void QQuickTextEdit::updateWholeDocument()
{
Q_D(QQuickTextEdit);
if (!d->textNodeMap.isEmpty()) {
- Q_FOREACH (TextNode* node, d->textNodeMap)
+ for (TextNode* node : qAsConst(d->textNodeMap))
node->setDirty();
}
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 9b7eb4ea4b..68112461b2 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -84,7 +84,7 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
and setting \l echoMode to an appropriate value enables TextInput to be used for
a password input field.
- On OS X, the Up/Down key bindings for Home/End are explicitly disabled.
+ On \macos, the Up/Down key bindings for Home/End are explicitly disabled.
If you want such bindings (on any platform), you will need to construct them in QML.
\sa TextEdit, Text
@@ -1042,6 +1042,7 @@ void QQuickTextInput::q_validatorChanged()
QRectF QQuickTextInputPrivate::anchorRectangle() const
{
+ Q_Q(const QQuickTextInput);
QRectF rect;
int a;
// Unfortunately we cannot use selectionStart() and selectionEnd()
@@ -1062,8 +1063,8 @@ QRectF QQuickTextInputPrivate::anchorRectangle() const
a = 0;
QTextLine l = m_textLayout.lineForTextPosition(a);
if (l.isValid()) {
- qreal x = l.cursorToX(a) - hscroll;
- qreal y = l.y() - vscroll;
+ qreal x = l.cursorToX(a) - hscroll + q->leftPadding();
+ qreal y = l.y() - vscroll + q->topPadding();
rect.setRect(x, y, 1, l.height());
}
}
@@ -2681,8 +2682,8 @@ void QQuickTextInputPrivate::init()
#endif
q->setFlag(QQuickItem::ItemHasContents);
#ifndef QT_NO_CLIPBOARD
- q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
- q, SLOT(q_canPasteChanged()));
+ qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()),
+ q, QQuickTextInput, SLOT(q_canPasteChanged()));
#endif // QT_NO_CLIPBOARD
lastSelectionStart = 0;
@@ -2842,7 +2843,7 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
// drawing boxes when using fonts that don't have glyphs for such
// characters)
QChar* uc = str.data();
- for (int i = 0; i < (int)str.length(); ++i) {
+ for (int i = 0; i < str.length(); ++i) {
if ((uc[i].unicode() < 0x20 && uc[i] != QChar::Tabulation)
|| uc[i] == QChar::LineSeparator
|| uc[i] == QChar::ParagraphSeparator
@@ -2991,7 +2992,7 @@ void QQuickTextInputPrivate::updateLayout()
if (inLayout) // probably the result of a binding loop, but by letting it
return; // get this far we'll get a warning to that effect.
}
- qreal lineWidth = q->widthValid() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX;
+ qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX;
qreal height = 0;
qreal width = 0;
do {
@@ -3228,7 +3229,7 @@ void QQuickTextInputPrivate::setSelection(int start, int length)
commitPreedit();
#endif
- if (start < 0 || start > (int)m_text.length()){
+ if (start < 0 || start > m_text.length()) {
qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
return;
}
@@ -3237,7 +3238,7 @@ void QQuickTextInputPrivate::setSelection(int start, int length)
if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
return;
m_selstart = start;
- m_selend = qMin(start + length, (int)m_text.length());
+ m_selend = qMin(start + length, m_text.length());
m_cursor = m_selend;
} else if (length < 0){
if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
@@ -3675,7 +3676,7 @@ void QQuickTextInputPrivate::internalInsert(const QString &s)
Q_ASSERT(!hasSelectedText()); // insert(), processInputMethodEvent() call removeSelectedText() first.
if (m_maskData) {
QString ms = maskString(m_cursor, s);
- for (int i = 0; i < (int) ms.length(); ++i) {
+ for (int i = 0; i < ms.length(); ++i) {
addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
}
@@ -3687,7 +3688,7 @@ void QQuickTextInputPrivate::internalInsert(const QString &s)
int remaining = m_maxLength - m_text.length();
if (remaining != 0) {
m_text.insert(m_cursor, s.left(remaining));
- for (int i = 0; i < (int) s.leftRef(remaining).length(); ++i)
+ for (int i = 0; i < s.leftRef(remaining).length(); ++i)
addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
m_textDirty = true;
}
@@ -3707,7 +3708,7 @@ void QQuickTextInputPrivate::internalInsert(const QString &s)
*/
void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
{
- if (m_cursor < (int) m_text.length()) {
+ if (m_cursor < m_text.length()) {
cancelPasswordEchoTimer();
Q_ASSERT(!hasSelectedText()); // del(), backspace() call removeSelectedText() first.
addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
@@ -3733,7 +3734,7 @@ void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
*/
void QQuickTextInputPrivate::removeSelectedText()
{
- if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
+ if (m_selstart < m_selend && m_selend <= m_text.length()) {
cancelPasswordEchoTimer();
int i ;
if (m_selstart <= m_cursor && m_cursor < m_selend) {
@@ -4019,44 +4020,44 @@ QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool cl
if (strIndex < str.length()) {
if (m_maskData[i].separator) {
s += m_maskData[i].maskChar;
- if (str[(int)strIndex] == m_maskData[i].maskChar)
+ if (str[strIndex] == m_maskData[i].maskChar)
strIndex++;
++i;
} else {
- if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
+ if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
switch (m_maskData[i].caseMode) {
case MaskInputData::Upper:
- s += str[(int)strIndex].toUpper();
+ s += str[strIndex].toUpper();
break;
case MaskInputData::Lower:
- s += str[(int)strIndex].toLower();
+ s += str[strIndex].toLower();
break;
default:
- s += str[(int)strIndex];
+ s += str[strIndex];
}
++i;
} else {
// search for separator first
- int n = findInMask(i, true, true, str[(int)strIndex]);
+ int n = findInMask(i, true, true, str[strIndex]);
if (n != -1) {
- if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
+ if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
s += fill.midRef(i, n-i+1);
i = n + 1; // update i to find + 1
}
} else {
// search for valid m_blank if not
- n = findInMask(i, true, false, str[(int)strIndex]);
+ n = findInMask(i, true, false, str[strIndex]);
if (n != -1) {
s += fill.midRef(i, n-i);
switch (m_maskData[n].caseMode) {
case MaskInputData::Upper:
- s += str[(int)strIndex].toUpper();
+ s += str[strIndex].toUpper();
break;
case MaskInputData::Lower:
- s += str[(int)strIndex].toLower();
+ s += str[strIndex].toLower();
break;
default:
- s += str[(int)strIndex];
+ s += str[strIndex];
}
i = n + 1; // updates i to find + 1
}
@@ -4107,7 +4108,7 @@ QString QQuickTextInputPrivate::stripString(const QString &str) const
return str;
QString s;
- int end = qMin(m_maxLength, (int)str.length());
+ int end = qMin(m_maxLength, str.length());
for (int i = 0; i < end; ++i) {
if (m_maskData[i].separator)
s += m_maskData[i].maskChar;
@@ -4197,7 +4198,7 @@ void QQuickTextInputPrivate::internalRedo()
if (!isRedoAvailable())
return;
internalDeselect();
- while (m_undoState < (int)m_history.size()) {
+ while (m_undoState < m_history.size()) {
Command& cmd = m_history[m_undoState++];
switch (cmd.type) {
case Insert:
@@ -4224,7 +4225,7 @@ void QQuickTextInputPrivate::internalRedo()
m_cursor = cmd.pos;
break;
}
- if (m_undoState < (int)m_history.size()) {
+ if (m_undoState < m_history.size()) {
Command& next = m_history[m_undoState];
if (next.type != cmd.type
&& cmd.type < RemoveSelection
@@ -4355,8 +4356,13 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
if (!(q->inputMethodHints() & Qt::ImhMultiLine))
inputMethod->hide();
+ if (activeFocus) {
+ // If we lost focus after hiding the virtual keyboard, we've already emitted
+ // editingFinished from handleFocusEvent. Otherwise we emit it now.
+ emit q->editingFinished();
+ }
+
emit q->accepted();
- emit q->editingFinished();
}
event->ignore();
return;
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index 7ee01b5398..8716f98bff 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -136,7 +136,7 @@ void QQuickTextNode::setCursor(const QRectF &rect, const QColor &color)
delete m_cursorNode;
QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
- m_cursorNode = sg->sceneGraphContext()->createRectangleNode(rect, color);
+ m_cursorNode = sg->sceneGraphContext()->createInternalRectangleNode(rect, color);
appendChildNode(m_cursorNode);
}
@@ -151,19 +151,27 @@ void QQuickTextNode::clearCursor()
void QQuickTextNode::addRectangleNode(const QRectF &rect, const QColor &color)
{
QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
- appendChildNode(sg->sceneGraphContext()->createRectangleNode(rect, color));
+ appendChildNode(sg->sceneGraphContext()->createInternalRectangleNode(rect, color));
}
void QQuickTextNode::addImage(const QRectF &rect, const QImage &image)
{
QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
- QSGImageNode *node = sg->sceneGraphContext()->createImageNode();
+ QSGInternalImageNode *node = sg->sceneGraphContext()->createInternalImageNode();
QSGTexture *texture = sg->createTexture(image);
+ if (m_ownerElement->smooth()) {
+ texture->setFiltering(QSGTexture::Linear);
+ texture->setMipmapFiltering(QSGTexture::Linear);
+ }
m_textures.append(texture);
node->setTargetRect(rect);
node->setInnerTargetRect(rect);
node->setTexture(texture);
+ if (m_ownerElement->smooth()) {
+ node->setFiltering(QSGTexture::Linear);
+ node->setMipmapFiltering(QSGTexture::Linear);
+ }
appendChildNode(node);
node->update();
}
diff --git a/src/quick/items/qquicktextnode_p.h b/src/quick/items/qquicktextnode_p.h
index 0006cf1156..2969ce9dbc 100644
--- a/src/quick/items/qquicktextnode_p.h
+++ b/src/quick/items/qquicktextnode_p.h
@@ -68,7 +68,7 @@ class QColor;
class QTextDocument;
class QSGContext;
class QRawFont;
-class QSGRectangleNode;
+class QSGInternalRectangleNode;
class QSGClipNode;
class QSGTexture;
@@ -77,15 +77,6 @@ class QQuickTextNodeEngine;
class Q_QUICK_PRIVATE_EXPORT QQuickTextNode : public QSGTransformNode
{
public:
- enum Decoration {
- NoDecoration = 0x0,
- Underline = 0x1,
- Overline = 0x2,
- StrikeOut = 0x4,
- Background = 0x8
- };
- Q_DECLARE_FLAGS(Decorations, Decoration)
-
QQuickTextNode(QQuickItem *ownerElement);
~QQuickTextNode();
@@ -106,7 +97,7 @@ public:
void setCursor(const QRectF &rect, const QColor &color);
void clearCursor();
- QSGRectangleNode *cursorNode() const { return m_cursorNode; }
+ QSGInternalRectangleNode *cursorNode() const { return m_cursorNode; }
QSGGlyphNode *addGlyphs(const QPointF &position, const QGlyphRun &glyphs, const QColor &color,
QQuickText::TextStyle style = QQuickText::Normal, const QColor &styleColor = QColor(),
@@ -118,7 +109,7 @@ public:
void setUseNativeRenderer(bool on) { m_useNativeRenderer = on; }
private:
- QSGRectangleNode *m_cursorNode;
+ QSGInternalRectangleNode *m_cursorNode;
QList<QSGTexture *> m_textures;
QQuickItem *m_ownerElement;
bool m_useNativeRenderer;
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index 98da3ca777..4631b2e724 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -68,7 +68,7 @@ QQuickTextNodeEngine::BinaryTreeNodeKey::BinaryTreeNodeKey(BinaryTreeNode *node)
QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
SelectionState selState,
const QRectF &brect,
- const QQuickTextNode::Decorations &decs,
+ const Decorations &decs,
const QColor &c,
const QColor &bc,
const QPointF &pos, qreal a)
@@ -90,7 +90,7 @@ QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
- QQuickTextNode::Decorations decorations, const QColor &textColor,
+ Decorations decorations, const QColor &textColor,
const QColor &backgroundColor, const QPointF &position)
{
QRectF searchRect = glyphRun.boundingRect();
@@ -99,10 +99,10 @@ void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode
if (qFuzzyIsNull(searchRect.width()) || qFuzzyIsNull(searchRect.height()))
return;
- decorations |= (glyphRun.underline() ? QQuickTextNode::Underline : QQuickTextNode::NoDecoration);
- decorations |= (glyphRun.overline() ? QQuickTextNode::Overline : QQuickTextNode::NoDecoration);
- decorations |= (glyphRun.strikeOut() ? QQuickTextNode::StrikeOut : QQuickTextNode::NoDecoration);
- decorations |= (backgroundColor.isValid() ? QQuickTextNode::Background : QQuickTextNode::NoDecoration);
+ decorations |= (glyphRun.underline() ? Decoration::Underline : Decoration::NoDecoration);
+ decorations |= (glyphRun.overline() ? Decoration::Overline : Decoration::NoDecoration);
+ decorations |= (glyphRun.strikeOut() ? Decoration::StrikeOut : Decoration::NoDecoration);
+ decorations |= (backgroundColor.isValid() ? Decoration::Background : Decoration::NoDecoration);
qreal ascent = glyphRun.rawFont().ascent();
insert(binaryTree, BinaryTreeNode(glyphRun,
@@ -237,7 +237,7 @@ void QQuickTextNodeEngine::processCurrentLine()
SelectionState currentSelectionState = Unselected;
QRectF currentRect;
- QQuickTextNode::Decorations currentDecorations = QQuickTextNode::NoDecoration;
+ Decorations currentDecorations = Decoration::NoDecoration;
qreal underlineOffset = 0.0;
qreal underlineThickness = 0.0;
@@ -271,7 +271,7 @@ void QQuickTextNodeEngine::processCurrentLine()
currentSelectionState = node->selectionState;
// Update decorations
- if (currentDecorations != QQuickTextNode::NoDecoration) {
+ if (currentDecorations != Decoration::NoDecoration) {
decorationRect.setY(m_position.y() + m_currentLine.y());
decorationRect.setHeight(m_currentLine.height());
@@ -279,16 +279,16 @@ void QQuickTextNodeEngine::processCurrentLine()
decorationRect.setRight(node->boundingRect.left());
TextDecoration textDecoration(currentSelectionState, decorationRect, lastColor);
- if (currentDecorations & QQuickTextNode::Underline)
+ if (currentDecorations & Decoration::Underline)
pendingUnderlines.append(textDecoration);
- if (currentDecorations & QQuickTextNode::Overline)
+ if (currentDecorations & Decoration::Overline)
pendingOverlines.append(textDecoration);
- if (currentDecorations & QQuickTextNode::StrikeOut)
+ if (currentDecorations & Decoration::StrikeOut)
pendingStrikeOuts.append(textDecoration);
- if (currentDecorations & QQuickTextNode::Background)
+ if (currentDecorations & Decoration::Background)
m_backgrounds.append(qMakePair(decorationRect, lastBackgroundColor));
}
@@ -344,7 +344,7 @@ void QQuickTextNodeEngine::processCurrentLine()
// If previous item(s) had underline and current does not, then we add the
// pending lines to the lists and likewise for overlines and strikeouts
if (!pendingUnderlines.isEmpty()
- && !(node->decorations & QQuickTextNode::Underline)) {
+ && !(node->decorations & Decoration::Underline)) {
addTextDecorations(pendingUnderlines, underlineOffset, underlineThickness);
pendingUnderlines.clear();
@@ -377,19 +377,19 @@ void QQuickTextNodeEngine::processCurrentLine()
// Merge current values with previous. Prefer greatest thickness
QRawFont rawFont = node->glyphRun.rawFont();
- if (node->decorations & QQuickTextNode::Underline) {
+ if (node->decorations & Decoration::Underline) {
if (rawFont.lineThickness() > underlineThickness) {
underlineThickness = rawFont.lineThickness();
underlineOffset = rawFont.underlinePosition();
}
}
- if (node->decorations & QQuickTextNode::Overline) {
+ if (node->decorations & Decoration::Overline) {
overlineOffset = -rawFont.ascent();
overlineThickness = rawFont.lineThickness();
}
- if (node->decorations & QQuickTextNode::StrikeOut) {
+ if (node->decorations & Decoration::StrikeOut) {
strikeOutThickness = rawFont.lineThickness();
strikeOutOffset = rawFont.ascent() / -3.0;
}
@@ -495,7 +495,7 @@ void QQuickTextNodeEngine::addUnselectedGlyphs(const QGlyphRun &glyphRun)
BinaryTreeNode::insert(&m_currentLineTree,
glyphRun,
Unselected,
- QQuickTextNode::NoDecoration,
+ Decoration::NoDecoration,
m_textColor,
m_backgroundColor,
m_position);
@@ -507,7 +507,7 @@ void QQuickTextNodeEngine::addSelectedGlyphs(const QGlyphRun &glyphRun)
BinaryTreeNode::insert(&m_currentLineTree,
glyphRun,
Selected,
- QQuickTextNode::NoDecoration,
+ Decoration::NoDecoration,
m_textColor,
m_backgroundColor,
m_position);
@@ -642,9 +642,12 @@ void QQuickTextNodeEngine::addBorder(const QRectF &rect, qreal border,
void QQuickTextNodeEngine::addFrameDecorations(QTextDocument *document, QTextFrame *frame)
{
QTextDocumentLayout *documentLayout = qobject_cast<QTextDocumentLayout *>(document->documentLayout());
- QTextFrameFormat frameFormat = frame->format().toFrameFormat();
+ if (Q_UNLIKELY(!documentLayout))
+ return;
+ QTextFrameFormat frameFormat = frame->format().toFrameFormat();
QTextTable *table = qobject_cast<QTextTable *>(frame);
+
QRectF boundingRect = table == 0
? documentLayout->frameBoundingRect(frame)
: documentLayout->tableBoundingRect(table);
diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h
index 87235344e6..91ed6f4430 100644
--- a/src/quick/items/qquicktextnodeengine_p.h
+++ b/src/quick/items/qquicktextnodeengine_p.h
@@ -68,8 +68,15 @@ QT_BEGIN_NAMESPACE
// number of nodes, and join decorations in neighbouring items
class QQuickTextNodeEngine {
-
public:
+ enum Decoration {
+ NoDecoration = 0x0,
+ Underline = 0x1,
+ Overline = 0x2,
+ StrikeOut = 0x4,
+ Background = 0x8
+ };
+ Q_DECLARE_FLAGS(Decorations, Decoration)
enum SelectionState {
Unselected,
@@ -79,26 +86,26 @@ public:
struct BinaryTreeNode {
BinaryTreeNode()
- : selectionState(Unselected), clipNode(0), decorations(QQuickTextNode::NoDecoration)
+ : selectionState(Unselected), clipNode(0), decorations(Decoration::NoDecoration)
, ascent(0.0), leftChildIndex(-1), rightChildIndex(-1)
{
}
BinaryTreeNode(const QRectF &brect, const QImage &i, SelectionState selState, qreal a)
- : boundingRect(brect), selectionState(selState), clipNode(0), decorations(QQuickTextNode::NoDecoration)
+ : boundingRect(brect), selectionState(selState), clipNode(0), decorations(Decoration::NoDecoration)
, image(i), ascent(a), leftChildIndex(-1), rightChildIndex(-1)
{
}
BinaryTreeNode(const QGlyphRun &g, SelectionState selState, const QRectF &brect,
- const QQuickTextNode::Decorations &decs, const QColor &c, const QColor &bc,
+ const Decorations &decs, const QColor &c, const QColor &bc,
const QPointF &pos, qreal a);
QGlyphRun glyphRun;
QRectF boundingRect;
SelectionState selectionState;
QQuickDefaultClipNode *clipNode;
- QQuickTextNode::Decorations decorations;
+ Decorations decorations;
QColor color;
QColor backgroundColor;
QPointF position;
@@ -114,7 +121,7 @@ public:
{ insert(binaryTree, BinaryTreeNode(rect, image, selectionState, ascent)); }
static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
- QQuickTextNode::Decorations decorations, const QColor &textColor, const QColor &backgroundColor, const QPointF &position);
+ Decorations decorations, const QColor &textColor, const QColor &backgroundColor, const QPointF &position);
static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const BinaryTreeNode &binaryTreeNode);
static void inOrder(const QVarLengthArray<BinaryTreeNode, 16> &binaryTree, QVarLengthArray<int> *sortedIndexes, int currentIndex = 0);
};
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index 1101b88992..d79d8ba3cd 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -44,9 +44,6 @@
#include "qquickitem_p.h"
#include "qquickitemchangelistener_p.h"
-#include <private/qqmldebugconnector_p.h>
-#include <private/qquickprofiler_p.h>
-#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmlmemoryprofiler_p.h>
#include <QtQml/qqmlengine.h>
@@ -131,14 +128,15 @@ void QQuickViewPrivate::execute()
}
}
-void QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change,
+ const QRectF &diff)
{
Q_Q(QQuickView);
if (resizeItem == root && resizeMode == QQuickView::SizeViewToRootObject) {
// wait for both width and height to be changed
resizetimer.start(0,q);
}
- QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+ QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, diff);
}
/*!
@@ -266,8 +264,8 @@ void QQuickView::setContent(const QUrl& url, QQmlComponent *component, QObject*
d->component = component;
if (d->component && d->component->isError()) {
- QList<QQmlError> errorList = d->component->errors();
- foreach (const QQmlError &error, errorList) {
+ const QList<QQmlError> errorList = d->component->errors();
+ for (const QQmlError &error : errorList) {
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
<< error;
}
@@ -432,9 +430,14 @@ void QQuickViewPrivate::updateSize()
q->resize(newSize);
}
} else if (resizeMode == QQuickView::SizeRootObjectToView) {
- if (!qFuzzyCompare(q->width(), root->width()))
+ bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
+ bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
+
+ if (needToUpdateWidth && needToUpdateHeight)
+ root->setSize(QSizeF(q->width(), q->height()));
+ else if (needToUpdateWidth)
root->setWidth(q->width());
- if (!qFuzzyCompare(q->height(), root->height()))
+ else if (needToUpdateHeight)
root->setHeight(q->height());
}
}
@@ -472,8 +475,8 @@ void QQuickView::continueExecute()
disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)), this, SLOT(continueExecute()));
if (d->component->isError()) {
- QList<QQmlError> errorList = d->component->errors();
- foreach (const QQmlError &error, errorList) {
+ const QList<QQmlError> errorList = d->component->errors();
+ for (const QQmlError &error : errorList) {
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
<< error;
}
@@ -484,8 +487,8 @@ void QQuickView::continueExecute()
QObject *obj = d->component->create();
if (d->component->isError()) {
- QList<QQmlError> errorList = d->component->errors();
- foreach (const QQmlError &error, errorList) {
+ const QList<QQmlError> errorList = d->component->errors();
+ for (const QQmlError &error : errorList) {
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
<< error;
}
diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h
index 1bbff0de0e..c21468ef53 100644
--- a/src/quick/items/qquickview_p.h
+++ b/src/quick/items/qquickview_p.h
@@ -88,7 +88,7 @@ public:
~QQuickViewPrivate();
void execute();
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
void initResize();
void updateSize();
void setRootObject(QObject *);
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index b3ca563f16..834841333b 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -85,6 +85,7 @@ Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch")
Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target")
Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse")
Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target")
+Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace")
Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus")
Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty")
@@ -202,11 +203,6 @@ thus the first item that has focus will get it (assuming the scope doesn't alrea
have a scope focused item), and the other items will have their focus cleared.
*/
-QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
-: transformNode(0)
-{
-}
-
QQuickRootItem::QQuickRootItem()
{
}
@@ -292,7 +288,9 @@ void QQuickWindowPrivate::polishItems()
int recursionSafeguard = INT_MAX;
while (!itemsToPolish.isEmpty() && --recursionSafeguard > 0) {
QQuickItem *item = itemsToPolish.takeLast();
- QQuickItemPrivate::get(item)->polishScheduled = false;
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->polishScheduled = false;
+ itemPrivate->updatePolish();
item->updatePolish();
}
@@ -473,7 +471,6 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
QQuickWindowPrivate::QQuickWindowPrivate()
: contentItem(0)
, activeFocusItem(0)
- , mouseGrabberItem(0)
#ifndef QT_NO_CURSOR
, cursorItem(0)
#endif
@@ -481,6 +478,7 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, dragGrabber(0)
#endif
, touchMouseId(-1)
+ , touchMouseDevice(nullptr)
, touchMousePressTimestamp(0)
, dirtyItemList(0)
, devicePixelRatio(0)
@@ -488,7 +486,7 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, renderer(0)
, windowManager(0)
, renderControl(0)
- , touchRecursionGuard(0)
+ , pointerEventRecursionGuard(0)
, customRenderStage(0)
, clearColor(Qt::white)
, clearBeforeRendering(true)
@@ -624,8 +622,17 @@ bool QQuickWindowPrivate::checkIfDoubleClicked(ulong newPressEventTimestamp)
return doubleClicked;
}
-bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *event)
+bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEvent *pointerEvent)
{
+ Q_Q(QQuickWindow);
+ auto device = pointerEvent->device();
+
+ // FIXME: make this work for mouse events too and get rid of the asTouchEvent in here.
+ Q_ASSERT(pointerEvent->asPointerTouchEvent());
+ QTouchEvent *event = pointerEvent->asPointerTouchEvent()->touchEventForItem(item);
+ if (!event)
+ return false;
+
// For each point, check if it is accepted, if not, try the next point.
// Any of the fingers can become the mouse one.
// This can happen because a mouse area might not accept an event at some point but another.
@@ -639,65 +646,45 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
if (!item->contains(pos))
break;
- // Store the id already here and restore it to -1 if the event does not get
- // accepted. Cannot defer setting the new value because otherwise if the event
- // handler spins the event loop all subsequent moves and releases get lost.
- touchMouseId = p.id();
- itemForTouchPointId[touchMouseId] = item;
qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << item;
QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item, false));
// Send a single press and see if that's accepted
- if (!mouseGrabberItem)
- item->grabMouse();
- item->grabTouchPoints(QVector<int>() << touchMouseId);
-
QCoreApplication::sendEvent(item, mousePress.data());
event->setAccepted(mousePress->isAccepted());
- if (!mousePress->isAccepted()) {
- touchMouseId = -1;
- if (itemForTouchPointId.value(p.id()) == item) {
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "disassociated";
- itemForTouchPointId.remove(p.id());
+ if (mousePress->isAccepted()) {
+ touchMouseDevice = device;
+ touchMouseId = p.id();
+ if (!q->mouseGrabberItem())
+ item->grabMouse();
+ auto pointerEventPoint = pointerEvent->pointById(p.id());
+ pointerEventPoint->setGrabber(item);
+
+ if (checkIfDoubleClicked(event->timestamp())) {
+ QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item, false));
+ QCoreApplication::sendEvent(item, mouseDoubleClick.data());
+ event->setAccepted(mouseDoubleClick->isAccepted());
+ if (!mouseDoubleClick->isAccepted()) {
+ touchMouseId = -1;
+ touchMouseDevice = nullptr;
+ }
}
- if (mouseGrabberItem == item)
- item->ungrabMouse();
- }
-
- if (mousePress->isAccepted() && checkIfDoubleClicked(event->timestamp())) {
- QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item, false));
- QCoreApplication::sendEvent(item, mouseDoubleClick.data());
- event->setAccepted(mouseDoubleClick->isAccepted());
- if (mouseDoubleClick->isAccepted()) {
- touchMouseIdCandidates.clear();
- return true;
- } else {
- touchMouseId = -1;
- }
- }
- // The event was accepted, we are done.
- if (mousePress->isAccepted()) {
- touchMouseIdCandidates.clear();
return true;
}
- // The event was not accepted but touchMouseId was set.
- if (touchMouseId != -1)
- return false;
// try the next point
// Touch point was there before and moved
- } else if (p.id() == touchMouseId) {
+ } else if (touchMouseDevice == device && p.id() == touchMouseId) {
if (p.state() & Qt::TouchPointMoved) {
- if (mouseGrabberItem) {
+ if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) {
QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
event->setAccepted(me->isAccepted());
if (me->isAccepted()) {
qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << mouseGrabberItem;
- itemForTouchPointId[p.id()] = mouseGrabberItem; // N.B. the mouseGrabberItem may be different after returning from sendEvent()
- return true;
}
+ return event->isAccepted();
} else {
// no grabber, check if we care about mouse hover
// FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
@@ -709,10 +696,10 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
lastMousePosition = me->windowPos();
bool accepted = me->isAccepted();
- bool delivered = deliverHoverEvent(contentItem, me->windowPos(), last, me->modifiers(), accepted);
+ bool delivered = deliverHoverEvent(contentItem, me->windowPos(), last, me->modifiers(), me->timestamp(), accepted);
if (!delivered) {
//take care of any exits
- accepted = clearHover();
+ accepted = clearHover(me->timestamp());
}
me->setAccepted(accepted);
break;
@@ -720,7 +707,8 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
} else if (p.state() & Qt::TouchPointReleased) {
// currently handled point was released
touchMouseId = -1;
- if (mouseGrabberItem) {
+ touchMouseDevice = nullptr;
+ if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) {
QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
@@ -732,8 +720,8 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
Qt::NoButton, Qt::NoButton, event->modifiers());
QCoreApplication::sendEvent(item, &mm);
}
- if (mouseGrabberItem) // might have ungrabbed due to event
- mouseGrabberItem->ungrabMouse();
+ if (q->mouseGrabberItem()) // might have ungrabbed due to event
+ q->mouseGrabberItem()->ungrabMouse();
return me->isAccepted();
}
}
@@ -746,40 +734,83 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
{
Q_Q(QQuickWindow);
- if (mouseGrabberItem == grabber)
+ if (q->mouseGrabberItem() == grabber)
return;
- qCDebug(DBG_MOUSE_TARGET) << "grabber" << mouseGrabberItem << "->" << grabber;
- QQuickItem *oldGrabber = mouseGrabberItem;
- mouseGrabberItem = grabber;
+ qCDebug(DBG_MOUSE_TARGET) << "grabber" << q->mouseGrabberItem() << "->" << grabber;
+ QQuickItem *oldGrabber = q->mouseGrabberItem();
- if (touchMouseId != -1) {
+ QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent();
+ Q_ASSERT(event->pointCount() == 1);
+ event->point(0)->setGrabber(grabber);
+
+ if (grabber && touchMouseId != -1 && touchMouseDevice) {
// update the touch item for mouse touch id to the new grabber
- itemForTouchPointId.remove(touchMouseId);
- if (grabber) {
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << touchMouseId << "->" << mouseGrabberItem;
- itemForTouchPointId[touchMouseId] = grabber;
- }
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << touchMouseId << "->" << q->mouseGrabberItem();
+ auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId);
+ if (point)
+ point->setGrabber(grabber);
}
if (oldGrabber) {
- QEvent ev(QEvent::UngrabMouse);
- q->sendEvent(oldGrabber, &ev);
+ QEvent e(QEvent::UngrabMouse);
+ QSet<QQuickItem *> hasFiltered;
+ if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered))
+ oldGrabber->mouseUngrabEvent();
}
}
-void QQuickWindowPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
+void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int> &ids)
{
- QMatrix4x4 transformMatrix(transform);
- for (int i=0; i<touchPoints.count(); i++) {
- QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
- touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
- touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
- touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
- touchPoint.setVelocity(transformMatrix.mapVector(touchPoint.velocity()).toVector2D());
+ Q_Q(QQuickWindow);
+ QSet<QQuickItem*> ungrab;
+ for (int i = 0; i < ids.count(); ++i) {
+ // FIXME: deprecate this function, we need a device
+ const auto touchDevices = QQuickPointerDevice::touchDevices();
+ for (auto device : touchDevices) {
+ auto point = device->pointerEvent()->pointById(ids.at(i));
+ if (!point)
+ continue;
+ QQuickItem *oldGrabber = point->grabber();
+ if (oldGrabber == grabber)
+ continue;
+
+ point->setGrabber(grabber);
+ if (oldGrabber)
+ ungrab.insert(oldGrabber);
+ }
+
+ QQuickItem *mouseGrabberItem = q->mouseGrabberItem();
+ if (touchMouseId == ids.at(i) && mouseGrabberItem && mouseGrabberItem != grabber) {
+ qCDebug(DBG_MOUSE_TARGET) << "grabTouchPoints: grabber" << mouseGrabberItem << "-> null";
+ setMouseGrabber(nullptr);
+ }
}
+ for (QQuickItem *oldGrabber : qAsConst(ungrab))
+ oldGrabber->touchUngrabEvent();
}
+void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch)
+{
+ Q_Q(QQuickWindow);
+ if (Q_LIKELY(touch)) {
+ const auto touchDevices = QQuickPointerDevice::touchDevices();
+ for (auto device : touchDevices) {
+ auto pointerEvent = device->pointerEvent();
+ for (int i = 0; i < pointerEvent->pointCount(); ++i) {
+ if (pointerEvent->point(i)->grabber() == grabber) {
+ pointerEvent->point(i)->setGrabber(nullptr);
+ // FIXME send ungrab event only once
+ grabber->touchUngrabEvent();
+ }
+ }
+ }
+ }
+ if (Q_LIKELY(mouse) && q->mouseGrabberItem() == grabber) {
+ qCDebug(DBG_MOUSE_TARGET) << "removeGrabber" << q->mouseGrabberItem() << "-> null";
+ setMouseGrabber(nullptr);
+ }
+}
/*!
Translates the data in \a touchEvent to this window. This method leaves the item local positions in
@@ -791,16 +822,9 @@ void QQuickWindowPrivate::translateTouchEvent(QTouchEvent *touchEvent)
for (int i = 0; i < touchPoints.count(); ++i) {
QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
- touchPoint.setScreenRect(touchPoint.sceneRect());
- touchPoint.setStartScreenPos(touchPoint.startScenePos());
- touchPoint.setLastScreenPos(touchPoint.lastScenePos());
-
touchPoint.setSceneRect(touchPoint.rect());
touchPoint.setStartScenePos(touchPoint.startPos());
touchPoint.setLastScenePos(touchPoint.lastPos());
-
- if (i == 0)
- lastMousePosition = touchPoint.pos().toPoint();
}
touchEvent->setTouchPoints(touchPoints);
}
@@ -834,8 +858,10 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ QQuickItem *oldActiveFocusItem = 0;
QQuickItem *currentActiveFocusItem = activeFocusItem;
QQuickItem *newActiveFocusItem = 0;
+ bool sendFocusIn = false;
lastFocusReason = reason;
@@ -843,7 +869,6 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
// Does this change the active focus?
if (item == contentItem || scopePrivate->activeFocus) {
- QQuickItem *oldActiveFocusItem = 0;
oldActiveFocusItem = activeFocusItem;
if (item->isEnabled()) {
newActiveFocusItem = item;
@@ -862,8 +887,6 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
#endif
activeFocusItem = 0;
- QFocusEvent event(QEvent::FocusOut, reason);
- q->sendEvent(oldActiveFocusItem, &event);
QQuickItem *afi = oldActiveFocusItem;
while (afi && afi != scope) {
@@ -908,9 +931,20 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
afi = afi->parentItem();
}
updateFocusItemTransform();
+ sendFocusIn = true;
+ }
+ // Now that all the state is changed, emit signals & events
+ // We must do this last, as this process may result in further changes to focus.
+ if (oldActiveFocusItem) {
+ QFocusEvent event(QEvent::FocusOut, reason);
+ QCoreApplication::sendEvent(oldActiveFocusItem, &event);
+ }
+
+ // Make sure that the FocusOut didn't result in another focus change.
+ if (sendFocusIn && activeFocusItem == newActiveFocusItem) {
QFocusEvent event(QEvent::FocusIn, reason);
- q->sendEvent(newActiveFocusItem, &event);
+ QCoreApplication::sendEvent(newActiveFocusItem, &event);
}
if (activeFocusItem != currentActiveFocusItem)
@@ -961,9 +995,6 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
activeFocusItem = 0;
if (oldActiveFocusItem) {
- QFocusEvent event(QEvent::FocusOut, reason);
- q->sendEvent(oldActiveFocusItem, &event);
-
QQuickItem *afi = oldActiveFocusItem;
while (afi && afi != scope) {
if (QQuickItemPrivate::get(afi)->activeFocus) {
@@ -993,9 +1024,20 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
Q_ASSERT(newActiveFocusItem == scope);
activeFocusItem = scope;
updateFocusItemTransform();
+ }
+
+ // Now that all the state is changed, emit signals & events
+ // We must do this last, as this process may result in further changes to
+ // focus.
+ if (oldActiveFocusItem) {
+ QFocusEvent event(QEvent::FocusOut, reason);
+ QCoreApplication::sendEvent(oldActiveFocusItem, &event);
+ }
+ // Make sure that the FocusOut didn't result in another focus change.
+ if (newActiveFocusItem && activeFocusItem == newActiveFocusItem) {
QFocusEvent event(QEvent::FocusIn, reason);
- q->sendEvent(newActiveFocusItem, &event);
+ QCoreApplication::sendEvent(newActiveFocusItem, &event);
}
if (activeFocusItem != currentActiveFocusItem)
@@ -1424,13 +1466,13 @@ QObject *QQuickWindow::focusObject() const
*/
QQuickItem *QQuickWindow::mouseGrabberItem() const
{
- Q_D(const QQuickWindow);
-
- return d->mouseGrabberItem;
+ QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent();
+ Q_ASSERT(event->pointCount());
+ return event->point(0)->grabber();
}
-bool QQuickWindowPrivate::clearHover()
+bool QQuickWindowPrivate::clearHover(ulong timestamp)
{
Q_Q(QQuickWindow);
if (hoverItems.isEmpty())
@@ -1439,8 +1481,8 @@ bool QQuickWindowPrivate::clearHover()
QPointF pos = q->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
bool accepted = false;
- foreach (QQuickItem* item, hoverItems)
- accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
+ for (QQuickItem* item : qAsConst(hoverItems))
+ accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), timestamp, true) || accepted;
hoverItems.clear();
return accepted;
}
@@ -1456,8 +1498,7 @@ bool QQuickWindow::event(QEvent *e)
case QEvent::TouchUpdate:
case QEvent::TouchEnd: {
QTouchEvent *touch = static_cast<QTouchEvent*>(e);
- d->translateTouchEvent(touch);
- d->deliverTouchEvent(touch);
+ d->handleTouchEvent(touch);
if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
// we consume all touch events ourselves to avoid duplicate
// mouse delivery by QtGui mouse synthesis
@@ -1470,9 +1511,18 @@ bool QQuickWindow::event(QEvent *e)
// return in order to avoid the QWindow::event below
return d->deliverTouchCancelEvent(static_cast<QTouchEvent*>(e));
break;
+ case QEvent::Enter: {
+ QEnterEvent *enter = static_cast<QEnterEvent*>(e);
+ bool accepted = enter->isAccepted();
+ bool delivered = d->deliverHoverEvent(d->contentItem, enter->windowPos(), d->lastMousePosition,
+ QGuiApplication::keyboardModifiers(), 0L, accepted);
+ enter->setAccepted(accepted);
+ return delivered;
+ }
+ break;
case QEvent::Leave:
d->clearHover();
- d->lastMousePosition = QPoint();
+ d->lastMousePosition = QPointF();
break;
#ifndef QT_NO_DRAGANDDROP
case QEvent::DragEnter:
@@ -1498,8 +1548,8 @@ bool QQuickWindow::event(QEvent *e)
if (d->activeFocusItem)
qGuiApp->inputMethod()->commit();
#endif
- if (d->mouseGrabberItem)
- d->mouseGrabberItem->ungrabMouse();
+ if (mouseGrabberItem())
+ mouseGrabberItem()->ungrabMouse();
break;
case QEvent::UpdateRequest: {
if (d->windowManager)
@@ -1513,7 +1563,7 @@ bool QQuickWindow::event(QEvent *e)
#endif
case QEvent::ShortcutOverride:
if (d->activeFocusItem)
- sendEvent(d->activeFocusItem, static_cast<QKeyEvent *>(e));
+ QCoreApplication::sendEvent(d->activeFocusItem, e);
return true;
default:
break;
@@ -1565,148 +1615,56 @@ QMouseEvent *QQuickWindowPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *t
return me;
}
-bool QQuickWindowPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
+void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent)
{
Q_Q(QQuickWindow);
-
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(event->windowPos());
- if (!item->contains(p))
- return false;
- }
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
- continue;
- if (deliverInitialMousePressEvent(child, event))
- return true;
- }
-
- if (itemPrivate->acceptedMouseButtons() & event->button()) {
- QPointF localPos = item->mapFromScene(event->windowPos());
- if (item->contains(localPos)) {
- QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
- me->accept();
- item->grabMouse();
- q->sendEvent(item, me.data());
- event->setAccepted(me->isAccepted());
- if (me->isAccepted())
- return true;
- if (mouseGrabberItem)
- mouseGrabberItem->ungrabMouse();
+ auto point = pointerEvent->point(0);
+ lastMousePosition = point->scenePos();
+ QQuickItem *grabber = point->grabber();
+ if (grabber) {
+ // if the update consists of changing button state, then don't accept it
+ // unless the button is one in which the item is interested
+ if (pointerEvent->button() != Qt::NoButton
+ && grabber->acceptedMouseButtons()
+ && !(grabber->acceptedMouseButtons() & pointerEvent->button())) {
+ pointerEvent->setAccepted(false);
+ return;
}
- }
-
- return false;
-}
-
-bool QQuickWindowPrivate::deliverMouseEvent(QMouseEvent *event)
-{
- Q_Q(QQuickWindow);
-
- lastMousePosition = event->windowPos();
- if (!mouseGrabberItem &&
- event->type() == QEvent::MouseButtonPress &&
- (event->buttons() & event->button()) == event->buttons()) {
- if (deliverInitialMousePressEvent(contentItem, event))
- event->accept();
- else
- event->ignore();
- return event->isAccepted();
- }
-
- if (mouseGrabberItem) {
- QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos());
- QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
+ // send update
+ QPointF localPos = grabber->mapFromScene(lastMousePosition);
+ auto me = pointerEvent->asMouseEvent(localPos);
me->accept();
- q->sendEvent(mouseGrabberItem, me.data());
- event->setAccepted(me->isAccepted());
- if (me->isAccepted())
- return true;
- }
-
- return false;
-}
-
-/*! \reimp */
-void QQuickWindow::mousePressEvent(QMouseEvent *event)
-{
- Q_D(QQuickWindow);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(),
- event->buttons());
-
- if (event->source() == Qt::MouseEventSynthesizedBySystem) {
- event->accept();
- return;
- }
-
- qCDebug(DBG_MOUSE) << "QQuickWindow::mousePressEvent()" << event->localPos() << event->button() << event->buttons();
- d->deliverMouseEvent(event);
-}
-
-/*! \reimp */
-void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
-{
- Q_D(QQuickWindow);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
- event->buttons());
-
- if (event->source() == Qt::MouseEventSynthesizedBySystem) {
- event->accept();
- return;
- }
-
- qCDebug(DBG_MOUSE) << "QQuickWindow::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons() << "grabber:" << d->mouseGrabberItem;
-
- if (!d->mouseGrabberItem) {
- QWindow::mouseReleaseEvent(event);
- return;
- }
-
- d->deliverMouseEvent(event);
- if (d->mouseGrabberItem && !event->buttons())
- d->mouseGrabberItem->ungrabMouse();
-}
+ q->sendEvent(grabber, me);
+ point->setAccepted(me->isAccepted());
-/*! \reimp */
-void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
-{
- Q_D(QQuickWindow);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
- event->button(), event->buttons());
-
- if (event->source() == Qt::MouseEventSynthesizedBySystem) {
- event->accept();
- return;
- }
-
- qCDebug(DBG_MOUSE) << "QQuickWindow::mouseDoubleClickEvent()" << event->localPos() << event->button() << event->buttons();
+ // release event, make sure to ungrab if there still is a grabber
+ if (me->type() == QEvent::MouseButtonRelease && !me->buttons() && q->mouseGrabberItem())
+ q->mouseGrabberItem()->ungrabMouse();
+ } else {
+ // send initial press
+ bool delivered = false;
+ if (pointerEvent->isPressEvent()) {
+ QSet<QQuickItem*> hasFiltered;
+ delivered = deliverPressEvent(pointerEvent, &hasFiltered);
+ }
- if (!d->mouseGrabberItem && (event->buttons() & event->button()) == event->buttons()) {
- if (d->deliverInitialMousePressEvent(d->contentItem, event))
- event->accept();
- else
- event->ignore();
- return;
+ if (!delivered)
+ // make sure not to accept unhandled events
+ pointerEvent->setAccepted(false);
}
-
- d->deliverMouseEvent(event);
}
bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
const QPointF &scenePos, const QPointF &lastScenePos,
- Qt::KeyboardModifiers modifiers, bool accepted)
+ Qt::KeyboardModifiers modifiers, ulong timestamp,
+ bool accepted)
{
- Q_Q(QQuickWindow);
const QTransform transform = QQuickItemPrivate::get(item)->windowToItemTransform();
//create copy of event
QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
+ hoverEvent.setTimestamp(timestamp);
hoverEvent.setAccepted(accepted);
QSet<QQuickItem *> hasFiltered;
@@ -1714,50 +1672,13 @@ bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
return true;
}
- q->sendEvent(item, &hoverEvent);
+ QCoreApplication::sendEvent(item, &hoverEvent);
return hoverEvent.isAccepted();
}
-/*! \reimp */
-void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
-{
- Q_D(QQuickWindow);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
- event->localPos().x(), event->localPos().y());
-
- if (event->source() == Qt::MouseEventSynthesizedBySystem) {
- event->accept();
- return;
- }
-
- qCDebug(DBG_MOUSE) << "QQuickWindow::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
-
-#ifndef QT_NO_CURSOR
- d->updateCursor(event->windowPos());
-#endif
-
- if (!d->mouseGrabberItem) {
- if (d->lastMousePosition.isNull())
- d->lastMousePosition = event->windowPos();
- QPointF last = d->lastMousePosition;
- d->lastMousePosition = event->windowPos();
-
- bool accepted = event->isAccepted();
- bool delivered = d->deliverHoverEvent(d->contentItem, event->windowPos(), last, event->modifiers(), accepted);
- if (!delivered) {
- //take care of any exits
- accepted = d->clearHover();
- }
- event->setAccepted(accepted);
- return;
- }
-
- d->deliverMouseEvent(event);
-}
-
bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
- Qt::KeyboardModifiers modifiers, bool &accepted)
+ Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted)
{
Q_Q(QQuickWindow);
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
@@ -1768,13 +1689,14 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
return false;
}
- if (itemPrivate->hasHoverInChild) {
+ qCDebug(DBG_HOVER_TRACE) << q << item << scenePos << lastScenePos << "subtreeHoverEnabled" << itemPrivate->subtreeHoverEnabled;
+ if (itemPrivate->subtreeHoverEnabled) {
QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
for (int ii = children.count() - 1; ii >= 0; --ii) {
QQuickItem *child = children.at(ii);
if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
continue;
- if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
+ if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, timestamp, accepted))
return true;
}
}
@@ -1782,9 +1704,9 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
if (itemPrivate->hoverEnabled) {
QPointF p = item->mapFromScene(scenePos);
if (item->contains(p)) {
- if (!hoverItems.isEmpty() && hoverItems[0] == item) {
+ if (!hoverItems.isEmpty() && hoverItems.at(0) == item) {
//move
- accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
+ accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp, accepted);
} else {
QList<QQuickItem *> itemsToHover;
QQuickItem* parent = item;
@@ -1793,24 +1715,24 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
itemsToHover << parent;
// Leaving from previous hovered items until we reach the item or one of its ancestors.
- while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
+ while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems.at(0))) {
QQuickItem *hoverLeaveItem = hoverItems.takeFirst();
- sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, accepted);
+ sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, timestamp, accepted);
}
- if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
+ if (!hoverItems.isEmpty() && hoverItems.at(0) == item) {//Not entering a new Item
// ### Shouldn't we send moves for the parent items as well?
- accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
+ accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp, accepted);
} else {
// Enter items that are not entered yet.
int startIdx = -1;
if (!hoverItems.isEmpty())
- startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
+ startIdx = itemsToHover.indexOf(hoverItems.at(0)) - 1;
if (startIdx == -1)
startIdx = itemsToHover.count() - 1;
for (int i = startIdx; i >= 0; i--) {
- QQuickItem *itemToHover = itemsToHover[i];
+ QQuickItem *itemToHover = itemsToHover.at(i);
QQuickItemPrivate *itemToHoverPrivate = QQuickItemPrivate::get(itemToHover);
// The item may be about to be deleted or reparented to another window
// due to another hover event delivered in this function. If that is the
@@ -1819,7 +1741,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
// itemToHoverPrivate->window here prevents that case.
if (itemToHoverPrivate->window == q && itemToHoverPrivate->hoverEnabled) {
hoverItems.prepend(itemToHover);
- sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
+ sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, timestamp, accepted);
}
}
}
@@ -1834,7 +1756,6 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
#ifndef QT_NO_WHEELEVENT
bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
{
- Q_Q(QQuickWindow);
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
@@ -1858,7 +1779,7 @@ bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event
QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(),
event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted());
wheel.accept();
- q->sendEvent(item, &wheel);
+ QCoreApplication::sendEvent(item, &wheel);
if (wheel.isAccepted()) {
event->accept();
return true;
@@ -1925,20 +1846,22 @@ bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
{
qCDebug(DBG_TOUCH) << event;
Q_Q(QQuickWindow);
+
// A TouchCancel event will typically not contain any points.
// Deliver it to all items that have active touches.
- QSet<QQuickItem *> cancelDelivered;
- foreach (QQuickItem *item, itemForTouchPointId) {
- if (cancelDelivered.contains(item))
- continue;
- cancelDelivered.insert(item);
- q->sendEvent(item, event);
+ QQuickPointerEvent *pointerEvent = QQuickPointerDevice::touchDevice(event->device())->pointerEvent();
+ QVector<QQuickItem *> grabbers = pointerEvent->grabbers();
+
+ for (QQuickItem *grabber: qAsConst(grabbers)) {
+ q->sendEvent(grabber, event);
}
touchMouseId = -1;
- if (mouseGrabberItem)
- mouseGrabberItem->ungrabMouse();
+ touchMouseDevice = nullptr;
+ if (q->mouseGrabberItem())
+ q->mouseGrabberItem()->ungrabMouse();
+
// The next touch event can only be a TouchBegin so clean up.
- itemForTouchPointId.clear();
+ pointerEvent->clearGrabbers();
return true;
}
@@ -1948,88 +1871,185 @@ void QQuickWindowPrivate::deliverDelayedTouchEvent()
// Set delayedTouch to 0 before delivery to avoid redelivery in case of
// event loop recursions (e.g if it the touch starts a dnd session).
QScopedPointer<QTouchEvent> e(delayedTouch.take());
- reallyDeliverTouchEvent(e.data());
+ deliverPointerEvent(pointerEventInstance(e.data()));
}
-static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet("QML_NO_TOUCH_COMPRESSION");
+bool QQuickWindowPrivate::compressTouchEvent(QTouchEvent *event)
+{
+ Q_Q(QQuickWindow);
+ Qt::TouchPointStates states = event->touchPointStates();
+ if (((states & (Qt::TouchPointMoved | Qt::TouchPointStationary)) == 0)
+ || ((states & (Qt::TouchPointPressed | Qt::TouchPointReleased)) != 0)) {
+ // we can only compress something that isn't a press or release
+ return false;
+ }
+
+ if (!delayedTouch) {
+ delayedTouch.reset(new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints()));
+ delayedTouch->setTimestamp(event->timestamp());
+ if (renderControl)
+ QQuickRenderControlPrivate::get(renderControl)->maybeUpdate();
+ else if (windowManager)
+ windowManager->maybeUpdate(q);
+ return true;
+ }
+
+ // check if this looks like the last touch event
+ if (delayedTouch->type() == event->type() &&
+ delayedTouch->device() == event->device() &&
+ delayedTouch->modifiers() == event->modifiers() &&
+ delayedTouch->touchPoints().count() == event->touchPoints().count())
+ {
+ // possible match.. is it really the same?
+ bool mismatch = false;
+
+ QList<QTouchEvent::TouchPoint> tpts = event->touchPoints();
+ Qt::TouchPointStates states;
+ for (int i = 0; i < event->touchPoints().count(); ++i) {
+ const QTouchEvent::TouchPoint &tp = tpts.at(i);
+ const QTouchEvent::TouchPoint &tpDelayed = delayedTouch->touchPoints().at(i);
+ if (tp.id() != tpDelayed.id()) {
+ mismatch = true;
+ break;
+ }
+
+ if (tpDelayed.state() == Qt::TouchPointMoved && tp.state() == Qt::TouchPointStationary)
+ tpts[i].setState(Qt::TouchPointMoved);
+ tpts[i].setLastPos(tpDelayed.lastPos());
+ tpts[i].setLastScenePos(tpDelayed.lastScenePos());
+ tpts[i].setLastScreenPos(tpDelayed.lastScreenPos());
+ tpts[i].setLastNormalizedPos(tpDelayed.lastNormalizedPos());
+
+ states |= tpts.at(i).state();
+ }
+
+ // matching touch event? then merge the new event into the old one
+ if (!mismatch) {
+ delayedTouch->setTouchPoints(tpts);
+ delayedTouch->setTimestamp(event->timestamp());
+ return true;
+ }
+ }
+
+ // merging wasn't possible, so deliver the delayed event first, and then delay this one
+ deliverDelayedTouchEvent();
+ delayedTouch.reset(new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints()));
+ delayedTouch->setTimestamp(event->timestamp());
+ return true;
+}
-// check what kind of touch we have (begin/update) and
-// call deliverTouchPoints to actually dispatch the points
-void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
+// entry point for touch event delivery:
+// - translate the event to window coordinates
+// - compress the event instead of delivering it if applicable
+// - call deliverTouchPoints to actually dispatch the points
+void QQuickWindowPrivate::handleTouchEvent(QTouchEvent *event)
{
+ translateTouchEvent(event);
+ if (event->touchPoints().size())
+ lastMousePosition = event->touchPoints().at(0).pos();
+
qCDebug(DBG_TOUCH) << event;
+
+ static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet("QML_NO_TOUCH_COMPRESSION");
+
+ if (qquickwindow_no_touch_compression || pointerEventRecursionGuard) {
+ deliverPointerEvent(pointerEventInstance(event));
+ return;
+ }
+
+ if (!compressTouchEvent(event)) {
+ if (delayedTouch)
+ deliverDelayedTouchEvent();
+ deliverPointerEvent(pointerEventInstance(event));
+ }
+}
+
+/*! \reimp */
+void QQuickWindow::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickWindow);
+ d->handleMouseEvent(event);
+}
+/*! \reimp */
+void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickWindow);
+ d->handleMouseEvent(event);
+}
+/*! \reimp */
+void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QQuickWindow);
+ d->handleMouseEvent(event);
+}
+/*! \reimp */
+void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickWindow);
+ d->handleMouseEvent(event);
+}
+
+void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
+{
Q_Q(QQuickWindow);
- if (qquickwindow_no_touch_compression || touchRecursionGuard) {
- reallyDeliverTouchEvent(event);
+ if (event->source() == Qt::MouseEventSynthesizedBySystem) {
+ event->accept();
return;
}
+ qCDebug(DBG_MOUSE) << "QQuickWindow::handleMouseEvent()" << event->type() << event->localPos() << event->button() << event->buttons();
- Qt::TouchPointStates states = event->touchPointStates();
- if (((states & (Qt::TouchPointMoved | Qt::TouchPointStationary)) != 0)
- && ((states & (Qt::TouchPointPressed | Qt::TouchPointReleased)) == 0)) {
- // we can only compress something that isn't a press or release
- if (!delayedTouch) {
- delayedTouch.reset(new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints()));
- delayedTouch->setTimestamp(event->timestamp());
- if (renderControl)
- QQuickRenderControlPrivate::get(renderControl)->maybeUpdate();
- else if (windowManager)
- windowManager->maybeUpdate(q);
- return;
- } else {
- // check if this looks like the last touch event
- if (delayedTouch->type() == event->type() &&
- delayedTouch->device() == event->device() &&
- delayedTouch->modifiers() == event->modifiers() &&
- delayedTouch->touchPoints().count() == event->touchPoints().count())
- {
- // possible match.. is it really the same?
- bool mismatch = false;
-
- QList<QTouchEvent::TouchPoint> tpts = event->touchPoints();
- Qt::TouchPointStates states;
- for (int i = 0; i < event->touchPoints().count(); ++i) {
- const QTouchEvent::TouchPoint &tp = tpts.at(i);
- const QTouchEvent::TouchPoint &tpDelayed = delayedTouch->touchPoints().at(i);
- if (tp.id() != tpDelayed.id()) {
- mismatch = true;
- break;
- }
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(),
+ event->buttons());
+ deliverPointerEvent(pointerEventInstance(event));
+ break;
+ case QEvent::MouseButtonRelease:
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
+ event->buttons());
+ deliverPointerEvent(pointerEventInstance(event));
+ break;
+ case QEvent::MouseButtonDblClick:
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
+ event->button(), event->buttons());
+ deliverPointerEvent(pointerEventInstance(event));
+ break;
+ case QEvent::MouseMove:
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
+ event->localPos().x(), event->localPos().y());
- if (tpDelayed.state() == Qt::TouchPointMoved && tp.state() == Qt::TouchPointStationary)
- tpts[i].setState(Qt::TouchPointMoved);
- tpts[i].setLastPos(tpDelayed.lastPos());
- tpts[i].setLastScenePos(tpDelayed.lastScenePos());
- tpts[i].setLastScreenPos(tpDelayed.lastScreenPos());
- tpts[i].setLastNormalizedPos(tpDelayed.lastNormalizedPos());
+ qCDebug(DBG_HOVER_TRACE) << this;
- states |= tpts.at(i).state();
- }
+ #ifndef QT_NO_CURSOR
+ updateCursor(event->windowPos());
+ #endif
- // matching touch event? then merge the new event into the old one
- if (!mismatch) {
- delayedTouch->setTouchPoints(tpts);
- delayedTouch->setTimestamp(event->timestamp());
- return;
- }
- }
+ if (!q->mouseGrabberItem()) {
+ QPointF last = lastMousePosition.isNull() ? event->windowPos() : lastMousePosition;
+ lastMousePosition = event->windowPos();
- // merging wasn't possible, so deliver the delayed event first, and then delay this one
- deliverDelayedTouchEvent();
- delayedTouch.reset(new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints()));
- delayedTouch->setTimestamp(event->timestamp());
+ bool accepted = event->isAccepted();
+ bool delivered = deliverHoverEvent(contentItem, event->windowPos(), last, event->modifiers(), event->timestamp(), accepted);
+ if (!delivered) {
+ //take care of any exits
+ accepted = clearHover(event->timestamp());
+ }
+ event->setAccepted(accepted);
return;
}
- } else {
- if (delayedTouch)
- deliverDelayedTouchEvent();
- reallyDeliverTouchEvent(event);
+ deliverPointerEvent(pointerEventInstance(event));
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
}
}
void QQuickWindowPrivate::flushFrameSynchronousEvents()
{
+ Q_Q(QQuickWindow);
+
if (delayedTouch) {
deliverDelayedTouchEvent();
@@ -2044,175 +2064,223 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents()
// For instance, during animation (including the case of a ListView
// whose delegates contain MouseAreas), a MouseArea needs to know
// whether it has moved into a position where it is now under the cursor.
- if (!mouseGrabberItem && !lastMousePosition.isNull()) {
+ if (!q->mouseGrabberItem() && !lastMousePosition.isNull()) {
bool accepted = false;
- bool delivered = deliverHoverEvent(contentItem, lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), accepted);
+ bool delivered = deliverHoverEvent(contentItem, lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0, accepted);
if (!delivered)
clearHover(); // take care of any exits
}
}
-void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event)
-{
- qCDebug(DBG_TOUCH) << " - delivering" << event;
+/*!
+ \internal
+ Returns a QQuickPointerEvent instance suitable for wrapping and delivering \a event.
- // If users spin the eventloop as a result of touch delivery, we disable
- // touch compression and send events directly. This is because we consider
- // the usecase a bit evil, but we at least don't want to lose events.
- ++touchRecursionGuard;
-
- // List of all items that received an event before
- // When we have TouchBegin this is and will stay empty
- QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
-
- // Figure out who accepted a touch point last and put it in updatedPoints
- // Add additional item to newPoints
- const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
- QList<QTouchEvent::TouchPoint> newPoints;
- for (int i=0; i<touchPoints.count(); i++) {
- const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
- if (touchPoint.state() == Qt::TouchPointPressed) {
- newPoints << touchPoint;
- } else {
- // TouchPointStationary is relevant only to items which
- // are also receiving touch points with some other state.
- // But we have not yet decided which points go to which item,
- // so for now we must include all non-new points in updatedPoints.
- if (itemForTouchPointId.contains(touchPoint.id())) {
- QQuickItem *item = itemForTouchPointId.value(touchPoint.id());
- if (item)
- updatedPoints[item].append(touchPoint);
- }
- }
+ There is a unique instance per QQuickPointerDevice, which is determined
+ from \a event's device.
+*/
+QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) const
+{
+ QQuickPointerDevice *dev = nullptr;
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ dev = QQuickPointerDevice::genericMouseDevice();
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ case QEvent::TouchCancel:
+ dev = QQuickPointerDevice::touchDevice(static_cast<QTouchEvent *>(event)->device());
+ break;
+ // TODO tablet event types
+ default:
+ break;
}
+ Q_ASSERT(dev);
+ return dev->pointerEvent()->reset(event);
+}
- // Deliver the event, but only if there is at least one new point
- // or some item accepted a point and should receive an update
- if (newPoints.count() > 0 || updatedPoints.count() > 0) {
- QSet<int> acceptedNewPoints;
- QSet<QQuickItem *> hasFiltered;
- event->setAccepted(deliverTouchPoints(contentItem, event, newPoints, &acceptedNewPoints, &updatedPoints, &hasFiltered));
- } else
- event->ignore();
+void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
+{
+ // If users spin the eventloop as a result of event delivery, we disable
+ // event compression and send events directly. This is because we consider
+ // the usecase a bit evil, but we at least don't want to lose events.
+ ++pointerEventRecursionGuard;
- // Remove released points from itemForTouchPointId
- if (event->touchPointStates() & Qt::TouchPointReleased) {
- for (int i=0; i<touchPoints.count(); i++) {
- if (touchPoints[i].state() == Qt::TouchPointReleased) {
- qCDebug(DBG_TOUCH_TARGET) << "TP" << touchPoints[i].id() << "released";
- itemForTouchPointId.remove(touchPoints[i].id());
- if (touchPoints[i].id() == touchMouseId)
- touchMouseId = -1;
- touchMouseIdCandidates.remove(touchPoints[i].id());
- }
- }
+ if (event->asPointerMouseEvent()) {
+ deliverMouseEvent(event->asPointerMouseEvent());
+ } else if (event->asPointerTouchEvent()) {
+ deliverTouchEvent(event->asPointerTouchEvent());
+ } else {
+ Q_ASSERT(false);
}
- if (event->type() == QEvent::TouchEnd) {
- if (!itemForTouchPointId.isEmpty()) {
- qWarning() << "No release received for" << itemForTouchPointId.size()
- << "touch points over" << itemForTouchPointId.begin().value()
- << "on touch end.";
- itemForTouchPointId.clear();
- }
- }
+ event->reset(nullptr);
- --touchRecursionGuard;
+ --pointerEventRecursionGuard;
}
-// This function recurses and sends the events to the individual items
-bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints,
- QSet<int> *acceptedNewPoints, QHash<QQuickItem *,
- QList<QTouchEvent::TouchPoint> > *updatedPoints, QSet<QQuickItem *> *hasFiltered)
+// check if item or any of its child items contain the point
+// FIXME: should this be iterative instead of recursive?
+QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, const QPointF &scenePos, bool checkMouseButtons) const
{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
+ QVector<QQuickItem *> targets;
+ auto itemPrivate = QQuickItemPrivate::get(item);
+ QPointF itemPos = item->mapFromScene(scenePos);
+ // if the item clips, we can potentially return early
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- for (int i=0; i<newPoints.count(); i++) {
- QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (!item->contains(p))
- return false;
- }
+ if (!item->contains(itemPos))
+ return targets;
}
- // Check if our children want the event (or parts of it)
- // This is the only point where touch event delivery recurses!
+ // recurse for children
QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
for (int ii = children.count() - 1; ii >= 0; --ii) {
QQuickItem *child = children.at(ii);
- if (!child->isEnabled() || !child->isVisible() || QQuickItemPrivate::get(child)->culled)
+ auto childPrivate = QQuickItemPrivate::get(child);
+ if (!child->isVisible() || !child->isEnabled() || childPrivate->culled)
continue;
- if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints, hasFiltered))
- return true;
+ targets << pointerTargets(child, scenePos, false);
}
- // None of the children accepted the event, so check the given item itself.
- // First, construct matchingPoints as a list of TouchPoints which the
- // given item might be interested in. Any newly-pressed point which is
- // inside the item's bounds will be interesting, and also any updated point
- // which was already accepted by that item when it was first pressed.
- // (A point which was already accepted is effectively "grabbed" by the item.)
-
- // set of IDs of "interesting" new points
- QSet<int> matchingNewPoints;
- // set of points which this item has previously accepted, for starters
- QList<QTouchEvent::TouchPoint> matchingPoints = (*updatedPoints)[item];
- // now add the new points which are inside this item's bounds
- if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
- for (int i = 0; i < newPoints.count(); i++) {
- if (acceptedNewPoints->contains(newPoints[i].id()))
- continue;
- QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (item->contains(p)) {
- matchingNewPoints.insert(newPoints[i].id());
- matchingPoints << newPoints[i];
- }
+ if (item->contains(itemPos) && (!checkMouseButtons || itemPrivate->acceptedMouseButtons())) {
+ // add this item last - children take precedence
+ targets << item;
+ }
+ return targets;
+}
+
+// return the joined lists
+// list1 has priority, common items come last
+QVector<QQuickItem *> QQuickWindowPrivate::mergePointerTargets(const QVector<QQuickItem *> &list1, const QVector<QQuickItem *> &list2) const
+{
+ QVector<QQuickItem *> targets = list1;
+ // start at the end of list2
+ // if item not in list, append it
+ // if item found, move to next one, inserting before the last found one
+ int insertPosition = targets.length();
+ for (int i = list2.length() - 1; i >= 0; --i) {
+ int newInsertPosition = targets.lastIndexOf(list2.at(i), insertPosition);
+ if (newInsertPosition >= 0) {
+ Q_ASSERT(newInsertPosition <= insertPosition);
+ insertPosition = newInsertPosition;
}
+ // check for duplicates, only insert if the item isn't there already
+ if (insertPosition == targets.size() || list2.at(i) != targets.at(insertPosition))
+ targets.insert(insertPosition, list2.at(i));
}
- // If there are no matching new points, and the existing points are all stationary,
- // there's no need to send an event to this item. This is required by a test in
- // tst_qquickwindow::touchEvent_basic:
- // a single stationary press on an item shouldn't cause an event
- if (matchingNewPoints.isEmpty()) {
- bool stationaryOnly = true;
-
- foreach (const QTouchEvent::TouchPoint &tp, matchingPoints) {
- if (tp.state() != Qt::TouchPointStationary) {
- stationaryOnly = false;
- break;
+ return targets;
+}
+
+void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event)
+{
+ qCDebug(DBG_TOUCH) << " - delivering" << event->asTouchEvent();
+
+ QSet<QQuickItem *> hasFiltered;
+ if (event->isPressEvent())
+ deliverPressEvent(event, &hasFiltered);
+ if (!event->allPointsAccepted())
+ deliverUpdatedTouchPoints(event, &hasFiltered);
+
+ // Remove released points from itemForTouchPointId
+ bool allReleased = true;
+ int pointCount = event->pointCount();
+ for (int i = 0; i < pointCount; ++i) {
+ QQuickEventPoint *point = event->point(i);
+ if (point->state() == QQuickEventPoint::Released) {
+ int id = point->pointId();
+ qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "released";
+ point->setGrabber(nullptr);
+ if (id == touchMouseId) {
+ touchMouseId = -1;
+ touchMouseDevice = nullptr;
}
+ } else {
+ allReleased = false;
}
+ }
- if (stationaryOnly)
- matchingPoints.clear();
+ if (allReleased && !event->grabbers().isEmpty()) {
+ qWarning() << "No release received for some grabbers" << event->grabbers();
+ event->clearGrabbers();
}
+}
- if (!matchingPoints.isEmpty()) {
- // Now we know this item might be interested in the event. Copy and send it, but
- // with only the subset of TouchPoints which are relevant to that item: that's matchingPoints.
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- transformTouchPoints(matchingPoints, itemPrivate->windowToItemTransform());
- deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints, hasFiltered);
+// Deliver touch points to existing grabbers
+bool QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event, QSet<QQuickItem *> *hasFiltered)
+{
+ const auto grabbers = event->grabbers();
+ for (auto grabber : grabbers)
+ deliverMatchingPointsToItem(grabber, event, hasFiltered);
+
+ return false;
+}
+
+// Deliver newly pressed touch points
+bool QQuickWindowPrivate::deliverPressEvent(QQuickPointerEvent *event, QSet<QQuickItem *> *hasFiltered)
+{
+ const QVector<QPointF> points = event->unacceptedPressedPointScenePositions();
+ QVector<QQuickItem *> targetItems;
+ for (QPointF point: points) {
+ QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point, false);
+ if (targetItems.count()) {
+ targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
+ } else {
+ targetItems = targetItemsForPoint;
+ }
}
- // record the fact that this item has been visited already
- updatedPoints->remove(item);
+ for (QQuickItem *item: targetItems) {
+ deliverMatchingPointsToItem(item, event, hasFiltered);
+ if (event->allPointsAccepted())
+ break;
+ }
- // recursion is done only if ALL touch points have been delivered
- return (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty());
+ return event->allPointsAccepted();
}
-// touchEventForItem has no means to generate a touch event that contains
-// only the points that are relevant for this item. Thus the need for
-// matchingPoints to already be that set of interesting points.
-// They are all pre-transformed, too.
-bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem *> *hasFiltered)
+bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, QSet<QQuickItem *> *hasFiltered)
{
- QScopedPointer<QTouchEvent> touchEvent(touchEventWithPoints(*event, matchingPoints));
- touchEvent.data()->setTarget(item);
- bool touchEventAccepted = false;
+ Q_Q(QQuickWindow);
+
+ // TODO: unite this mouse point delivery with the synthetic mouse event below
+ if (auto event = pointerEvent->asPointerMouseEvent()) {
+ if (item->acceptedMouseButtons() & event->button()) {
+ auto point = event->point(0);
+ if (point->isAccepted())
+ return false;
+ QPointF localPos = item->mapFromScene(point->scenePos());
+ Q_ASSERT(item->contains(localPos)); // transform is checked already
+ QMouseEvent *me = event->asMouseEvent(localPos);
+ me->accept();
+ q->sendEvent(item, me);
+ if (me->isAccepted()) {
+ auto mouseGrabber = q->mouseGrabberItem();
+ if (mouseGrabber && mouseGrabber != item) {
+ item->mouseUngrabEvent();
+ } else {
+ item->grabMouse();
+ }
+ point->setAccepted(true);
+ }
+ return me->isAccepted();
+ }
+ return false;
+ }
+
+ QQuickPointerTouchEvent *event = pointerEvent->asPointerTouchEvent();
+ if (!event)
+ return false;
+
+ QScopedPointer<QTouchEvent> touchEvent(event->touchEventForItem(item));
+ if (!touchEvent)
+ return false;
qCDebug(DBG_TOUCH) << " - considering delivering " << touchEvent.data() << " to " << item;
+ bool eventAccepted = false;
// First check whether the parent wants to be a filter,
// and if the parent accepts the event we are done.
@@ -2220,112 +2288,53 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv
// If the touch was accepted (regardless by whom or in what form),
// update acceptedNewPoints
qCDebug(DBG_TOUCH) << " - can't. intercepted " << touchEvent.data() << " to " << item->parentItem() << " instead of " << item;
- foreach (int id, matchingNewPoints)
- acceptedNewPoints->insert(id);
+ for (auto point: qAsConst(touchEvent->touchPoints())) {
+ event->pointById(point.id())->setAccepted();
+ }
return true;
}
- // Since it can change in sendEvent, update itemForTouchPointId now
- foreach (int id, matchingNewPoints) {
- qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "->" << item;
- itemForTouchPointId[id] = item;
- }
-
// Deliver the touch event to the given item
qCDebug(DBG_TOUCH) << " - actually delivering " << touchEvent.data() << " to " << item;
QCoreApplication::sendEvent(item, touchEvent.data());
- touchEventAccepted = touchEvent->isAccepted();
+ eventAccepted = touchEvent->isAccepted();
// If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it.
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- if (!touchEventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
+ if (!eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
// send mouse event
- event->setAccepted(translateTouchToMouse(item, touchEvent.data()));
- if (event->isAccepted()) {
- touchEventAccepted = true;
- }
+ if (deliverTouchAsMouse(item, event))
+ eventAccepted = true;
}
- if (touchEventAccepted) {
+ if (eventAccepted) {
// If the touch was accepted (regardless by whom or in what form),
- // update acceptedNewPoints.
- foreach (int id, matchingNewPoints)
- acceptedNewPoints->insert(id);
+ // update accepted new points.
+ for (auto point: qAsConst(touchEvent->touchPoints())) {
+ auto pointerEventPoint = event->pointById(point.id());
+ pointerEventPoint->setAccepted();
+ if (point.state() == Qt::TouchPointPressed)
+ pointerEventPoint->setGrabber(item);
+ }
} else {
// But if the event was not accepted then we know this item
// will not be interested in further updates for those touchpoint IDs either.
- foreach (int id, matchingNewPoints)
- if (itemForTouchPointId[id] == item) {
- qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "disassociated";
- itemForTouchPointId.remove(id);
- }
- }
-
- return touchEventAccepted;
-}
-
-QTouchEvent *QQuickWindowPrivate::touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds)
-{
- const QList<QTouchEvent::TouchPoint> &touchPoints = originalEvent.touchPoints();
- QList<QTouchEvent::TouchPoint> pointsInBounds;
- // if all points are stationary, the list of points should be empty to signal a no-op
- if (originalEvent.touchPointStates() != Qt::TouchPointStationary) {
- for (int i = 0; i < touchPoints.count(); ++i) {
- const QTouchEvent::TouchPoint &tp = touchPoints.at(i);
- // Touch presses are relevant to the target item only if they occur inside its bounds.
- // Touch updates and releases are relevant if they occur inside, or if we want to
- // finish the sequence because the press occurred inside.
- if (tp.state() == Qt::TouchPointPressed || alwaysCheckBounds) {
- QPointF p = target->mapFromScene(tp.scenePos());
- if (target->contains(p))
- pointsInBounds.append(tp);
- } else {
- pointsInBounds.append(tp);
+ for (auto point: qAsConst(touchEvent->touchPoints())) {
+ if (point.state() == Qt::TouchPointPressed) {
+ if (event->pointById(point.id())->grabber() == item) {
+ qCDebug(DBG_TOUCH_TARGET) << "TP" << point.id() << "disassociated";
+ event->pointById(point.id())->setGrabber(nullptr);
+ }
}
}
- transformTouchPoints(pointsInBounds, QQuickItemPrivate::get(target)->windowToItemTransform());
- }
-
- QTouchEvent* touchEvent = touchEventWithPoints(originalEvent, pointsInBounds);
- touchEvent->setTarget(target);
- return touchEvent;
-}
-
-QTouchEvent *QQuickWindowPrivate::touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints)
-{
- Qt::TouchPointStates eventStates;
- for (int i=0; i<newPoints.count(); i++)
- eventStates |= newPoints[i].state();
- // if all points have the same state, set the event type accordingly
- QEvent::Type eventType = event.type();
- switch (eventStates) {
- case Qt::TouchPointPressed:
- eventType = QEvent::TouchBegin;
- break;
- case Qt::TouchPointReleased:
- eventType = QEvent::TouchEnd;
- break;
- default:
- eventType = QEvent::TouchUpdate;
- break;
}
- QTouchEvent *touchEvent = new QTouchEvent(eventType);
- touchEvent->setWindow(event.window());
- touchEvent->setTarget(event.target());
- touchEvent->setDevice(event.device());
- touchEvent->setModifiers(event.modifiers());
- touchEvent->setTouchPoints(newPoints);
- touchEvent->setTouchPointStates(eventStates);
- touchEvent->setTimestamp(event.timestamp());
- touchEvent->accept();
- return touchEvent;
+ return eventAccepted;
}
#ifndef QT_NO_DRAGANDDROP
void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
{
- Q_Q(QQuickWindow);
grabber->resetTarget();
QQuickDragGrabber::iterator grabItem = grabber->begin();
if (grabItem != grabber->end()) {
@@ -2341,7 +2350,7 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
e->mouseButtons(),
e->keyboardModifiers());
QQuickDropEventEx::copyActions(&translatedEvent, *e);
- q->sendEvent(**grabItem, &translatedEvent);
+ QCoreApplication::sendEvent(**grabItem, &translatedEvent);
e->setAccepted(translatedEvent.isAccepted());
e->setDropAction(translatedEvent.dropAction());
grabber->setTarget(**grabItem);
@@ -2350,7 +2359,7 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
if (event->type() != QEvent::DragMove) { // Either an accepted drop or a leave.
QDragLeaveEvent leaveEvent;
for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
- q->sendEvent(**grabItem, &leaveEvent);
+ QCoreApplication::sendEvent(**grabItem, &leaveEvent);
return;
} else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
@@ -2366,18 +2375,18 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
moveEvent->mouseButtons(),
moveEvent->keyboardModifiers());
QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
- q->sendEvent(**grabItem, &translatedEvent);
+ QCoreApplication::sendEvent(**grabItem, &translatedEvent);
++grabItem;
} else {
QDragLeaveEvent leaveEvent;
- q->sendEvent(**grabItem, &leaveEvent);
+ QCoreApplication::sendEvent(**grabItem, &leaveEvent);
grabItem = grabber->release(grabItem);
}
}
return;
} else {
QDragLeaveEvent leaveEvent;
- q->sendEvent(**grabItem, &leaveEvent);
+ QCoreApplication::sendEvent(**grabItem, &leaveEvent);
}
}
}
@@ -2396,7 +2405,6 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
{
- Q_Q(QQuickWindow);
bool accepted = false;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
@@ -2431,7 +2439,7 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
event->keyboardModifiers(),
event->type());
QQuickDropEventEx::copyActions(&translatedEvent, *event);
- q->sendEvent(item, &translatedEvent);
+ QCoreApplication::sendEvent(item, &translatedEvent);
if (event->type() == QEvent::DragEnter) {
if (translatedEvent.isAccepted()) {
grabber->grab(item);
@@ -2474,7 +2482,7 @@ QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF
return 0;
}
- if (itemPrivate->hasCursorInChild) {
+ if (itemPrivate->subtreeCursorEnabled) {
QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
for (int ii = children.count() - 1; ii >= 0; --ii) {
QQuickItem *child = children.at(ii);
@@ -2494,8 +2502,10 @@ QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF
}
#endif
-bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem *> *hasFiltered)
+bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QQuickPointerTouchEvent *event, QSet<QQuickItem *> *hasFiltered)
{
+ Q_Q(QQuickWindow);
+
if (!target)
return false;
@@ -2504,8 +2514,8 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) {
hasFiltered->insert(target);
- QScopedPointer<QTouchEvent> targetEvent(touchEventForItem(target, *event));
- if (!targetEvent->touchPoints().isEmpty()) {
+ QScopedPointer<QTouchEvent> targetEvent(event->touchEventForItem(target, true));
+ if (targetEvent) {
if (target->childMouseEventFilter(item, targetEvent.data())) {
qCDebug(DBG_TOUCH) << " - first chance intercepted on childMouseEventFilter by " << target;
QVector<int> touchIds;
@@ -2514,9 +2524,10 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
for (int i = 0; i < touchPointCount; ++i)
touchIds.append(targetEvent->touchPoints().at(i).id());
target->grabTouchPoints(touchIds);
- if (mouseGrabberItem) {
- mouseGrabberItem->ungrabMouse();
+ if (q->mouseGrabberItem()) {
+ q->mouseGrabberItem()->ungrabMouse();
touchMouseId = -1;
+ touchMouseDevice = nullptr;
}
filtered = true;
}
@@ -2528,12 +2539,6 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
switch (tp.state()) {
case Qt::TouchPointPressed:
t = QEvent::MouseButtonPress;
- if (touchMouseId == -1) {
- // We don't want to later filter touches as a mouse event if they were pressed
- // while a touchMouseId was already active.
- // Remember this touch as a potential to become the touchMouseId.
- touchMouseIdCandidates.insert(tp.id());
- }
break;
case Qt::TouchPointReleased:
t = QEvent::MouseButtonRelease;
@@ -2546,18 +2551,20 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
}
// Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId
- if ((touchMouseIdCandidates.contains(tp.id()) && touchMouseId == -1) || touchMouseId == tp.id()) {
+ if (touchMouseId == -1 || touchMouseId == tp.id()) {
// targetEvent is already transformed wrt local position, velocity, etc.
- QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event, item, false));
+
+ // FIXME: remove asTouchEvent!!!
+ QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event->asTouchEvent(), item, false));
if (target->childMouseEventFilter(item, mouseEvent.data())) {
qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target;
if (t != QEvent::MouseButtonRelease) {
qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target;
- itemForTouchPointId[tp.id()] = target;
touchMouseId = tp.id();
+ touchMouseDevice = event->device();
+ touchMouseDevice->pointerEvent()->pointById(tp.id())->setGrabber(target);
target->grabMouse();
}
- touchMouseIdCandidates.clear();
filtered = true;
}
// Only one event can be filtered as a mouse event.
@@ -2711,8 +2718,13 @@ void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &fo
/*!
Propagates an event \a e to a QQuickItem \a item on the window.
+ Use \l QCoreApplication::sendEvent() directly instead.
+
The return value is currently not used.
+
+ \deprecated
*/
+// ### Qt6: remove
bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
{
Q_D(QQuickWindow);
@@ -2734,9 +2746,6 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
QCoreApplication::sendEvent(item, e);
}
break;
- case QEvent::ShortcutOverride:
- QCoreApplication::sendEvent(item, e);
- break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
@@ -2750,41 +2759,8 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
}
}
break;
- case QEvent::UngrabMouse: {
- QSet<QQuickItem *> hasFiltered;
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e, &hasFiltered)) {
- e->accept();
- item->mouseUngrabEvent();
- }
- }
- break;
-#ifndef QT_NO_WHEELEVENT
- case QEvent::Wheel:
-#endif
-#ifndef QT_NO_DRAGANDDROP
- case QEvent::DragEnter:
- case QEvent::DragMove:
- case QEvent::DragLeave:
- case QEvent::Drop:
-#endif
- case QEvent::FocusIn:
- case QEvent::FocusOut:
- case QEvent::HoverEnter:
- case QEvent::HoverLeave:
- case QEvent::HoverMove:
- case QEvent::TouchCancel:
- QCoreApplication::sendEvent(item, e);
- break;
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- case QEvent::TouchEnd: {
- QSet<QQuickItem*> hasFiltered;
- QTouchEvent *ev = static_cast<QTouchEvent *>(e);
- qCDebug(DBG_TOUCH) << " - sendEvent for " << ev << " to " << item->parentItem() << " and " << item;
- d->sendFilteredTouchEvent(item->parentItem(), item, ev, &hasFiltered);
- }
- break;
default:
+ QCoreApplication::sendEvent(item, e);
break;
}
@@ -3145,7 +3121,7 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
<< itemPriv->paintNode;
nodes.removeAll(0);
- Q_ASSERT(nodes.first() == itemPriv->itemNodeInstance);
+ Q_ASSERT(nodes.constFirst() == itemPriv->itemNodeInstance);
for (int i=1; i<nodes.size(); ++i) {
QSGNode *n = nodes.at(i);
// Failing this means we messed up reparenting
@@ -3244,7 +3220,9 @@ bool QQuickWindow::isSceneGraphInitialized() const
/*!
\fn void QQuickWindow::frameSwapped()
- This signal is emitted when the frame buffers have been swapped.
+ This signal is emitted when a frame has been queued for presenting. With
+ vertical synchronization enabled the signal is emitted at most once per
+ vsync interval in a continuously animating scene.
This signal will be emitted from the scene graph rendering thread.
*/
@@ -4168,6 +4146,28 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
+ \qmlproperty variant Window::targetScreen
+
+ Specifies the screen the window should be placed on. Equivalent to
+ QWindow::setScreen().
+
+ The value must be an element from the Qt.application.screens array.
+
+ By default the value is null which leads to using the primary screen.
+
+ \note To ensure that the window is associated with the desired screen right
+ upon the underlying native window's initial creation, make sure this
+ property is set as early as possible and that the setting of its value is
+ not deferred. This can be particularly important on embedded platforms
+ without a windowing system, where only one window per screen is allowed at a
+ time.
+
+ \since 5.9
+
+ \sa QWindow::setScreen(), QScreen, Qt.application
+ */
+
+/*!
\qmlproperty Item Window::activeFocusItem
\since 5.1
@@ -4397,7 +4397,7 @@ void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs)
jobs->clear();
renderJobMutex.unlock();
- foreach (QRunnable *r, jobList) {
+ for (QRunnable *r : qAsConst(jobList)) {
r->run();
delete r;
}
@@ -4428,16 +4428,37 @@ qreal QQuickWindow::effectiveDevicePixelRatio() const
}
/*!
- Returns the current renderer interface if there is one. Otherwise null is returned.
+ \return the current renderer interface. The value is always valid and is never null.
+
+ \note This function can be called at any time after constructing the
+ QQuickWindow, even while isSceneGraphInitialized() is still false. However,
+ some renderer interface functions, in particular
+ QSGRendererInterface::getResource() will not be functional until the
+ scenegraph is up and running. Backend queries, like
+ QSGRendererInterface::graphicsApi() or QSGRendererInterface::shaderType(),
+ will always be functional on the other hand.
- \sa QSGRenderNode, QSGRendererInterface, isSceneGraphInitialized()
+ \note The ownership of the returned pointer stays with Qt. The returned
+ instance may or may not be shared between different QQuickWindow instances,
+ depending on the scenegraph backend in use. Therefore applications are
+ expected to query the interface object for each QQuickWindow instead of
+ reusing the already queried pointer.
+
+ \sa QSGRenderNode, QSGRendererInterface
\since 5.8
*/
QSGRendererInterface *QQuickWindow::rendererInterface() const
{
Q_D(const QQuickWindow);
- return isSceneGraphInitialized() ? d->context->sceneGraphContext()->rendererInterface(d->context) : nullptr;
+
+ // no context validity check - it is essential to be able to return a
+ // renderer interface instance before scenegraphInitialized() is emitted
+ // (depending on the backend, that can happen way too late for some of the
+ // rif use cases, like examining the graphics api or shading language in
+ // use)
+
+ return d->context->sceneGraphContext()->rendererInterface(d->context);
}
/*!
@@ -4491,6 +4512,45 @@ void QQuickWindow::setSceneGraphBackend(const QString &backend)
QSGContext::setBackend(backend);
}
+/*!
+ Creates a simple rectangle node. When the scenegraph is not initialized, the return value is null.
+
+ This is cross-backend alternative to constructing a QSGSimpleRectNode directly.
+
+ \since 5.8
+ \sa QSGRectangleNode
+ */
+QSGRectangleNode *QQuickWindow::createRectangleNode() const
+{
+ Q_D(const QQuickWindow);
+ return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createRectangleNode() : nullptr;
+}
+
+/*!
+ Creates a simple image node. When the scenegraph is not initialized, the return value is null.
+
+ This is cross-backend alternative to constructing a QSGSimpleTextureNode directly.
+
+ \since 5.8
+ \sa QSGImageNode
+ */
+QSGImageNode *QQuickWindow::createImageNode() const
+{
+ Q_D(const QQuickWindow);
+ return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createImageNode() : nullptr;
+}
+
+/*!
+ Creates a nine patch node. When the scenegraph is not initialized, the return value is null.
+
+ \since 5.8
+ */
+QSGNinePatchNode *QQuickWindow::createNinePatchNode() const
+{
+ Q_D(const QQuickWindow);
+ return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createNinePatchNode() : nullptr;
+}
+
#include "moc_qquickwindow.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index c741772253..cfadadec2d 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -61,6 +61,9 @@ class QQmlIncubationController;
class QInputMethodEvent;
class QQuickCloseEvent;
class QQuickRenderControl;
+class QSGRectangleNode;
+class QSGImageNode;
+class QSGNinePatchNode;
class Q_QUICK_EXPORT QQuickWindow : public QWindow
{
@@ -159,6 +162,10 @@ public:
static void setSceneGraphBackend(QSGRendererInterface::GraphicsApi api);
static void setSceneGraphBackend(const QString &backend);
+ QSGRectangleNode *createRectangleNode() const;
+ QSGImageNode *createImageNode() const;
+ QSGNinePatchNode *createNinePatchNode() const;
+
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index daff9ef473..3e146d5440 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -53,6 +53,7 @@
#include "qquickitem.h"
#include "qquickwindow.h"
+#include "qquickevents_p_p.h"
#include <QtQuick/private/qsgcontext_p.h>
@@ -68,13 +69,19 @@
QT_BEGIN_NAMESPACE
-//Make it easy to identify and customize the root item if needed
-
+class QOpenGLVertexArrayObjectHelper;
class QQuickAnimatorController;
-class QSGRenderLoop;
-class QQuickRenderControl;
class QQuickDragGrabber;
+class QQuickItemPrivate;
+class QQuickPointerDevice;
+class QQuickRenderControl;
+class QQuickWindowIncubationController;
+class QQuickWindowPrivate;
+class QQuickWindowRenderLoop;
+class QSGRenderLoop;
+class QTouchEvent;
+//Make it easy to identify and customize the root item if needed
class QQuickRootItem : public QQuickItem
{
Q_OBJECT
@@ -85,15 +92,6 @@ public Q_SLOTS:
void setHeight(int h) {QQuickItem::setHeight(qreal(h));}
};
-class QQuickItemPrivate;
-class QQuickWindowPrivate;
-
-class QTouchEvent;
-class QQuickWindowRenderLoop;
-class QQuickWindowIncubationController;
-
-class QOpenGLVertexArrayObjectHelper;
-
class Q_QUICK_PRIVATE_EXPORT QQuickCustomRenderStage
{
public:
@@ -127,7 +125,6 @@ public:
void deliverKeyEvent(QKeyEvent *e);
// Keeps track of the item currently receiving mouse events
- QQuickItem *mouseGrabberItem;
#ifndef QT_NO_CURSOR
QQuickItem *cursorItem;
#endif
@@ -135,18 +132,19 @@ public:
QQuickDragGrabber *dragGrabber;
#endif
int touchMouseId;
+ QQuickPointerDevice *touchMouseDevice;
bool checkIfDoubleClicked(ulong newPressEventTimestamp);
ulong touchMousePressTimestamp;
// Mouse positions are saved in widget coordinates
QPointF lastMousePosition;
- bool translateTouchToMouse(QQuickItem *item, QTouchEvent *event);
+ bool deliverTouchAsMouse(QQuickItem *item, QQuickPointerEvent *pointerEvent);
void translateTouchEvent(QTouchEvent *touchEvent);
void setMouseGrabber(QQuickItem *grabber);
- static void transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform);
+ void grabTouchPoints(QQuickItem *grabber, const QVector<int> &ids);
+ void removeGrabber(QQuickItem *grabber, bool mouse = true, bool touch = true);
static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
- bool deliverInitialMousePressEvent(QQuickItem *, QMouseEvent *);
- bool deliverMouseEvent(QMouseEvent *);
+ void deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent);
bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *, QSet<QQuickItem *> *);
#ifndef QT_NO_WHEELEVENT
bool deliverWheelEvent(QQuickItem *, QWheelEvent *);
@@ -154,21 +152,33 @@ public:
#ifndef QT_NO_GESTURES
bool deliverNativeGestureEvent(QQuickItem *, QNativeGestureEvent *);
#endif
- bool deliverTouchPoints(QQuickItem *, QTouchEvent *, const QList<QTouchEvent::TouchPoint> &, QSet<int> *,
- QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *, QSet<QQuickItem*> *filtered);
- void deliverTouchEvent(QTouchEvent *);
- void reallyDeliverTouchEvent(QTouchEvent *);
- bool deliverTouchCancelEvent(QTouchEvent *);
- void deliverDelayedTouchEvent();
+
+ // entry point of events to the window
+ void handleTouchEvent(QTouchEvent *);
+ void handleMouseEvent(QMouseEvent *);
+ bool compressTouchEvent(QTouchEvent *);
void flushFrameSynchronousEvents();
- bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted);
- bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered);
- static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false);
- static QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints);
- bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem*> *filtered);
+ void deliverDelayedTouchEvent();
+
+ // delivery of pointer events:
+ QQuickPointerEvent *pointerEventInstance(QEvent *ev) const;
+ void deliverPointerEvent(QQuickPointerEvent *);
+ void deliverTouchEvent(QQuickPointerTouchEvent *);
+ bool deliverTouchCancelEvent(QTouchEvent *);
+ bool deliverPressEvent(QQuickPointerEvent *, QSet<QQuickItem *> *);
+ bool deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event, QSet<QQuickItem *> *hasFiltered);
+ bool deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, QSet<QQuickItem*> *filtered);
+ bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QQuickPointerTouchEvent *event, QSet<QQuickItem*> *filtered);
+
+ QVector<QQuickItem *> pointerTargets(QQuickItem *, const QPointF &, bool checkMouseButtons) const;
+ QVector<QQuickItem *> mergePointerTargets(const QVector<QQuickItem *> &list1, const QVector<QQuickItem *> &list2) const;
+
+ // hover delivery
+ bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted);
bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos,
- Qt::KeyboardModifiers modifiers, bool accepted);
- bool clearHover();
+ Qt::KeyboardModifiers modifiers, ulong timestamp, bool accepted);
+ bool clearHover(ulong timestamp = 0);
+
#ifndef QT_NO_DRAGANDDROP
void deliverDragEvent(QQuickDragGrabber *, QEvent *);
bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *);
@@ -188,7 +198,7 @@ public:
void setFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = 0);
void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = 0);
static void notifyFocusChangesRecur(QQuickItem **item, int remaining);
- void clearFocusObject();
+ void clearFocusObject() override;
void updateFocusItemTransform();
@@ -233,15 +243,14 @@ public:
QQuickRenderControl *renderControl;
QQuickAnimatorController *animationController;
QScopedPointer<QTouchEvent> delayedTouch;
- int touchRecursionGuard;
+
+ int pointerEventRecursionGuard;
QQuickCustomRenderStage *customRenderStage;
QColor clearColor;
uint clearBeforeRendering : 1;
- // Currently unused in the default implementation, as we're not stopping
- // rendering when obscured as we should...
uint persistentGLContext : 1;
uint persistentSceneGraph : 1;
@@ -256,10 +265,6 @@ public:
QOpenGLVertexArrayObjectHelper *vaoHelper;
- // Keeps track of which touch point (int) was last accepted by which item
- QHash<int, QQuickItem *> itemForTouchPointId;
- QSet<int> touchMouseIdCandidates;
-
mutable QQuickWindowIncubationController *incubationController;
static bool defaultAlphaBuffer;
@@ -291,22 +296,6 @@ private:
static void cleanupNodesOnShutdown(QQuickItem *);
};
-class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
-
-public:
- QQuickCloseEvent()
- : _accepted(true) {}
-
- bool isAccepted() { return _accepted; }
- void setAccepted(bool accepted) { _accepted = accepted; }
-
-private:
- bool _accepted;
-};
-
class QQuickWindowQObjectCleanupJob : public QRunnable
{
public:
@@ -324,6 +313,4 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickWindowPrivate::FocusOptions)
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickCloseEvent)
-
#endif // QQUICKWINDOW_P_H
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index c624d162a9..8ab2cee96f 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -58,6 +58,7 @@ public:
: complete(false)
, visible(false)
, visibility(QQuickWindow::AutomaticVisibility)
+ , targetScreen(nullptr)
{
}
@@ -65,6 +66,7 @@ public:
bool visible;
QQuickWindow::Visibility visibility;
QV4::PersistentValue rootItemMarker;
+ QObject *targetScreen;
};
QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent)
@@ -170,6 +172,26 @@ void QQuickWindowQmlImpl::setWindowVisibility()
}
}
+QObject *QQuickWindowQmlImpl::targetScreen() const
+{
+ Q_D(const QQuickWindowQmlImpl);
+ return d->targetScreen;
+}
+
+void QQuickWindowQmlImpl::setTargetScreen(QObject *screen)
+{
+ Q_D(QQuickWindowQmlImpl);
+ if (d->targetScreen != screen) {
+ d->targetScreen = screen;
+ emit targetScreenChanged();
+ QQuickScreenInfo *screenWrapper = qobject_cast<QQuickScreenInfo *>(screen);
+ if (screenWrapper)
+ setScreen(screenWrapper->wrappedScreen());
+ else
+ setScreen(nullptr);
+ }
+}
+
void QQuickWindowModule::defineModule()
{
const char uri[] = "QtQuick.Window";
@@ -181,7 +203,10 @@ void QQuickWindowModule::defineModule()
qmlRegisterRevision<QQuickWindow,2>(uri, 2, 2);
qmlRegisterType<QQuickWindowQmlImpl>(uri, 2, 1, "Window");
qmlRegisterType<QQuickWindowQmlImpl,1>(uri, 2, 2, "Window");
+ qmlRegisterType<QQuickWindowQmlImpl,2>(uri, 2, 3, "Window");
qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property."));
+ qmlRegisterUncreatableType<QQuickScreen,1>(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property."));
+ qmlRegisterUncreatableType<QQuickScreenInfo,2>(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property."));
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index 8a6bbac412..7ca29880ea 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -67,6 +67,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
+ Q_PROPERTY(QObject *targetScreen READ targetScreen WRITE setTargetScreen NOTIFY targetScreenChanged REVISION 2)
public:
QQuickWindowQmlImpl(QWindow *parent = Q_NULLPTR);
@@ -74,11 +75,15 @@ public:
void setVisible(bool visible);
void setVisibility(Visibility visibility);
+ QObject *targetScreen() const;
+ void setTargetScreen(QObject *screen);
+
static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
Q_SIGNALS:
void visibleChanged(bool arg);
void visibilityChanged(QWindow::Visibility visibility);
+ Q_REVISION(2) void targetScreenChanged();
protected:
void classBegin() Q_DECL_OVERRIDE;
diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp
index 41e30a1110..4028c63da5 100644
--- a/src/quick/qtquick2.cpp
+++ b/src/quick/qtquick2.cpp
@@ -49,7 +49,6 @@
#include <private/qqmldebugstatesdelegate_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlcontext_p.h>
-#include <private/qquickprofiler_p.h>
#include <private/qquickapplication_p.h>
#include <QtQuick/private/qquickpropertychanges_p.h>
#include <QtQuick/private/qquickstate_p.h>
@@ -63,23 +62,29 @@ static void initResources()
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+class QQmlQtQuick2DebugStatesDelegate : public QQmlDebugStatesDelegate {};
+
+#else
+
class QQmlQtQuick2DebugStatesDelegate : public QQmlDebugStatesDelegate
{
public:
QQmlQtQuick2DebugStatesDelegate();
- virtual ~QQmlQtQuick2DebugStatesDelegate();
- virtual void buildStatesList(bool cleanList, const QList<QPointer<QObject> > &instances);
- virtual void updateBinding(QQmlContext *context,
- const QQmlProperty &property,
- const QVariant &expression, bool isLiteralValue,
- const QString &fileName, int line, int column,
- bool *isBaseState);
- virtual bool setBindingForInvalidProperty(QObject *object,
- const QString &propertyName,
- const QVariant &expression,
- bool isLiteralValue);
- virtual void resetBindingForInvalidProperty(QObject *object,
- const QString &propertyName);
+ ~QQmlQtQuick2DebugStatesDelegate();
+ void buildStatesList(bool cleanList, const QList<QPointer<QObject> > &instances) override;
+ void updateBinding(QQmlContext *context,
+ const QQmlProperty &property,
+ const QVariant &expression, bool isLiteralValue,
+ const QString &fileName, int line, int column,
+ bool *isBaseState) override;
+ bool setBindingForInvalidProperty(QObject *object,
+ const QString &propertyName,
+ const QVariant &expression,
+ bool isLiteralValue) override;
+ void resetBindingForInvalidProperty(QObject *object,
+ const QString &propertyName) override;
private:
void buildStatesList(QObject *obj);
@@ -128,7 +133,7 @@ void QQmlQtQuick2DebugStatesDelegate::updateBinding(QQmlContext *context,
typedef QPointer<QQuickState> QuickStatePointer;
QObject *object = property.object();
QString propertyName = property.name();
- foreach (const QuickStatePointer& statePointer, m_allStates) {
+ for (const QuickStatePointer& statePointer : qAsConst(m_allStates)) {
if (QQuickState *state = statePointer.data()) {
// here we assume that the revert list on itself defines the base state
if (state->isStateActive() && state->containsPropertyInRevertList(object, propertyName)) {
@@ -136,9 +141,10 @@ void QQmlQtQuick2DebugStatesDelegate::updateBinding(QQmlContext *context,
QQmlBinding *newBinding = 0;
if (!isLiteralValue) {
- newBinding = new QQmlBinding(expression.toString(), object,
- QQmlContextData::get(context), fileName,
- line, column);
+ newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core,
+ expression.toString(), object,
+ QQmlContextData::get(context), fileName,
+ line, column);
newBinding->setTarget(property);
}
@@ -174,6 +180,7 @@ void QQmlQtQuick2DebugStatesDelegate::resetBindingForInvalidProperty(QObject *ob
}
}
+#endif // QT_NO_QML_DEBUGGER
void QQmlQtQuick2Module::defineModule()
{
diff --git a/src/quick/quick.pro b/src/quick/quick.pro
index f74a554aa9..4909f7fce8 100644
--- a/src/quick/quick.pro
+++ b/src/quick/quick.pro
@@ -33,7 +33,7 @@ include(util/util.pri)
include(scenegraph/scenegraph.pri)
include(items/items.pri)
include(designer/designer.pri)
-contains(QT_CONFIG, accessibility) {
+qtConfig(accessibility) {
include(accessible/accessible.pri)
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
index eb0e26462a..2ff180ea99 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
@@ -67,9 +67,7 @@ QSGAbstractSoftwareRenderer::~QSGAbstractSoftwareRenderer()
// Cleanup RenderableNodes
delete m_background;
- for (QSGSoftwareRenderableNode *node : m_nodes.values()) {
- delete node;
- }
+ qDeleteAll(m_nodes);
delete m_nodeUpdater;
}
@@ -149,7 +147,7 @@ void QSGAbstractSoftwareRenderer::buildRenderList()
QSGSoftwareRenderListBuilder(this).visitChildren(rootNode());
}
-void QSGAbstractSoftwareRenderer::optimizeRenderList()
+QRegion QSGAbstractSoftwareRenderer::optimizeRenderList()
{
// Iterate through the renderlist from front to back
// Objective is to update the dirty status and rects.
@@ -212,9 +210,13 @@ void QSGAbstractSoftwareRenderer::optimizeRenderList()
m_dirtyRegion += node->dirtyRegion();
}
+ QRegion updateRegion = m_dirtyRegion;
+
// Empty dirtyRegion
m_dirtyRegion = QRegion();
m_obscuredRegion = QRegion();
+
+ return updateRegion;
}
void QSGAbstractSoftwareRenderer::setBackgroundColor(const QColor &color)
@@ -232,7 +234,7 @@ void QSGAbstractSoftwareRenderer::setBackgroundSize(const QSize &size)
m_background->setRect(0.0f, 0.0f, size.width(), size.height());
renderableNode(m_background)->markGeometryDirty();
// Invalidate the whole scene when the background is resized
- m_dirtyRegion = QRegion(m_background->rect().toRect());
+ markDirty();
}
QColor QSGAbstractSoftwareRenderer::backgroundColor()
@@ -318,4 +320,9 @@ void QSGAbstractSoftwareRenderer::nodeOpacityUpdated(QSGNode *node)
m_nodeUpdater->updateNodes(node);
}
+void QSGAbstractSoftwareRenderer::markDirty()
+{
+ m_dirtyRegion = QRegion(m_background->rect().toRect());
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
index a2e953f40d..905577b92a 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
@@ -75,10 +75,12 @@ public:
void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override;
+ void markDirty();
+
protected:
QRegion renderNodes(QPainter *painter);
void buildRenderList();
- void optimizeRenderList();
+ QRegion optimizeRenderList();
void setBackgroundColor(const QColor &color);
void setBackgroundSize(const QSize &size);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp
index 0e2f4f5382..92c02b4966 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp
@@ -40,6 +40,7 @@
#include "qsgsoftwareadaptation_p.h"
#include "qsgsoftwarecontext_p.h"
#include "qsgsoftwarerenderloop_p.h"
+#include "qsgsoftwarethreadedrenderloop_p.h"
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -53,7 +54,7 @@ QSGSoftwareAdaptation::QSGSoftwareAdaptation(QObject *parent)
QStringList QSGSoftwareAdaptation::keys() const
{
- return QStringList() << QLatin1String("software");
+ return QStringList() << QLatin1String("software") << QLatin1String("softwarecontext");
}
QSGContext *QSGSoftwareAdaptation::create(const QString &) const
@@ -73,6 +74,16 @@ QSGContextFactoryInterface::Flags QSGSoftwareAdaptation::flags(const QString &)
QSGRenderLoop *QSGSoftwareAdaptation::createWindowManager()
{
+ static bool threaded = false;
+ static bool envChecked = false;
+ if (!envChecked) {
+ envChecked = true;
+ threaded = qgetenv("QSG_RENDER_LOOP") == "threaded";
+ }
+
+ if (threaded)
+ return new QSGSoftwareThreadedRenderLoop;
+
return new QSGSoftwareRenderLoop();
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
index ce726e342b..80112c1121 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
@@ -39,28 +39,21 @@
#include "qsgsoftwarecontext_p.h"
-#include "qsgsoftwarerectanglenode_p.h"
-#include "qsgsoftwareimagenode_p.h"
+#include "qsgsoftwareinternalrectanglenode_p.h"
+#include "qsgsoftwareinternalimagenode_p.h"
#include "qsgsoftwarepainternode_p.h"
#include "qsgsoftwarepixmaptexture_p.h"
#include "qsgsoftwareglyphnode_p.h"
-#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepublicnodes_p.h"
#include "qsgsoftwarelayer_p.h"
#include "qsgsoftwarerenderer_p.h"
+#include "qsgsoftwarespritenode_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QElapsedTimer>
#include <QtGui/QWindow>
-
-#include <QtQuick/QSGFlatColorMaterial>
-#include <QtQuick/QSGVertexColorMaterial>
-#include <QtQuick/QSGOpaqueTextureMaterial>
-#include <QtQuick/QSGTextureMaterial>
-
-#ifndef QSG_NO_RENDERER_TIMING
-static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
-#endif
+#include <QtQuick/private/qquickwindow_p.h>
// Used for very high-level info about the renderering and gl context
// Includes GL_VERSION, type of render loop, atlas size, etc.
@@ -90,21 +83,23 @@ QT_BEGIN_NAMESPACE
QSGSoftwareRenderContext::QSGSoftwareRenderContext(QSGContext *ctx)
: QSGRenderContext(ctx)
, m_initialized(false)
+ , m_activePainter(nullptr)
{
}
+
QSGSoftwareContext::QSGSoftwareContext(QObject *parent)
: QSGContext(parent)
{
}
-QSGRectangleNode *QSGSoftwareContext::createRectangleNode()
+QSGInternalRectangleNode *QSGSoftwareContext::createInternalRectangleNode()
{
- return new QSGSoftwareRectangleNode();
+ return new QSGSoftwareInternalRectangleNode();
}
-QSGImageNode *QSGSoftwareContext::createImageNode()
+QSGInternalImageNode *QSGSoftwareContext::createInternalImageNode()
{
- return new QSGSoftwareImageNode();
+ return new QSGSoftwareInternalImageNode();
}
QSGPainterNode *QSGSoftwareContext::createPainterNode(QQuickPaintedItem *item)
@@ -119,11 +114,6 @@ QSGGlyphNode *QSGSoftwareContext::createGlyphNode(QSGRenderContext *rc, bool pre
return new QSGSoftwareGlyphNode();
}
-QSGNinePatchNode *QSGSoftwareContext::createNinePatchNode()
-{
- return new QSGSoftwareNinePatchNode();
-}
-
QSGLayer *QSGSoftwareContext::createLayer(QSGRenderContext *renderContext)
{
return new QSGSoftwareLayer(renderContext);
@@ -148,7 +138,8 @@ void QSGSoftwareRenderContext::initializeIfNeeded()
void QSGSoftwareRenderContext::invalidate()
{
- QSGRenderContext::invalidate();
+ m_sg->renderContextInvalidated(this);
+ emit invalidated();
}
QSGTexture *QSGSoftwareRenderContext::createTexture(const QImage &image, uint flags) const
@@ -167,12 +158,37 @@ void QSGSoftwareRenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo)
renderer->renderScene(fbo);
}
+int QSGSoftwareRenderContext::maxTextureSize() const
+{
+ return 2048;
+}
+
QSGRendererInterface *QSGSoftwareContext::rendererInterface(QSGRenderContext *renderContext)
{
Q_UNUSED(renderContext);
return this;
}
+QSGRectangleNode *QSGSoftwareContext::createRectangleNode()
+{
+ return new QSGSoftwareRectangleNode;
+}
+
+QSGImageNode *QSGSoftwareContext::createImageNode()
+{
+ return new QSGSoftwareImageNode;
+}
+
+QSGNinePatchNode *QSGSoftwareContext::createNinePatchNode()
+{
+ return new QSGSoftwareNinePatchNode;
+}
+
+QSGSpriteNode *QSGSoftwareContext::createSpriteNode()
+{
+ return new QSGSoftwareSpriteNode;
+}
+
QSGRendererInterface::GraphicsApi QSGSoftwareContext::graphicsApi() const
{
return Software;
@@ -193,4 +209,12 @@ QSGRendererInterface::ShaderSourceTypes QSGSoftwareContext::shaderSourceType() c
return 0;
}
+void *QSGSoftwareContext::getResource(QQuickWindow *window, Resource resource) const
+{
+ if (resource == Painter && window && window->isSceneGraphInitialized())
+ return static_cast<QSGSoftwareRenderContext *>(QQuickWindowPrivate::get(window)->context)->m_activePainter;
+
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h
index 992f6f5677..dcc137b4b4 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h
@@ -75,8 +75,10 @@ public:
void renderNextFrame(QSGRenderer *renderer, uint fbo) override;
QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const override;
QSGRenderer *createRenderer() override;
+ int maxTextureSize() const override;
bool m_initialized;
+ QPainter *m_activePainter;
};
class QSGSoftwareContext : public QSGContext, public QSGRendererInterface
@@ -86,19 +88,23 @@ public:
explicit QSGSoftwareContext(QObject *parent = nullptr);
QSGRenderContext *createRenderContext() override { return new QSGSoftwareRenderContext(this); }
- QSGRectangleNode *createRectangleNode() override;
- QSGImageNode *createImageNode() override;
+ QSGInternalRectangleNode *createInternalRectangleNode() override;
+ QSGInternalImageNode *createInternalImageNode() override;
QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override;
QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override;
- QSGNinePatchNode *createNinePatchNode() override;
QSGLayer *createLayer(QSGRenderContext *renderContext) override;
QSurfaceFormat defaultSurfaceFormat() const override;
QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
+ QSGRectangleNode *createRectangleNode() override;
+ QSGImageNode *createImageNode() override;
+ QSGNinePatchNode *createNinePatchNode() override;
+ QSGSpriteNode *createSpriteNode() override;
GraphicsApi graphicsApi() const override;
ShaderType shaderType() const override;
ShaderCompilationTypes shaderCompilationType() const override;
ShaderSourceTypes shaderSourceType() const override;
+ void *getResource(QQuickWindow *window, Resource resource) const override;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp
index 7dadc1d3d4..10291b9cb5 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qsgsoftwareimagenode_p.h"
+#include "qsgsoftwareinternalimagenode_p.h"
#include "qsgsoftwarepixmaptexture_p.h"
#include "qsgsoftwarelayer_p.h"
@@ -315,7 +315,7 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin
} // QSGSoftwareHelpers namespace
-QSGSoftwareImageNode::QSGSoftwareImageNode()
+QSGSoftwareInternalImageNode::QSGSoftwareInternalImageNode()
: m_innerSourceRect(0, 0, 1, 1)
, m_subSourceRect(0, 0, 1, 1)
, m_texture(0)
@@ -330,7 +330,7 @@ QSGSoftwareImageNode::QSGSoftwareImageNode()
}
-void QSGSoftwareImageNode::setTargetRect(const QRectF &rect)
+void QSGSoftwareInternalImageNode::setTargetRect(const QRectF &rect)
{
if (rect == m_targetRect)
return;
@@ -338,7 +338,7 @@ void QSGSoftwareImageNode::setTargetRect(const QRectF &rect)
markDirty(DirtyGeometry);
}
-void QSGSoftwareImageNode::setInnerTargetRect(const QRectF &rect)
+void QSGSoftwareInternalImageNode::setInnerTargetRect(const QRectF &rect)
{
if (rect == m_innerTargetRect)
return;
@@ -346,7 +346,7 @@ void QSGSoftwareImageNode::setInnerTargetRect(const QRectF &rect)
markDirty(DirtyGeometry);
}
-void QSGSoftwareImageNode::setInnerSourceRect(const QRectF &rect)
+void QSGSoftwareInternalImageNode::setInnerSourceRect(const QRectF &rect)
{
if (rect == m_innerSourceRect)
return;
@@ -354,7 +354,7 @@ void QSGSoftwareImageNode::setInnerSourceRect(const QRectF &rect)
markDirty(DirtyGeometry);
}
-void QSGSoftwareImageNode::setSubSourceRect(const QRectF &rect)
+void QSGSoftwareInternalImageNode::setSubSourceRect(const QRectF &rect)
{
if (rect == m_subSourceRect)
return;
@@ -362,16 +362,14 @@ void QSGSoftwareImageNode::setSubSourceRect(const QRectF &rect)
markDirty(DirtyGeometry);
}
-void QSGSoftwareImageNode::setTexture(QSGTexture *texture)
+void QSGSoftwareInternalImageNode::setTexture(QSGTexture *texture)
{
- if (m_texture != texture) {
- m_texture = texture;
- m_cachedMirroredPixmapIsDirty = true;
- markDirty(DirtyMaterial);
- }
+ m_texture = texture;
+ m_cachedMirroredPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
}
-void QSGSoftwareImageNode::setMirror(bool mirror)
+void QSGSoftwareInternalImageNode::setMirror(bool mirror)
{
if (m_mirror != mirror) {
m_mirror = mirror;
@@ -380,11 +378,11 @@ void QSGSoftwareImageNode::setMirror(bool mirror)
}
}
-void QSGSoftwareImageNode::setMipmapFiltering(QSGTexture::Filtering /*filtering*/)
+void QSGSoftwareInternalImageNode::setMipmapFiltering(QSGTexture::Filtering /*filtering*/)
{
}
-void QSGSoftwareImageNode::setFiltering(QSGTexture::Filtering filtering)
+void QSGSoftwareInternalImageNode::setFiltering(QSGTexture::Filtering filtering)
{
bool smooth = (filtering == QSGTexture::Linear);
if (smooth == m_smooth)
@@ -394,7 +392,7 @@ void QSGSoftwareImageNode::setFiltering(QSGTexture::Filtering filtering)
markDirty(DirtyMaterial);
}
-void QSGSoftwareImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
+void QSGSoftwareInternalImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
{
bool tileHorizontal = (wrapMode == QSGTexture::Repeat);
if (tileHorizontal == m_tileHorizontal)
@@ -404,7 +402,7 @@ void QSGSoftwareImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
markDirty(DirtyMaterial);
}
-void QSGSoftwareImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
+void QSGSoftwareInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
{
bool tileVertical = (wrapMode == QSGTexture::Repeat);
if (tileVertical == m_tileVertical)
@@ -414,7 +412,7 @@ void QSGSoftwareImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
markDirty(DirtyMaterial);
}
-void QSGSoftwareImageNode::update()
+void QSGSoftwareInternalImageNode::update()
{
if (m_cachedMirroredPixmapIsDirty) {
if (m_mirror) {
@@ -428,7 +426,7 @@ void QSGSoftwareImageNode::update()
}
}
-void QSGSoftwareImageNode::preprocess()
+void QSGSoftwareInternalImageNode::preprocess()
{
bool doDirty = false;
QSGLayer *t = qobject_cast<QSGLayer *>(m_texture);
@@ -452,7 +450,7 @@ static Qt::TileRule getTileRule(qreal factor)
}
-void QSGSoftwareImageNode::paint(QPainter *painter)
+void QSGSoftwareInternalImageNode::paint(QPainter *painter)
{
painter->setRenderHint(QPainter::SmoothPixmapTransform, m_smooth);
@@ -485,12 +483,12 @@ void QSGSoftwareImageNode::paint(QPainter *painter)
}
}
-QRectF QSGSoftwareImageNode::rect() const
+QRectF QSGSoftwareInternalImageNode::rect() const
{
return m_targetRect;
}
-const QPixmap &QSGSoftwareImageNode::pixmap() const
+const QPixmap &QSGSoftwareInternalImageNode::pixmap() const
{
if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture*>(m_texture)) {
return pt->pixmap();
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h
index e42f616757..f21667fdf7 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QSGSOFTWAREIMAGENODE_H
-#define QSGSOFTWAREIMAGENODE_H
+#ifndef QSGSOFTWAREINTERNALIMAGENODE_H
+#define QSGSOFTWAREINTERNALIMAGENODE_H
//
// W A R N I N G
@@ -101,10 +101,10 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin
} // QSGSoftwareHelpers namespace
-class QSGSoftwareImageNode : public QSGImageNode
+class QSGSoftwareInternalImageNode : public QSGInternalImageNode
{
public:
- QSGSoftwareImageNode();
+ QSGSoftwareInternalImageNode();
void setTargetRect(const QRectF &rect) override;
void setInnerTargetRect(const QRectF &rect) override;
@@ -144,4 +144,4 @@ private:
QT_END_NAMESPACE
-#endif // QSGSOFTWAREIMAGENODE_H
+#endif // QSGSOFTWAREINTERNALIMAGENODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp
index 7672b14371..f6898b3879 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp
@@ -37,14 +37,14 @@
**
****************************************************************************/
-#include "qsgsoftwarerectanglenode_p.h"
+#include "qsgsoftwareinternalrectanglenode_p.h"
#include <qmath.h>
#include <QtGui/QPainter>
QT_BEGIN_NAMESPACE
-QSGSoftwareRectangleNode::QSGSoftwareRectangleNode()
+QSGSoftwareInternalRectangleNode::QSGSoftwareInternalRectangleNode()
: m_penWidth(0)
, m_radius(0)
, m_cornerPixmapIsDirty(true)
@@ -56,7 +56,7 @@ QSGSoftwareRectangleNode::QSGSoftwareRectangleNode()
setGeometry((QSGGeometry*)1);
}
-void QSGSoftwareRectangleNode::setRect(const QRectF &rect)
+void QSGSoftwareInternalRectangleNode::setRect(const QRectF &rect)
{
QRect alignedRect = rect.toAlignedRect();
if (m_rect != alignedRect) {
@@ -65,7 +65,7 @@ void QSGSoftwareRectangleNode::setRect(const QRectF &rect)
}
}
-void QSGSoftwareRectangleNode::setColor(const QColor &color)
+void QSGSoftwareInternalRectangleNode::setColor(const QColor &color)
{
if (m_color != color) {
m_color = color;
@@ -74,7 +74,7 @@ void QSGSoftwareRectangleNode::setColor(const QColor &color)
}
}
-void QSGSoftwareRectangleNode::setPenColor(const QColor &color)
+void QSGSoftwareInternalRectangleNode::setPenColor(const QColor &color)
{
if (m_penColor != color) {
m_penColor = color;
@@ -83,7 +83,7 @@ void QSGSoftwareRectangleNode::setPenColor(const QColor &color)
}
}
-void QSGSoftwareRectangleNode::setPenWidth(qreal width)
+void QSGSoftwareInternalRectangleNode::setPenWidth(qreal width)
{
if (m_penWidth != width) {
m_penWidth = width;
@@ -113,11 +113,11 @@ static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGrad
return newStop;
}
-void QSGSoftwareRectangleNode::setGradientStops(const QGradientStops &stops)
+void QSGSoftwareInternalRectangleNode::setGradientStops(const QGradientStops &stops)
{
//normalize stops
bool needsNormalization = false;
- foreach (const QGradientStop &stop, stops) {
+ for (const QGradientStop &stop : qAsConst(stops)) {
if (stop.first < 0.0 || stop.first > 1.0) {
needsNormalization = true;
continue;
@@ -186,7 +186,7 @@ void QSGSoftwareRectangleNode::setGradientStops(const QGradientStops &stops)
markDirty(DirtyMaterial);
}
-void QSGSoftwareRectangleNode::setRadius(qreal radius)
+void QSGSoftwareInternalRectangleNode::setRadius(qreal radius)
{
if (m_radius != radius) {
m_radius = radius;
@@ -195,11 +195,11 @@ void QSGSoftwareRectangleNode::setRadius(qreal radius)
}
}
-void QSGSoftwareRectangleNode::setAligned(bool /*aligned*/)
+void QSGSoftwareInternalRectangleNode::setAligned(bool /*aligned*/)
{
}
-void QSGSoftwareRectangleNode::update()
+void QSGSoftwareInternalRectangleNode::update()
{
if (!m_penWidth || m_penColor == Qt::transparent) {
m_pen = Qt::NoPen;
@@ -223,7 +223,7 @@ void QSGSoftwareRectangleNode::update()
}
}
-void QSGSoftwareRectangleNode::paint(QPainter *painter)
+void QSGSoftwareInternalRectangleNode::paint(QPainter *painter)
{
//We can only check for a device pixel ratio change when we know what
//paint device is being used.
@@ -265,7 +265,7 @@ void QSGSoftwareRectangleNode::paint(QPainter *painter)
}
-bool QSGSoftwareRectangleNode::isOpaque() const
+bool QSGSoftwareInternalRectangleNode::isOpaque() const
{
if (m_radius > 0.0f)
return false;
@@ -274,7 +274,7 @@ bool QSGSoftwareRectangleNode::isOpaque() const
if (m_penWidth > 0.0f && m_penColor.alpha() < 255)
return false;
if (m_stops.count() > 0) {
- foreach (QGradientStop stop, m_stops) {
+ for (const QGradientStop &stop : qAsConst(m_stops)) {
if (stop.second.alpha() < 255)
return false;
}
@@ -283,13 +283,13 @@ bool QSGSoftwareRectangleNode::isOpaque() const
return true;
}
-QRectF QSGSoftwareRectangleNode::rect() const
+QRectF QSGSoftwareInternalRectangleNode::rect() const
{
//TODO: double check that this is correct.
return m_rect;
}
-void QSGSoftwareRectangleNode::paintRectangle(QPainter *painter, const QRect &rect)
+void QSGSoftwareInternalRectangleNode::paintRectangle(QPainter *painter, const QRect &rect)
{
//Radius should never exceeds half of the width or half of the height
int radius = qFloor(qMin(qMin(rect.width(), rect.height()) * 0.5, m_radius));
@@ -411,7 +411,7 @@ void QSGSoftwareRectangleNode::paintRectangle(QPainter *painter, const QRect &re
painter->setRenderHints(previousRenderHints);
}
-void QSGSoftwareRectangleNode::generateCornerPixmap()
+void QSGSoftwareInternalRectangleNode::generateCornerPixmap()
{
//Generate new corner Pixmap
int radius = qFloor(qMin(qMin(m_rect.width(), m_rect.height()) * 0.5, m_radius));
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h
index 9cc0823325..f363e279e1 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QSGSOFTWARERECTANGLENODE_H
-#define QSGSOFTWARERECTANGLENODE_H
+#ifndef QSGSOFTWAREINTERNALRECTANGLENODE_H
+#define QSGSOFTWAREINTERNALRECTANGLENODE_H
//
// W A R N I N G
@@ -59,10 +59,10 @@
QT_BEGIN_NAMESPACE
-class QSGSoftwareRectangleNode : public QSGRectangleNode
+class QSGSoftwareInternalRectangleNode : public QSGInternalRectangleNode
{
public:
- QSGSoftwareRectangleNode();
+ QSGSoftwareInternalRectangleNode();
void setRect(const QRectF &rect) override;
void setColor(const QColor &color) override;
@@ -100,4 +100,4 @@ private:
QT_END_NAMESPACE
-#endif // QSGSOFTWARERECTANGLENODE_H
+#endif // QSGSOFTWAREINTERNALRECTANGLENODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
index 304106a84d..f8c1a3d90b 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qsgsoftwarepixmaprenderer_p.h"
+#include "qsgsoftwarecontext_p.h"
#include <QtQuick/QSGSimpleRectNode>
@@ -84,6 +85,9 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target)
QPainter painter(target);
painter.setRenderHint(QPainter::Antialiasing);
painter.setWindow(m_projectionRect);
+ auto rc = static_cast<QSGSoftwareRenderContext *>(context());
+ QPainter *prevPainter = rc->m_activePainter;
+ rc->m_activePainter = &painter;
renderTimer.start();
buildRenderList();
@@ -100,6 +104,7 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target)
QRegion paintedRegion = renderNodes(&painter);
qint64 renderTime = renderTimer.elapsed();
+ rc->m_activePainter = prevPainter;
qCDebug(lcPixmapRenderer) << "pixmapRender" << paintedRegion << buildRenderListTime << optimizeRenderListTime << renderTime;
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp
index 36ff1f2229..1fa5234377 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp
@@ -37,12 +37,99 @@
**
****************************************************************************/
-#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepublicnodes_p.h"
#include "qsgsoftwarepixmaptexture_p.h"
-#include "qsgsoftwareimagenode_p.h"
+#include "qsgsoftwareinternalimagenode_p.h"
QT_BEGIN_NAMESPACE
+QSGSoftwareRectangleNode::QSGSoftwareRectangleNode()
+ : m_color(QColor(255, 255, 255))
+{
+ setMaterial((QSGMaterial*)1);
+ setGeometry((QSGGeometry*)1);
+}
+
+void QSGSoftwareRectangleNode::paint(QPainter *painter)
+{
+ painter->fillRect(m_rect, m_color);
+}
+
+QSGSoftwareImageNode::QSGSoftwareImageNode()
+ : m_texture(nullptr),
+ m_owns(false),
+ m_filtering(QSGTexture::None),
+ m_transformMode(NoTransform),
+ m_cachedMirroredPixmapIsDirty(false)
+{
+ setMaterial((QSGMaterial*)1);
+ setGeometry((QSGGeometry*)1);
+}
+
+QSGSoftwareImageNode::~QSGSoftwareImageNode()
+{
+ if (m_owns)
+ delete m_texture;
+}
+
+void QSGSoftwareImageNode::setTexture(QSGTexture *texture)
+{
+ m_texture = texture; markDirty(DirtyMaterial);
+ m_cachedMirroredPixmapIsDirty = true;
+}
+
+void QSGSoftwareImageNode::setTextureCoordinatesTransform(QSGImageNode::TextureCoordinatesTransformMode transformNode)
+{
+ if (m_transformMode == transformNode)
+ return;
+
+ m_transformMode = transformNode;
+ m_cachedMirroredPixmapIsDirty = true;
+
+ markDirty(DirtyGeometry);
+}
+
+void QSGSoftwareImageNode::paint(QPainter *painter)
+{
+ if (m_cachedMirroredPixmapIsDirty)
+ updateCachedMirroredPixmap();
+
+ painter->setRenderHint(QPainter::SmoothPixmapTransform, (m_filtering == QSGTexture::Linear));
+
+ if (!m_cachedPixmap.isNull()) {
+ painter->drawPixmap(m_rect, m_cachedPixmap, m_sourceRect);
+ } else if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(m_texture)) {
+ const QPixmap &pm = pt->pixmap();
+ painter->drawPixmap(m_rect, pm, m_sourceRect);
+ } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(m_texture)) {
+ const QImage &im = pt->image();
+ painter->drawImage(m_rect, im, m_sourceRect);
+ }
+}
+
+void QSGSoftwareImageNode::updateCachedMirroredPixmap()
+{
+ if (m_transformMode == NoTransform) {
+ m_cachedPixmap = QPixmap();
+ } else {
+
+ if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(m_texture)) {
+ QTransform mirrorTransform;
+ if (m_transformMode.testFlag(MirrorVertically))
+ mirrorTransform = mirrorTransform.scale(1, -1);
+ if (m_transformMode.testFlag(MirrorHorizontally))
+ mirrorTransform = mirrorTransform.scale(-1, 1);
+ m_cachedPixmap = pt->pixmap().transformed(mirrorTransform);
+ } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(m_texture)) {
+ m_cachedPixmap = QPixmap::fromImage(pt->image().mirrored(m_transformMode.testFlag(MirrorHorizontally), m_transformMode.testFlag(MirrorVertically)));
+ } else {
+ m_cachedPixmap = QPixmap();
+ }
+ }
+
+ m_cachedMirroredPixmapIsDirty = false;
+}
+
QSGSoftwareNinePatchNode::QSGSoftwareNinePatchNode()
{
setMaterial((QSGMaterial*)1);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h
new file mode 100644
index 0000000000..9f1913205b
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWAREPUBLICNODES_H
+#define QSGSOFTWAREPUBLICNODES_H
+
+#include <QtQuick/qsgrectanglenode.h>
+#include <QtQuick/qsgimagenode.h>
+#include <QtQuick/qsgninepatchnode.h>
+#include <QtGui/qpixmap.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwareRectangleNode : public QSGRectangleNode
+{
+public:
+ QSGSoftwareRectangleNode();
+
+ void setRect(const QRectF &rect) override { m_rect = rect; markDirty(DirtyMaterial); }
+ QRectF rect() const override { return m_rect; }
+
+ void setColor(const QColor &color) override { m_color = color; markDirty(DirtyMaterial); }
+ QColor color() const override { return m_color; }
+
+ void paint(QPainter *painter);
+
+private:
+ QRectF m_rect;
+ QColor m_color;
+};
+
+class QSGSoftwareImageNode : public QSGImageNode
+{
+public:
+ QSGSoftwareImageNode();
+ ~QSGSoftwareImageNode();
+
+ void setRect(const QRectF &rect) override { m_rect = rect; markDirty(DirtyMaterial); }
+ QRectF rect() const override { return m_rect; }
+
+ void setSourceRect(const QRectF &r) override { m_sourceRect = r; }
+ QRectF sourceRect() const override { return m_sourceRect; }
+
+ void setTexture(QSGTexture *texture) override;
+ QSGTexture *texture() const override { return m_texture; }
+
+ void setFiltering(QSGTexture::Filtering filtering) override { m_filtering = filtering; markDirty(DirtyMaterial); }
+ QSGTexture::Filtering filtering() const override { return m_filtering; }
+
+ void setMipmapFiltering(QSGTexture::Filtering) override { }
+ QSGTexture::Filtering mipmapFiltering() const override { return QSGTexture::None; }
+
+ void setTextureCoordinatesTransform(TextureCoordinatesTransformMode transformNode) override;
+ TextureCoordinatesTransformMode textureCoordinatesTransform() const override { return m_transformMode; }
+
+ void setOwnsTexture(bool owns) override { m_owns = owns; }
+ bool ownsTexture() const override { return m_owns; }
+
+ void paint(QPainter *painter);
+
+private:
+ void updateCachedMirroredPixmap();
+
+ QPixmap m_cachedPixmap;
+ QSGTexture *m_texture;
+ QRectF m_rect;
+ QRectF m_sourceRect;
+ bool m_owns;
+ QSGTexture::Filtering m_filtering;
+ TextureCoordinatesTransformMode m_transformMode;
+ bool m_cachedMirroredPixmapIsDirty;
+};
+
+class QSGSoftwareNinePatchNode : public QSGNinePatchNode
+{
+public:
+ QSGSoftwareNinePatchNode();
+
+ void setTexture(QSGTexture *texture) override;
+ void setBounds(const QRectF &bounds) override;
+ void setDevicePixelRatio(qreal ratio) override;
+ void setPadding(qreal left, qreal top, qreal right, qreal bottom) override;
+ void update() override;
+
+ void paint(QPainter *painter);
+
+ QRectF bounds() const;
+
+private:
+ QPixmap m_pixmap;
+ QRectF m_bounds;
+ qreal m_pixelRatio;
+ QMargins m_margins;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWAREPUBLICNODES_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
index 063242c63b..7b9e749532 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
@@ -39,15 +39,17 @@
#include "qsgsoftwarerenderablenode_p.h"
-#include "qsgsoftwareimagenode_p.h"
-#include "qsgsoftwarerectanglenode_p.h"
+#include "qsgsoftwareinternalimagenode_p.h"
+#include "qsgsoftwareinternalrectanglenode_p.h"
#include "qsgsoftwareglyphnode_p.h"
-#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepublicnodes_p.h"
#include "qsgsoftwarepainternode_p.h"
#include "qsgsoftwarepixmaptexture_p.h"
+#include "qsgsoftwarespritenode_p.h"
-#include <QtQuick/QSGSimpleRectNode>
-#include <QtQuick/qsgsimpletexturenode.h>
+#include <qsgsimplerectnode.h>
+#include <qsgsimpletexturenode.h>
+#include <private/qsgrendernode_p.h>
#include <private/qsgtexture_p.h>
Q_LOGGING_CATEGORY(lcRenderable, "qt.scenegraph.softwarecontext.renderable")
@@ -58,6 +60,7 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod
: m_nodeType(type)
, m_isOpaque(true)
, m_isDirty(true)
+ , m_hasClipRegion(false)
, m_opacity(1.0f)
{
switch (m_nodeType) {
@@ -68,13 +71,13 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod
m_handle.simpleTextureNode = static_cast<QSGSimpleTextureNode*>(node);
break;
case QSGSoftwareRenderableNode::Image:
- m_handle.imageNode = static_cast<QSGSoftwareImageNode*>(node);
+ m_handle.imageNode = static_cast<QSGSoftwareInternalImageNode*>(node);
break;
case QSGSoftwareRenderableNode::Painter:
m_handle.painterNode = static_cast<QSGSoftwarePainterNode*>(node);
break;
case QSGSoftwareRenderableNode::Rectangle:
- m_handle.rectangleNode = static_cast<QSGSoftwareRectangleNode*>(node);
+ m_handle.rectangleNode = static_cast<QSGSoftwareInternalRectangleNode*>(node);
break;
case QSGSoftwareRenderableNode::Glyph:
m_handle.glpyhNode = static_cast<QSGSoftwareGlyphNode*>(node);
@@ -82,6 +85,18 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod
case QSGSoftwareRenderableNode::NinePatch:
m_handle.ninePatchNode = static_cast<QSGSoftwareNinePatchNode*>(node);
break;
+ case QSGSoftwareRenderableNode::SimpleRectangle:
+ m_handle.simpleRectangleNode = static_cast<QSGRectangleNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::SimpleImage:
+ m_handle.simpleImageNode = static_cast<QSGImageNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::SpriteNode:
+ m_handle.spriteNode = static_cast<QSGSoftwareSpriteNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::RenderNode:
+ m_handle.renderNode = static_cast<QSGRenderNode*>(node);
+ break;
case QSGSoftwareRenderableNode::Invalid:
m_handle.simpleRectNode = nullptr;
break;
@@ -151,14 +166,46 @@ void QSGSoftwareRenderableNode::update()
boundingRect = m_handle.ninePatchNode->bounds().toRect();
break;
+ case QSGSoftwareRenderableNode::SimpleRectangle:
+ if (m_handle.simpleRectangleNode->color().alpha() == 255 && !m_transform.isRotating())
+ m_isOpaque = true;
+ else
+ m_isOpaque = false;
+
+ boundingRect = m_handle.simpleRectangleNode->rect().toRect();
+ break;
+ case QSGSoftwareRenderableNode::SimpleImage:
+ if (!m_handle.simpleImageNode->texture()->hasAlphaChannel() && !m_transform.isRotating())
+ m_isOpaque = true;
+ else
+ m_isOpaque = false;
+
+ boundingRect = m_handle.simpleImageNode->rect().toRect();
+ break;
+ case QSGSoftwareRenderableNode::SpriteNode:
+ m_isOpaque = m_handle.spriteNode->isOpaque();
+ boundingRect = m_handle.spriteNode->rect().toRect();
+ break;
+ case QSGSoftwareRenderableNode::RenderNode:
+ if (m_handle.renderNode->flags().testFlag(QSGRenderNode::OpaqueRendering) && !m_transform.isRotating())
+ m_isOpaque = true;
+ else
+ m_isOpaque = false;
+
+ boundingRect = m_handle.renderNode->rect().toRect();
+ break;
default:
break;
}
m_boundingRect = m_transform.mapRect(boundingRect);
- if (m_clipRegion.rectCount() == 1) {
- m_boundingRect = m_boundingRect.intersected(m_clipRegion.rects().first());
+ if (m_hasClipRegion && m_clipRegion.rectCount() <= 1) {
+ // If there is a clipRegion, and it is empty, the item wont be rendered
+ if (m_clipRegion.isEmpty())
+ m_boundingRect = QRect();
+ else
+ m_boundingRect = m_boundingRect.intersected(m_clipRegion.rects().first());
}
// Overrides
@@ -168,15 +215,56 @@ void QSGSoftwareRenderableNode::update()
m_dirtyRegion = QRegion(m_boundingRect);
}
+struct RenderNodeState : public QSGRenderNode::RenderState
+{
+ const QMatrix4x4 *projectionMatrix() const override { return &ident; }
+ QRect scissorRect() const override { return QRect(); }
+ bool scissorEnabled() const override { return false; }
+ int stencilValue() const override { return 0; }
+ bool stencilEnabled() const override { return false; }
+ const QRegion *clipRegion() const override { return &cr; }
+ QMatrix4x4 ident;
+ QRegion cr;
+};
+
QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaquePainting)
{
Q_ASSERT(painter);
// Check for don't paint conditions
- if (!m_isDirty || qFuzzyIsNull(m_opacity) || m_dirtyRegion.isEmpty()) {
- m_isDirty = false;
- m_dirtyRegion = QRegion();
- return QRegion();
+ if (m_nodeType != RenderNode) {
+ if (!m_isDirty || qFuzzyIsNull(m_opacity) || m_dirtyRegion.isEmpty()) {
+ m_isDirty = false;
+ m_dirtyRegion = QRegion();
+ return QRegion();
+ }
+ } else {
+ if (!m_isDirty || qFuzzyIsNull(m_opacity)) {
+ m_isDirty = false;
+ m_dirtyRegion = QRegion();
+ return QRegion();
+ } else {
+ QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(m_handle.renderNode);
+ QMatrix4x4 m = m_transform;
+ rd->m_matrix = &m;
+ rd->m_opacity = m_opacity;
+ RenderNodeState rs;
+ rs.cr = m_clipRegion;
+
+ const QRect br = m_handle.renderNode->flags().testFlag(QSGRenderNode::BoundedRectRendering)
+ ? m_boundingRect :
+ QRect(0, 0, painter->device()->width(), painter->device()->height());
+
+ painter->save();
+ painter->setClipRegion(br, Qt::ReplaceClip);
+ m_handle.renderNode->render(&rs);
+ painter->restore();
+
+ m_previousDirtyRegion = QRegion(br);
+ m_isDirty = false;
+ m_dirtyRegion = QRegion();
+ return br;
+ }
}
painter->save();
@@ -201,10 +289,10 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu
QSGTexture *texture = m_handle.simpleTextureNode->texture();
if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(texture)) {
const QPixmap &pm = pt->pixmap();
- painter->drawPixmap(m_handle.simpleTextureNode->rect(), pm, QRectF(0, 0, pm.width(), pm.height()));
+ painter->drawPixmap(m_handle.simpleTextureNode->rect(), pm, m_handle.simpleTextureNode->sourceRect());
} else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(texture)) {
const QImage &im = pt->image();
- painter->drawImage(m_handle.simpleTextureNode->rect(), im, QRectF(0, 0, im.width(), im.height()));
+ painter->drawImage(m_handle.simpleTextureNode->rect(), im, m_handle.simpleTextureNode->sourceRect());
}
}
break;
@@ -223,6 +311,15 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu
case QSGSoftwareRenderableNode::NinePatch:
m_handle.ninePatchNode->paint(painter);
break;
+ case QSGSoftwareRenderableNode::SimpleRectangle:
+ static_cast<QSGSoftwareRectangleNode *>(m_handle.simpleRectangleNode)->paint(painter);
+ break;
+ case QSGSoftwareRenderableNode::SimpleImage:
+ static_cast<QSGSoftwareImageNode *>(m_handle.simpleImageNode)->paint(painter);
+ break;
+ case QSGSoftwareRenderableNode::SpriteNode:
+ static_cast<QSGSoftwareSpriteNode *>(m_handle.spriteNode)->paint(painter);
+ break;
default:
break;
}
@@ -256,12 +353,13 @@ void QSGSoftwareRenderableNode::setTransform(const QTransform &transform)
update();
}
-void QSGSoftwareRenderableNode::setClipRegion(const QRegion &clipRect)
+void QSGSoftwareRenderableNode::setClipRegion(const QRegion &clipRect, bool hasClipRegion)
{
- if (m_clipRegion == clipRect)
+ if (m_clipRegion == clipRect && m_hasClipRegion == hasClipRegion)
return;
m_clipRegion = clipRect;
+ m_hasClipRegion = hasClipRegion;
update();
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
index 9a5e0a5683..0626b1e657 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
@@ -54,17 +54,21 @@
#include <QtGui/QRegion>
#include <QtCore/QRect>
#include <QtGui/QTransform>
+#include <QtQuick/qsgrectanglenode.h>
+#include <QtQuick/qsgimagenode.h>
+#include <QtQuick/qsgninepatchnode.h>
QT_BEGIN_NAMESPACE
-class QSGNode;
class QSGSimpleRectNode;
class QSGSimpleTextureNode;
-class QSGSoftwareImageNode;
+class QSGSoftwareInternalImageNode;
class QSGSoftwarePainterNode;
-class QSGSoftwareRectangleNode;
+class QSGSoftwareInternalRectangleNode;
class QSGSoftwareGlyphNode;
class QSGSoftwareNinePatchNode;
+class QSGSoftwareSpriteNode;
+class QSGRenderNode;
class QSGSoftwareRenderableNode
{
@@ -77,7 +81,11 @@ public:
Painter,
Rectangle,
Glyph,
- NinePatch
+ NinePatch,
+ SimpleRectangle,
+ SimpleImage,
+ SpriteNode,
+ RenderNode
};
QSGSoftwareRenderableNode(NodeType type, QSGNode *node);
@@ -93,7 +101,7 @@ public:
bool isDirtyRegionEmpty() const;
void setTransform(const QTransform &transform);
- void setClipRegion(const QRegion &clipRegion);
+ void setClipRegion(const QRegion &clipRegion, bool hasClipRegion = true);
void setOpacity(float opacity);
QTransform transform() const { return m_transform; }
QRegion clipRegion() const { return m_clipRegion; }
@@ -112,11 +120,15 @@ private:
union RenderableNodeHandle {
QSGSimpleRectNode *simpleRectNode;
QSGSimpleTextureNode *simpleTextureNode;
- QSGSoftwareImageNode *imageNode;
+ QSGSoftwareInternalImageNode *imageNode;
QSGSoftwarePainterNode *painterNode;
- QSGSoftwareRectangleNode *rectangleNode;
+ QSGSoftwareInternalRectangleNode *rectangleNode;
QSGSoftwareGlyphNode *glpyhNode;
QSGSoftwareNinePatchNode *ninePatchNode;
+ QSGRectangleNode *simpleRectangleNode;
+ QSGImageNode *simpleImageNode;
+ QSGSoftwareSpriteNode *spriteNode;
+ QSGRenderNode *renderNode;
};
const NodeType m_nodeType;
@@ -130,6 +142,7 @@ private:
QTransform m_transform;
QRegion m_clipRegion;
+ bool m_hasClipRegion;
float m_opacity;
QRect m_boundingRect;
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp
index 3d5fe21f7c..12dbf63353 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp
@@ -40,15 +40,16 @@
#include "qsgsoftwarerenderablenodeupdater_p.h"
#include "qsgabstractsoftwarerenderer_p.h"
-#include "qsgsoftwareimagenode_p.h"
-#include "qsgsoftwarerectanglenode_p.h"
+#include "qsgsoftwareinternalimagenode_p.h"
+#include "qsgsoftwareinternalrectanglenode_p.h"
#include "qsgsoftwareglyphnode_p.h"
-#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepublicnodes_p.h"
#include "qsgsoftwarepainternode_p.h"
#include "qsgsoftwarepixmaptexture_p.h"
-#include <QtQuick/QSGSimpleRectNode>
+#include <QtQuick/qsgsimplerectnode.h>
#include <QtQuick/qsgsimpletexturenode.h>
+#include <QtQuick/qsgrendernode.h>
QT_BEGIN_NAMESPACE
@@ -58,6 +59,7 @@ QSGSoftwareRenderableNodeUpdater::QSGSoftwareRenderableNodeUpdater(QSGAbstractSo
m_opacityState.push(1.0f);
// Invalid RectF by default for no clip
m_clipState.push(QRegion());
+ m_hasClip = false;
m_transformState.push(QTransform());
}
@@ -81,10 +83,13 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGTransformNode *)
bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node)
{
// Make sure to translate the clip rect into world coordinates
- if (m_clipState.top().isEmpty()) {
+ if (m_clipState.count() == 1) {
m_clipState.push(m_transformState.top().map(QRegion(node->clipRect().toRect())));
- } else
- m_clipState.push(m_transformState.top().map(QRegion(node->clipRect().toRect()).intersected(m_clipState.top())));
+ m_hasClip = true;
+ } else {
+ const QRegion transformedClipRect = m_transformState.top().map(QRegion(node->clipRect().toRect()));
+ m_clipState.push(transformedClipRect.intersected(m_clipState.top()));
+ }
m_stateMap[node] = currentState(node);
return true;
}
@@ -92,6 +97,8 @@ bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node)
void QSGSoftwareRenderableNodeUpdater::endVisit(QSGClipNode *)
{
m_clipState.pop();
+ if (m_clipState.count() == 1)
+ m_hasClip = false;
}
bool QSGSoftwareRenderableNodeUpdater::visit(QSGGeometryNode *node)
@@ -100,6 +107,12 @@ bool QSGSoftwareRenderableNodeUpdater::visit(QSGGeometryNode *node)
return updateRenderableNode(QSGSoftwareRenderableNode::SimpleRect, rectNode);
} else if (QSGSimpleTextureNode *tn = dynamic_cast<QSGSimpleTextureNode *>(node)) {
return updateRenderableNode(QSGSoftwareRenderableNode::SimpleTexture, tn);
+ } else if (QSGNinePatchNode *nn = dynamic_cast<QSGNinePatchNode *>(node)) {
+ return updateRenderableNode(QSGSoftwareRenderableNode::NinePatch, nn);
+ } else if (QSGRectangleNode *rn = dynamic_cast<QSGRectangleNode *>(node)) {
+ return updateRenderableNode(QSGSoftwareRenderableNode::SimpleRectangle, rn);
+ } else if (QSGImageNode *n = dynamic_cast<QSGImageNode *>(node)) {
+ return updateRenderableNode(QSGSoftwareRenderableNode::SimpleImage, n);
} else {
// We dont know, so skip
return false;
@@ -122,12 +135,12 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGOpacityNode *)
m_opacityState.pop();
}
-bool QSGSoftwareRenderableNodeUpdater::visit(QSGImageNode *node)
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGInternalImageNode *node)
{
return updateRenderableNode(QSGSoftwareRenderableNode::Image, node);
}
-void QSGSoftwareRenderableNodeUpdater::endVisit(QSGImageNode *)
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGInternalImageNode *)
{
}
@@ -140,12 +153,12 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGPainterNode *)
{
}
-bool QSGSoftwareRenderableNodeUpdater::visit(QSGRectangleNode *node)
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGInternalRectangleNode *node)
{
return updateRenderableNode(QSGSoftwareRenderableNode::Rectangle, node);
}
-void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRectangleNode *)
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGInternalRectangleNode *)
{
}
@@ -158,22 +171,32 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGGlyphNode *)
{
}
-bool QSGSoftwareRenderableNodeUpdater::visit(QSGNinePatchNode *node)
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGRootNode *node)
{
- return updateRenderableNode(QSGSoftwareRenderableNode::NinePatch, node);
+ m_stateMap[node] = currentState(node);
+ return true;
}
-void QSGSoftwareRenderableNodeUpdater::endVisit(QSGNinePatchNode *)
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRootNode *)
{
}
-bool QSGSoftwareRenderableNodeUpdater::visit(QSGRootNode *node)
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGSpriteNode *node)
{
- m_stateMap[node] = currentState(node);
- return true;
+ return updateRenderableNode(QSGSoftwareRenderableNode::SpriteNode, node);
}
-void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRootNode *)
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGSpriteNode *)
+{
+
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGRenderNode *node)
+{
+ return updateRenderableNode(QSGSoftwareRenderableNode::RenderNode, node);
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRenderNode *)
{
}
@@ -195,12 +218,13 @@ void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRem
m_opacityState.push(state.opacity);
m_transformState.push(state.transform);
m_clipState.push(state.clip);
-
+ m_hasClip = state.hasClip;
} else {
// There is no parent, and no previous parent, so likely a root node
m_opacityState.push(1.0f);
m_transformState.push(QTransform());
m_clipState.push(QRegion());
+ m_hasClip = false;
}
// If the node is being removed, then cleanup the state data
@@ -256,6 +280,13 @@ void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRem
visitChildren(node);
break;
}
+ case QSGNode::RenderNodeType: {
+ QSGRenderNode *r = static_cast<QSGRenderNode*>(node);
+ if (visit(r))
+ visitChildren(r);
+ endVisit(r);
+ break;
+ }
default:
Q_UNREACHABLE();
break;
@@ -267,6 +298,7 @@ QSGSoftwareRenderableNodeUpdater::NodeState QSGSoftwareRenderableNodeUpdater::cu
NodeState state;
state.opacity = m_opacityState.top();
state.clip = m_clipState.top();
+ state.hasClip = m_hasClip;
state.transform = m_transformState.top();
state.parent = node->parent();
return state;
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h
index 562d15769e..f204867236 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h
@@ -76,18 +76,20 @@ public:
void endVisit(QSGGeometryNode *) override;
bool visit(QSGOpacityNode *) override;
void endVisit(QSGOpacityNode *) override;
- bool visit(QSGImageNode *) override;
- void endVisit(QSGImageNode *) override;
+ bool visit(QSGInternalImageNode *) override;
+ void endVisit(QSGInternalImageNode *) override;
bool visit(QSGPainterNode *) override;
void endVisit(QSGPainterNode *) override;
- bool visit(QSGRectangleNode *) override;
- void endVisit(QSGRectangleNode *) override;
+ bool visit(QSGInternalRectangleNode *) override;
+ void endVisit(QSGInternalRectangleNode *) override;
bool visit(QSGGlyphNode *) override;
void endVisit(QSGGlyphNode *) override;
- bool visit(QSGNinePatchNode *) override;
- void endVisit(QSGNinePatchNode *) override;
bool visit(QSGRootNode *) override;
void endVisit(QSGRootNode *) override;
+ bool visit(QSGSpriteNode *) override;
+ void endVisit(QSGSpriteNode *) override;
+ bool visit(QSGRenderNode *) override;
+ void endVisit(QSGRenderNode *) override;
void updateNodes(QSGNode *node, bool isNodeRemoved = false);
@@ -95,6 +97,7 @@ private:
struct NodeState {
float opacity;
QRegion clip;
+ bool hasClip;
QTransform transform;
QSGNode *parent;
};
@@ -107,6 +110,7 @@ private:
QSGAbstractSoftwareRenderer *m_renderer;
QStack<float> m_opacityState;
QStack<QRegion> m_clipState;
+ bool m_hasClip;
QStack<QTransform> m_transformState;
QHash<QSGNode*,NodeState> m_stateMap;
};
@@ -124,7 +128,7 @@ bool QSGSoftwareRenderableNodeUpdater::updateRenderableNode(QSGSoftwareRenderabl
//Update the node
renderableNode->setTransform(m_transformState.top());
renderableNode->setOpacity(m_opacityState.top());
- renderableNode->setClipRegion(m_clipState.top());
+ renderableNode->setClipRegion(m_clipState.top(), m_hasClip);
renderableNode->update();
m_stateMap[node] = currentState(node);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
index ea00de7a66..cad826fb27 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
@@ -45,6 +45,7 @@
#include "qsgsoftwarerenderablenode_p.h"
#include <QtGui/QPaintDevice>
+#include <QtGui/QBackingStore>
#include <QElapsedTimer>
Q_LOGGING_CATEGORY(lcRenderer, "qt.scenegraph.softwarecontext.renderer")
@@ -53,6 +54,8 @@ QT_BEGIN_NAMESPACE
QSGSoftwareRenderer::QSGSoftwareRenderer(QSGRenderContext *context)
: QSGAbstractSoftwareRenderer(context)
+ , m_paintDevice(nullptr)
+ , m_backingStore(nullptr)
{
}
@@ -63,6 +66,18 @@ QSGSoftwareRenderer::~QSGSoftwareRenderer()
void QSGSoftwareRenderer::setCurrentPaintDevice(QPaintDevice *device)
{
m_paintDevice = device;
+ m_backingStore = nullptr;
+}
+
+QPaintDevice *QSGSoftwareRenderer::currentPaintDevice() const
+{
+ return m_paintDevice;
+}
+
+void QSGSoftwareRenderer::setBackingStore(QBackingStore *backingStore)
+{
+ m_backingStore = backingStore;
+ m_paintDevice = nullptr;
}
QRegion QSGSoftwareRenderer::flushRegion() const
@@ -82,18 +97,24 @@ void QSGSoftwareRenderer::renderScene(uint)
void QSGSoftwareRenderer::render()
{
- if (!m_paintDevice)
+ if (!m_paintDevice && !m_backingStore)
return;
+ // If there is a backingstore, set the current paint device
+ if (m_backingStore) {
+ // For HiDPI QBackingStores, the paint device is not valid
+ // until begin() has been called. See: QTBUG-55875
+ m_backingStore->beginPaint(QRegion());
+ m_paintDevice = m_backingStore->paintDevice();
+ m_backingStore->endPaint();
+ }
+
QElapsedTimer renderTimer;
setBackgroundColor(clearColor());
setBackgroundSize(QSize(m_paintDevice->width() / m_paintDevice->devicePixelRatio(),
m_paintDevice->height() / m_paintDevice->devicePixelRatio()));
- QPainter painter(m_paintDevice);
- painter.setRenderHint(QPainter::Antialiasing);
-
// Build Renderlist
// The renderlist is created by visiting each node in the tree and when a
// renderable node is reach, we find the coorosponding RenderableNode object
@@ -113,13 +134,31 @@ void QSGSoftwareRenderer::render()
// side effect of this is that additional nodes may need to be marked dirty to
// force a repaint. It is also important that any item that needs to be
// repainted only paints what is needed, via the use of clip regions.
- optimizeRenderList();
+ const QRegion updateRegion = optimizeRenderList();
qint64 optimizeRenderListTime = renderTimer.restart();
+ // If Rendering to a backingstore, prepare it to be updated
+ if (m_backingStore != nullptr) {
+ m_backingStore->beginPaint(updateRegion);
+ // It is possible that a QBackingStore's paintDevice() will change
+ // when begin() is called.
+ m_paintDevice = m_backingStore->paintDevice();
+ }
+
+ QPainter painter(m_paintDevice);
+ painter.setRenderHint(QPainter::Antialiasing);
+ auto rc = static_cast<QSGSoftwareRenderContext *>(context());
+ QPainter *prevPainter = rc->m_activePainter;
+ rc->m_activePainter = &painter;
+
// Render the contents Renderlist
m_flushRegion = renderNodes(&painter);
qint64 renderTime = renderTimer.elapsed();
+ if (m_backingStore != nullptr)
+ m_backingStore->endPaint();
+
+ rc->m_activePainter = prevPainter;
qCDebug(lcRenderer) << "render" << m_flushRegion << buildRenderListTime << optimizeRenderListTime << renderTime;
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h
index e2b8bcddca..bb28da4ca5 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h
@@ -56,6 +56,7 @@
QT_BEGIN_NAMESPACE
class QPaintDevice;
+class QBackingStore;
class Q_QUICK_PRIVATE_EXPORT QSGSoftwareRenderer : public QSGAbstractSoftwareRenderer
{
@@ -64,6 +65,8 @@ public:
virtual ~QSGSoftwareRenderer();
void setCurrentPaintDevice(QPaintDevice *device);
+ QPaintDevice *currentPaintDevice() const;
+ void setBackingStore(QBackingStore *backingStore);
QRegion flushRegion() const;
protected:
@@ -72,6 +75,7 @@ protected:
private:
QPaintDevice* m_paintDevice;
+ QBackingStore* m_backingStore;
QRegion m_flushRegion;
};
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp
index af81ff61c3..4e34517dad 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp
@@ -41,15 +41,16 @@
#include "qsgsoftwarerenderablenode_p.h"
#include "qsgabstractsoftwarerenderer_p.h"
-#include "qsgsoftwareimagenode_p.h"
-#include "qsgsoftwarerectanglenode_p.h"
+#include "qsgsoftwareinternalimagenode_p.h"
+#include "qsgsoftwareinternalrectanglenode_p.h"
#include "qsgsoftwareglyphnode_p.h"
-#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepublicnodes_p.h"
#include "qsgsoftwarepainternode_p.h"
#include "qsgsoftwarepixmaptexture_p.h"
-#include <QtQuick/QSGSimpleRectNode>
+#include <QtQuick/qsgsimplerectnode.h>
#include <QtQuick/qsgsimpletexturenode.h>
+#include <QtQuick/qsgrendernode.h>
QT_BEGIN_NAMESPACE
@@ -95,12 +96,12 @@ void QSGSoftwareRenderListBuilder::endVisit(QSGOpacityNode *)
{
}
-bool QSGSoftwareRenderListBuilder::visit(QSGImageNode *node)
+bool QSGSoftwareRenderListBuilder::visit(QSGInternalImageNode *node)
{
return addRenderableNode(node);
}
-void QSGSoftwareRenderListBuilder::endVisit(QSGImageNode *)
+void QSGSoftwareRenderListBuilder::endVisit(QSGInternalImageNode *)
{
}
@@ -113,12 +114,12 @@ void QSGSoftwareRenderListBuilder::endVisit(QSGPainterNode *)
{
}
-bool QSGSoftwareRenderListBuilder::visit(QSGRectangleNode *node)
+bool QSGSoftwareRenderListBuilder::visit(QSGInternalRectangleNode *node)
{
return addRenderableNode(node);
}
-void QSGSoftwareRenderListBuilder::endVisit(QSGRectangleNode *)
+void QSGSoftwareRenderListBuilder::endVisit(QSGInternalRectangleNode *)
{
}
@@ -131,21 +132,31 @@ void QSGSoftwareRenderListBuilder::endVisit(QSGGlyphNode *)
{
}
-bool QSGSoftwareRenderListBuilder::visit(QSGNinePatchNode *node)
+bool QSGSoftwareRenderListBuilder::visit(QSGRootNode *)
+{
+ return true;
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGRootNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGSpriteNode *node)
{
return addRenderableNode(node);
}
-void QSGSoftwareRenderListBuilder::endVisit(QSGNinePatchNode *)
+void QSGSoftwareRenderListBuilder::endVisit(QSGSpriteNode *)
{
+
}
-bool QSGSoftwareRenderListBuilder::visit(QSGRootNode *)
+bool QSGSoftwareRenderListBuilder::visit(QSGRenderNode *node)
{
- return true;
+ return addRenderableNode(node);
}
-void QSGSoftwareRenderListBuilder::endVisit(QSGRootNode *)
+void QSGSoftwareRenderListBuilder::endVisit(QSGRenderNode *)
{
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h
index 94b563564d..807cb7fdbe 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h
@@ -70,18 +70,20 @@ public:
void endVisit(QSGGeometryNode *) override;
bool visit(QSGOpacityNode *) override;
void endVisit(QSGOpacityNode *) override;
- bool visit(QSGImageNode *) override;
- void endVisit(QSGImageNode *) override;
+ bool visit(QSGInternalImageNode *) override;
+ void endVisit(QSGInternalImageNode *) override;
bool visit(QSGPainterNode *) override;
void endVisit(QSGPainterNode *) override;
- bool visit(QSGRectangleNode *) override;
- void endVisit(QSGRectangleNode *) override;
+ bool visit(QSGInternalRectangleNode *) override;
+ void endVisit(QSGInternalRectangleNode *) override;
bool visit(QSGGlyphNode *) override;
void endVisit(QSGGlyphNode *) override;
- bool visit(QSGNinePatchNode *) override;
- void endVisit(QSGNinePatchNode *) override;
bool visit(QSGRootNode *) override;
void endVisit(QSGRootNode *) override;
+ bool visit(QSGSpriteNode *) override;
+ void endVisit(QSGSpriteNode *) override;
+ bool visit(QSGRenderNode *) override;
+ void endVisit(QSGRenderNode *) override;
private:
bool addRenderableNode(QSGNode *node);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
index 5292e1371f..19a963b403 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
@@ -156,11 +156,9 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
//Tell the renderer about the windows backing store
auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer);
if (softwareRenderer)
- softwareRenderer->setCurrentPaintDevice(m_backingStores[window]->paintDevice());
+ softwareRenderer->setBackingStore(m_backingStores[window]);
- m_backingStores[window]->beginPaint(QRect(0, 0, window->width(), window->height()));
cd->renderSceneGraph(window->size());
- m_backingStores[window]->endPaint();
if (profileFrames)
renderTime = renderTimer.nsecsElapsed();
@@ -185,7 +183,7 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
if (QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled()) {
static QTime lastFrameTime = QTime::currentTime();
qCDebug(QSG_RASTER_LOG_TIME_RENDERLOOP,
- "Frame rendered with 'basic' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
+ "Frame rendered with 'software' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
int(swapTime / 1000000),
int(polishTime / 1000000),
int((syncTime - polishTime) / 1000000),
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp
new file mode 100644
index 0000000000..ba7bbc2d11
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarespritenode_p.h"
+#include "qsgsoftwarepixmaptexture_p.h"
+#include <QtGui/QPainter>
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareSpriteNode::QSGSoftwareSpriteNode()
+{
+ setMaterial((QSGMaterial*)1);
+ setGeometry((QSGGeometry*)1);
+}
+
+void QSGSoftwareSpriteNode::setTexture(QSGTexture *texture)
+{
+ m_texture = qobject_cast<QSGSoftwarePixmapTexture*>(texture);
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwareSpriteNode::setTime(float time)
+{
+ if (m_time != time) {
+ m_time = time;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareSpriteNode::setSourceA(const QPoint &source)
+{
+ if (m_sourceA != source) {
+ m_sourceA = source;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareSpriteNode::setSourceB(const QPoint &source)
+{
+ if (m_sourceB != source) {
+ m_sourceB = source;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareSpriteNode::setSpriteSize(const QSize &size)
+{
+ if (m_spriteSize != size) {
+ m_spriteSize = size;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareSpriteNode::setSheetSize(const QSize &size)
+{
+ if (m_sheetSize != size) {
+ m_sheetSize = size;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareSpriteNode::setSize(const QSizeF &size)
+{
+ if (m_size != size) {
+ m_size = size;
+ markDirty(DirtyGeometry);
+ }
+}
+
+void QSGSoftwareSpriteNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ Q_UNUSED(filtering);
+}
+
+void QSGSoftwareSpriteNode::update()
+{
+}
+
+void QSGSoftwareSpriteNode::paint(QPainter *painter)
+{
+ //Get the pixmap handle from the texture
+ if (!m_texture)
+ return;
+
+ const QPixmap &pixmap = m_texture->pixmap();
+
+ // XXX try to do some kind of interpolation between sourceA and sourceB using time
+ painter->drawPixmap(QRectF(0, 0, m_size.width(), m_size.height()),
+ pixmap,
+ QRectF(m_sourceA, m_spriteSize));
+}
+
+bool QSGSoftwareSpriteNode::isOpaque() const
+{
+ return false;
+}
+
+QRectF QSGSoftwareSpriteNode::rect() const
+{
+ return QRectF(0, 0, m_size.width(), m_size.height());
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h
new file mode 100644
index 0000000000..284ed3dff5
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARESPRITENODE_H
+#define QSGSOFTWARESPRITENODE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwarePixmapTexture;
+class QSGSoftwareSpriteNode : public QSGSpriteNode
+{
+public:
+ QSGSoftwareSpriteNode();
+
+ void setTexture(QSGTexture *texture) override;
+ void setTime(float time) override;
+ void setSourceA(const QPoint &source) override;
+ void setSourceB(const QPoint &source) override;
+ void setSpriteSize(const QSize &size) override;
+ void setSheetSize(const QSize &size) override;
+ void setSize(const QSizeF &size) override;
+ void setFiltering(QSGTexture::Filtering filtering) override;
+ void update() override;
+
+ void paint(QPainter *painter);
+ bool isOpaque() const;
+ QRectF rect() const;
+
+private:
+
+ QSGSoftwarePixmapTexture *m_texture;
+ float m_time;
+ QPoint m_sourceA;
+ QPoint m_sourceB;
+ QSize m_spriteSize;
+ QSize m_sheetSize;
+ QSizeF m_size;
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARESPRITENODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
new file mode 100644
index 0000000000..5d5485ed8f
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
@@ -0,0 +1,991 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarethreadedrenderloop_p.h"
+#include "qsgsoftwarecontext_p.h"
+#include "qsgsoftwarerenderer_p.h"
+
+#include <private/qsgrenderer_p.h>
+#include <private/qquickwindow_p.h>
+#include <private/qquickprofiler_p.h>
+#include <private/qquickanimatorcontroller_p.h>
+#include <private/qquickprofiler_p.h>
+#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmldebugconnector_p.h>
+
+#include <qpa/qplatformbackingstore.h>
+
+#include <QtCore/QQueue>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QBackingStore>
+#include <QtQuick/QQuickWindow>
+
+QT_BEGIN_NAMESPACE
+
+// Passed from the RL to the RT when a window is removed obscured and should be
+// removed from the render loop.
+const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1);
+
+// Passed from the RL to RT when GUI has been locked, waiting for sync.
+const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2);
+
+// Passed by the RT to itself to trigger another render pass. This is typically
+// a result of QQuickWindow::update().
+const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3);
+
+// Passed by the RL to the RT to maybe release resource if no windows are
+// rendering.
+const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4);
+
+// Passed by the RL to the RT when a QQuickWindow::grabWindow() is called.
+const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5);
+
+// Passed by the window when there is a render job to run.
+const QEvent::Type WM_PostJob = QEvent::Type(QEvent::User + 6);
+
+class QSGSoftwareWindowEvent : public QEvent
+{
+public:
+ QSGSoftwareWindowEvent(QQuickWindow *c, QEvent::Type type) : QEvent(type), window(c) { }
+ QQuickWindow *window;
+};
+
+class QSGSoftwareTryReleaseEvent : public QSGSoftwareWindowEvent
+{
+public:
+ QSGSoftwareTryReleaseEvent(QQuickWindow *win, bool destroy)
+ : QSGSoftwareWindowEvent(win, WM_TryRelease), destroying(destroy) { }
+ bool destroying;
+};
+
+class QSGSoftwareSyncEvent : public QSGSoftwareWindowEvent
+{
+public:
+ QSGSoftwareSyncEvent(QQuickWindow *c, bool inExpose, bool force)
+ : QSGSoftwareWindowEvent(c, WM_RequestSync)
+ , size(c->size())
+ , dpr(c->effectiveDevicePixelRatio())
+ , syncInExpose(inExpose)
+ , forceRenderPass(force) { }
+ QSize size;
+ float dpr;
+ bool syncInExpose;
+ bool forceRenderPass;
+};
+
+class QSGSoftwareGrabEvent : public QSGSoftwareWindowEvent
+{
+public:
+ QSGSoftwareGrabEvent(QQuickWindow *c, QImage *result)
+ : QSGSoftwareWindowEvent(c, WM_Grab), image(result) { }
+ QImage *image;
+};
+
+class QSGSoftwareJobEvent : public QSGSoftwareWindowEvent
+{
+public:
+ QSGSoftwareJobEvent(QQuickWindow *c, QRunnable *postedJob)
+ : QSGSoftwareWindowEvent(c, WM_PostJob), job(postedJob) { }
+ ~QSGSoftwareJobEvent() { delete job; }
+ QRunnable *job;
+};
+
+class QSGSoftwareEventQueue : public QQueue<QEvent *>
+{
+public:
+ void addEvent(QEvent *e) {
+ mutex.lock();
+ enqueue(e);
+ if (waiting)
+ condition.wakeOne();
+ mutex.unlock();
+ }
+
+ QEvent *takeEvent(bool wait) {
+ mutex.lock();
+ if (isEmpty() && wait) {
+ waiting = true;
+ condition.wait(&mutex);
+ waiting = false;
+ }
+ QEvent *e = dequeue();
+ mutex.unlock();
+ return e;
+ }
+
+ bool hasMoreEvents() {
+ mutex.lock();
+ bool has = !isEmpty();
+ mutex.unlock();
+ return has;
+ }
+
+private:
+ QMutex mutex;
+ QWaitCondition condition;
+ bool waiting = false;
+};
+
+static inline int qsgrl_animation_interval()
+{
+ const qreal refreshRate = QGuiApplication::primaryScreen() ? QGuiApplication::primaryScreen()->refreshRate() : 0;
+ return refreshRate < 1 ? 16 : int(1000 / refreshRate);
+}
+
+class QSGSoftwareRenderThread : public QThread
+{
+ Q_OBJECT
+public:
+ QSGSoftwareRenderThread(QSGSoftwareThreadedRenderLoop *rl, QSGRenderContext *renderContext)
+ : renderLoop(rl)
+ {
+ rc = static_cast<QSGSoftwareRenderContext *>(renderContext);
+ vsyncDelta = qsgrl_animation_interval();
+ }
+
+ ~QSGSoftwareRenderThread()
+ {
+ delete rc;
+ }
+
+ bool event(QEvent *e);
+ void run();
+
+ void syncAndRender();
+ void sync(bool inExpose);
+
+ void requestRepaint()
+ {
+ if (sleeping)
+ stopEventProcessing = true;
+ if (exposedWindow)
+ pendingUpdate |= RepaintRequest;
+ }
+
+ void processEventsAndWaitForMore();
+ void processEvents();
+ void postEvent(QEvent *e);
+
+ enum UpdateRequest {
+ SyncRequest = 0x01,
+ RepaintRequest = 0x02,
+ ExposeRequest = 0x04 | RepaintRequest | SyncRequest
+ };
+
+ QSGSoftwareThreadedRenderLoop *renderLoop;
+ QSGSoftwareRenderContext *rc;
+ QAnimationDriver *rtAnim = nullptr;
+ volatile bool active = false;
+ uint pendingUpdate = 0;
+ bool sleeping = false;
+ bool syncResultedInChanges = false;
+ float vsyncDelta;
+ QMutex mutex;
+ QWaitCondition waitCondition;
+ QQuickWindow *exposedWindow = nullptr;
+ QBackingStore *backingStore = nullptr;
+ bool stopEventProcessing = false;
+ QSGSoftwareEventQueue eventQueue;
+ QElapsedTimer renderThrottleTimer;
+ qint64 syncTime;
+ qint64 renderTime;
+ qint64 sinceLastTime;
+
+public slots:
+ void onSceneGraphChanged() {
+ syncResultedInChanges = true;
+ }
+};
+
+bool QSGSoftwareRenderThread::event(QEvent *e)
+{
+ switch ((int)e->type()) {
+
+ case WM_Obscure:
+ Q_ASSERT(!exposedWindow || exposedWindow == static_cast<QSGSoftwareWindowEvent *>(e)->window);
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - WM_Obscure" << exposedWindow;
+ mutex.lock();
+ if (exposedWindow) {
+ QQuickWindowPrivate::get(exposedWindow)->fireAboutToStop();
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Obscure - window removed");
+ exposedWindow = nullptr;
+ delete backingStore;
+ backingStore = nullptr;
+ }
+ waitCondition.wakeOne();
+ mutex.unlock();
+ return true;
+
+ case WM_RequestSync: {
+ QSGSoftwareSyncEvent *wme = static_cast<QSGSoftwareSyncEvent *>(e);
+ if (sleeping)
+ stopEventProcessing = true;
+ exposedWindow = wme->window;
+ if (backingStore == nullptr)
+ backingStore = new QBackingStore(exposedWindow);
+ if (backingStore->size() != exposedWindow->size())
+ backingStore->resize(exposedWindow->size());
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - WM_RequestSync" << exposedWindow;
+ pendingUpdate |= SyncRequest;
+ if (wme->syncInExpose) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestSync - triggered from expose");
+ pendingUpdate |= ExposeRequest;
+ }
+ if (wme->forceRenderPass) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestSync - repaint regardless");
+ pendingUpdate |= RepaintRequest;
+ }
+ return true;
+ }
+
+ case WM_TryRelease: {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease");
+ mutex.lock();
+ renderLoop->lockedForSync = true;
+ QSGSoftwareTryReleaseEvent *wme = static_cast<QSGSoftwareTryReleaseEvent *>(e);
+ // Only when no windows are exposed anymore or we are shutting down.
+ if (!exposedWindow || wme->destroying) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease - invalidating rc");
+ if (wme->window) {
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window);
+ if (wme->destroying) {
+ // Bye bye nodes...
+ wd->cleanupNodesOnShutdown();
+ }
+ rc->invalidate();
+ QCoreApplication::processEvents();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ if (wme->destroying)
+ delete wd->animationController;
+ }
+ if (wme->destroying)
+ active = false;
+ if (sleeping)
+ stopEventProcessing = true;
+ } else {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease - not releasing because window is still active");
+ }
+ waitCondition.wakeOne();
+ renderLoop->lockedForSync = false;
+ mutex.unlock();
+ return true;
+ }
+
+ case WM_Grab: {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Grab");
+ QSGSoftwareGrabEvent *wme = static_cast<QSGSoftwareGrabEvent *>(e);
+ Q_ASSERT(wme->window);
+ Q_ASSERT(wme->window == exposedWindow || !exposedWindow);
+ mutex.lock();
+ if (wme->window) {
+ // Grabbing is generally done by rendering a frame and reading the
+ // color buffer contents back, without presenting, and then
+ // creating a QImage from the returned data. It is terribly
+ // inefficient since it involves a full blocking wait for the GPU.
+ // However, our hands are tied by the existing, synchronous APIs of
+ // QQuickWindow and such.
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window);
+ auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(wd->renderer);
+ if (softwareRenderer)
+ softwareRenderer->setBackingStore(backingStore);
+ rc->initialize(nullptr);
+ wd->syncSceneGraph();
+ wd->renderSceneGraph(wme->window->size());
+ *wme->image = backingStore->handle()->toImage();
+ }
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Grab - waking gui to handle result");
+ waitCondition.wakeOne();
+ mutex.unlock();
+ return true;
+ }
+
+ case WM_PostJob: {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_PostJob");
+ QSGSoftwareJobEvent *wme = static_cast<QSGSoftwareJobEvent *>(e);
+ Q_ASSERT(wme->window == exposedWindow);
+ if (exposedWindow) {
+ wme->job->run();
+ delete wme->job;
+ wme->job = nullptr;
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_PostJob - job done");
+ }
+ return true;
+ }
+
+ case WM_RequestRepaint:
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestPaint");
+ // When GUI posts this event, it is followed by a polishAndSync, so we
+ // must not exit the event loop yet.
+ pendingUpdate |= RepaintRequest;
+ break;
+
+ default:
+ break;
+ }
+
+ return QThread::event(e);
+}
+
+void QSGSoftwareRenderThread::postEvent(QEvent *e)
+{
+ eventQueue.addEvent(e);
+}
+
+void QSGSoftwareRenderThread::processEvents()
+{
+ while (eventQueue.hasMoreEvents()) {
+ QEvent *e = eventQueue.takeEvent(false);
+ event(e);
+ delete e;
+ }
+}
+
+void QSGSoftwareRenderThread::processEventsAndWaitForMore()
+{
+ stopEventProcessing = false;
+ while (!stopEventProcessing) {
+ QEvent *e = eventQueue.takeEvent(true);
+ event(e);
+ delete e;
+ }
+}
+
+void QSGSoftwareRenderThread::run()
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - run()");
+
+ rtAnim = rc->sceneGraphContext()->createAnimationDriver(nullptr);
+ rtAnim->install();
+
+ if (QQmlDebugConnector::service<QQmlProfilerService>())
+ QQuickProfiler::registerAnimationCallback();
+
+ renderThrottleTimer.start();
+
+ while (active) {
+ if (exposedWindow)
+ syncAndRender();
+
+ processEvents();
+ QCoreApplication::processEvents();
+
+ if (pendingUpdate == 0 || !exposedWindow) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - done drawing, sleep");
+ sleeping = true;
+ processEventsAndWaitForMore();
+ sleeping = false;
+ }
+ }
+
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - run() exiting");
+
+ delete rtAnim;
+ rtAnim = nullptr;
+
+ rc->moveToThread(renderLoop->thread());
+ moveToThread(renderLoop->thread());
+}
+
+void QSGSoftwareRenderThread::sync(bool inExpose)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - sync");
+
+ mutex.lock();
+ Q_ASSERT_X(renderLoop->lockedForSync, "QSGD3D12RenderThread::sync()", "sync triggered with gui not locked");
+
+ if (exposedWindow) {
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow);
+ bool hadRenderer = wd->renderer != nullptr;
+ // If the scene graph was touched since the last sync() make sure it sends the
+ // changed signal.
+ if (wd->renderer)
+ wd->renderer->clearChangedFlag();
+
+ rc->initialize(nullptr);
+ wd->syncSceneGraph();
+
+ if (!hadRenderer && wd->renderer) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - created renderer");
+ syncResultedInChanges = true;
+ connect(wd->renderer, &QSGRenderer::sceneGraphChanged, this,
+ &QSGSoftwareRenderThread::onSceneGraphChanged, Qt::DirectConnection);
+ }
+
+ // Process deferred deletes now, directly after the sync as deleteLater
+ // on the GUI must now also have resulted in SG changes and the delete
+ // is a safe operation.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ }
+
+ if (!inExpose) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - sync complete, waking gui");
+ waitCondition.wakeOne();
+ mutex.unlock();
+ }
+}
+
+void QSGSoftwareRenderThread::syncAndRender()
+{
+ Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ QElapsedTimer waitTimer;
+ waitTimer.start();
+
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - syncAndRender()");
+
+ syncResultedInChanges = false;
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow);
+
+ const bool repaintRequested = (pendingUpdate & RepaintRequest) || wd->customRenderStage;
+ const bool syncRequested = pendingUpdate & SyncRequest;
+ const bool exposeRequested = (pendingUpdate & ExposeRequest) == ExposeRequest;
+ pendingUpdate = 0;
+
+ if (syncRequested)
+ sync(exposeRequested);
+
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ if (!syncResultedInChanges && !repaintRequested) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - no changes, render aborted");
+ int waitTime = vsyncDelta - (int) waitTimer.elapsed();
+ if (waitTime > 0)
+ msleep(waitTime);
+ return;
+ }
+
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - rendering started");
+
+ if (rtAnim->isRunning()) {
+ wd->animationController->lock();
+ rtAnim->advance();
+ wd->animationController->unlock();
+ }
+
+ bool canRender = wd->renderer != nullptr;
+
+ if (canRender) {
+ auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(wd->renderer);
+ if (softwareRenderer)
+ softwareRenderer->setBackingStore(backingStore);
+ wd->renderSceneGraph(exposedWindow->size());
+
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ if (softwareRenderer && (!wd->customRenderStage || !wd->customRenderStage->swap()))
+ backingStore->flush(softwareRenderer->flushRegion());
+
+ // Since there is no V-Sync with QBackingStore, throttle rendering the refresh
+ // rate of the current screen the window is on.
+ int blockTime = vsyncDelta - (int) renderThrottleTimer.elapsed();
+ if (blockTime > 0) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - blocking for " << blockTime << "ms";
+ msleep(blockTime);
+ }
+ renderThrottleTimer.restart();
+
+ wd->fireFrameSwapped();
+ } else {
+ Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame, 1);
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - window not ready, skipping render");
+ }
+
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - rendering done");
+
+ if (exposeRequested) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - wake gui after initial expose");
+ waitCondition.wakeOne();
+ mutex.unlock();
+ }
+
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame);
+}
+
+template<class T> T *windowFor(const QVector<T> &list, QQuickWindow *window)
+{
+ for (const T &t : list) {
+ if (t.window == window)
+ return const_cast<T *>(&t);
+ }
+ return nullptr;
+}
+
+
+QSGSoftwareThreadedRenderLoop::QSGSoftwareThreadedRenderLoop()
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "software threaded render loop constructor");
+ m_sg = new QSGSoftwareContext;
+ m_anim = m_sg->createAnimationDriver(this);
+ connect(m_anim, &QAnimationDriver::started, this, &QSGSoftwareThreadedRenderLoop::onAnimationStarted);
+ connect(m_anim, &QAnimationDriver::stopped, this, &QSGSoftwareThreadedRenderLoop::onAnimationStopped);
+ m_anim->install();
+}
+
+QSGSoftwareThreadedRenderLoop::~QSGSoftwareThreadedRenderLoop()
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "software threaded render loop destructor");
+ delete m_sg;
+}
+
+void QSGSoftwareThreadedRenderLoop::show(QQuickWindow *window)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "show" << window;
+}
+
+void QSGSoftwareThreadedRenderLoop::hide(QQuickWindow *window)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "hide" << window;
+
+ if (window->isExposed())
+ handleObscurity(windowFor(m_windows, window));
+
+ releaseResources(window);
+}
+
+void QSGSoftwareThreadedRenderLoop::resize(QQuickWindow *window)
+{
+ if (!window->isExposed() || window->size().isEmpty())
+ return;
+
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "resize" << window << window->size();
+}
+
+void QSGSoftwareThreadedRenderLoop::windowDestroyed(QQuickWindow *window)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "window destroyed" << window;
+
+ WindowData *w = windowFor(m_windows, window);
+ if (!w)
+ return;
+
+ handleObscurity(w);
+ handleResourceRelease(w, true);
+
+ QSGSoftwareRenderThread *thread = w->thread;
+ while (thread->isRunning())
+ QThread::yieldCurrentThread();
+
+ Q_ASSERT(thread->thread() == QThread::currentThread());
+ delete thread;
+
+ for (int i = 0; i < m_windows.size(); ++i) {
+ if (m_windows.at(i).window == window) {
+ m_windows.removeAt(i);
+ break;
+ }
+ }
+}
+
+void QSGSoftwareThreadedRenderLoop::exposureChanged(QQuickWindow *window)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "exposure changed" << window;
+
+ if (window->isExposed()) {
+ handleExposure(window);
+ } else {
+ WindowData *w = windowFor(m_windows, window);
+ if (w)
+ handleObscurity(w);
+ }
+}
+
+QImage QSGSoftwareThreadedRenderLoop::grab(QQuickWindow *window)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "grab" << window;
+
+ WindowData *w = windowFor(m_windows, window);
+ // Have to support invisible (but created()'ed) windows as well.
+ // Unlike with GL, leaving that case for QQuickWindow to handle is not feasible.
+ const bool tempExpose = !w;
+ if (tempExpose) {
+ handleExposure(window);
+ w = windowFor(m_windows, window);
+ Q_ASSERT(w);
+ }
+
+ if (!w->thread->isRunning())
+ return QImage();
+
+ if (!window->handle())
+ window->create();
+
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ wd->polishItems();
+
+ QImage result;
+ w->thread->mutex.lock();
+ lockedForSync = true;
+ w->thread->postEvent(new QSGSoftwareGrabEvent(window, &result));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ lockedForSync = false;
+ w->thread->mutex.unlock();
+
+ result.setDevicePixelRatio(window->effectiveDevicePixelRatio());
+
+ if (tempExpose)
+ handleObscurity(w);
+
+ return result;
+}
+
+void QSGSoftwareThreadedRenderLoop::update(QQuickWindow *window)
+{
+ WindowData *w = windowFor(m_windows, window);
+ if (!w)
+ return;
+
+ if (w->thread == QThread::currentThread()) {
+ w->thread->requestRepaint();
+ return;
+ }
+
+ // We set forceRenderPass because we want to make sure the QQuickWindow
+ // actually does a full render pass after the next sync.
+ w->forceRenderPass = true;
+ scheduleUpdate(w);
+}
+
+void QSGSoftwareThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
+{
+ WindowData *w = windowFor(m_windows, window);
+ if (w)
+ scheduleUpdate(w);
+}
+
+void QSGSoftwareThreadedRenderLoop::handleUpdateRequest(QQuickWindow *window)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleUpdateRequest" << window;
+
+ WindowData *w = windowFor(m_windows, window);
+ if (w)
+ polishAndSync(w, false);
+}
+
+QAnimationDriver *QSGSoftwareThreadedRenderLoop::animationDriver() const
+{
+ return m_anim;
+}
+
+QSGContext *QSGSoftwareThreadedRenderLoop::sceneGraphContext() const
+{
+ return m_sg;
+}
+
+QSGRenderContext *QSGSoftwareThreadedRenderLoop::createRenderContext(QSGContext *) const
+{
+ return m_sg->createRenderContext();
+}
+
+void QSGSoftwareThreadedRenderLoop::releaseResources(QQuickWindow *window)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "releaseResources" << window;
+
+ WindowData *w = windowFor(m_windows, window);
+ if (w)
+ handleResourceRelease(w, false);
+}
+
+void QSGSoftwareThreadedRenderLoop::postJob(QQuickWindow *window, QRunnable *job)
+{
+ WindowData *w = windowFor(m_windows, window);
+ if (w && w->thread && w->thread->exposedWindow)
+ w->thread->postEvent(new QSGSoftwareJobEvent(window, job));
+ else
+ delete job;
+}
+
+QSurface::SurfaceType QSGSoftwareThreadedRenderLoop::windowSurfaceType() const
+{
+ return QSurface::RasterSurface;
+}
+
+bool QSGSoftwareThreadedRenderLoop::interleaveIncubation() const
+{
+ bool somethingVisible = false;
+ for (const WindowData &w : m_windows) {
+ if (w.window->isVisible() && w.window->isExposed()) {
+ somethingVisible = true;
+ break;
+ }
+ }
+ return somethingVisible && m_anim->isRunning();
+}
+
+int QSGSoftwareThreadedRenderLoop::flags() const
+{
+ return SupportsGrabWithoutExpose;
+}
+
+bool QSGSoftwareThreadedRenderLoop::event(QEvent *e)
+{
+ if (e->type() == QEvent::Timer) {
+ QTimerEvent *te = static_cast<QTimerEvent *>(e);
+ if (te->timerId() == animationTimer) {
+ m_anim->advance();
+ emit timeToIncubate();
+ return true;
+ }
+ }
+
+ return QObject::event(e);
+}
+
+void QSGSoftwareThreadedRenderLoop::onAnimationStarted()
+{
+ startOrStopAnimationTimer();
+
+ for (const WindowData &w : qAsConst(m_windows))
+ w.window->requestUpdate();
+}
+
+void QSGSoftwareThreadedRenderLoop::onAnimationStopped()
+{
+ startOrStopAnimationTimer();
+}
+
+void QSGSoftwareThreadedRenderLoop::startOrStopAnimationTimer()
+{
+ int exposedWindowCount = 0;
+ const WindowData *exposed = nullptr;
+
+ for (int i = 0; i < m_windows.size(); ++i) {
+ const WindowData &w(m_windows[i]);
+ if (w.window->isVisible() && w.window->isExposed()) {
+ ++exposedWindowCount;
+ exposed = &w;
+ }
+ }
+
+ if (animationTimer && (exposedWindowCount == 1 || !m_anim->isRunning())) {
+ killTimer(animationTimer);
+ animationTimer = 0;
+ // If animations are running, make sure we keep on animating
+ if (m_anim->isRunning())
+ exposed->window->requestUpdate();
+ } else if (!animationTimer && exposedWindowCount != 1 && m_anim->isRunning()) {
+ animationTimer = startTimer(qsgrl_animation_interval());
+ }
+}
+
+void QSGSoftwareThreadedRenderLoop::handleExposure(QQuickWindow *window)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleExposure" << window;
+
+ WindowData *w = windowFor(m_windows, window);
+ if (!w) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "adding window to list");
+ WindowData win;
+ win.window = window;
+ QSGRenderContext *rc = QQuickWindowPrivate::get(window)->context; // will transfer ownership
+ win.thread = new QSGSoftwareRenderThread(this, rc);
+ win.updateDuringSync = false;
+ win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt
+ m_windows.append(win);
+ w = &m_windows.last();
+ }
+
+ // set this early as we'll be rendering shortly anyway and this avoids
+ // special casing exposure in polishAndSync.
+ w->thread->exposedWindow = window;
+
+ if (w->window->size().isEmpty()
+ || (w->window->isTopLevel() && !w->window->geometry().intersects(w->window->screen()->availableGeometry()))) {
+#ifndef QT_NO_DEBUG
+ qWarning().noquote().nospace() << "QSGSotwareThreadedRenderLoop: expose event received for window "
+ << w->window << " with invalid geometry: " << w->window->geometry()
+ << " on " << w->window->screen();
+#endif
+ }
+
+ if (!w->window->handle())
+ w->window->create();
+
+ // Start render thread if it is not running
+ if (!w->thread->isRunning()) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "starting render thread");
+ // Push a few things to the render thread.
+ QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController;
+ if (controller->thread() != w->thread)
+ controller->moveToThread(w->thread);
+ if (w->thread->thread() == QThread::currentThread()) {
+ w->thread->rc->moveToThread(w->thread);
+ w->thread->moveToThread(w->thread);
+ }
+
+ w->thread->active = true;
+ w->thread->start();
+
+ if (!w->thread->isRunning())
+ qFatal("Render thread failed to start, aborting application.");
+ }
+
+ polishAndSync(w, true);
+
+ startOrStopAnimationTimer();
+}
+
+void QSGSoftwareThreadedRenderLoop::handleObscurity(QSGSoftwareThreadedRenderLoop::WindowData *w)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleObscurity" << w->window;
+
+ if (w->thread->isRunning()) {
+ w->thread->mutex.lock();
+ w->thread->postEvent(new QSGSoftwareWindowEvent(w->window, WM_Obscure));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ w->thread->mutex.unlock();
+ }
+
+ startOrStopAnimationTimer();
+}
+
+void QSGSoftwareThreadedRenderLoop::scheduleUpdate(QSGSoftwareThreadedRenderLoop::WindowData *w)
+{
+ if (!QCoreApplication::instance())
+ return;
+
+ if (!w || !w->thread->isRunning())
+ return;
+
+ QThread *current = QThread::currentThread();
+ if (current != QCoreApplication::instance()->thread() && (current != w->thread || !lockedForSync)) {
+ qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()";
+ return;
+ }
+
+ if (current == w->thread) {
+ w->updateDuringSync = true;
+ return;
+ }
+
+ w->window->requestUpdate();
+}
+
+void QSGSoftwareThreadedRenderLoop::handleResourceRelease(QSGSoftwareThreadedRenderLoop::WindowData *w, bool destroying)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleResourceRelease" << (destroying ? "destroying" : "hide/releaseResources") << w->window;
+
+ w->thread->mutex.lock();
+ if (w->thread->isRunning() && w->thread->active) {
+ QQuickWindow *window = w->window;
+
+ // Note that window->handle() is typically null by this time because
+ // the platform window is already destroyed. This should not be a
+ // problem for the D3D cleanup.
+
+ w->thread->postEvent(new QSGSoftwareTryReleaseEvent(window, destroying));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+
+ // Avoid a shutdown race condition.
+ // If SG is invalidated and 'active' becomes false, the thread's run()
+ // method will exit. handleExposure() relies on QThread::isRunning() (because it
+ // potentially needs to start the thread again) and our mutex cannot be used to
+ // track the thread stopping, so we wait a few nanoseconds extra so the thread
+ // can exit properly.
+ if (!w->thread->active)
+ w->thread->wait();
+ }
+ w->thread->mutex.unlock();
+}
+
+void QSGSoftwareThreadedRenderLoop::polishAndSync(QSGSoftwareThreadedRenderLoop::WindowData *w, bool inExpose)
+{
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "polishAndSync" << (inExpose ? "(in expose)" : "(normal)") << w->window;
+
+ QQuickWindow *window = w->window;
+ if (!w->thread || !w->thread->exposedWindow) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - not exposed, abort");
+ return;
+ }
+
+ // Flush pending touch events.
+ QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
+ // The delivery of the event might have caused the window to stop rendering
+ w = windowFor(m_windows, window);
+ if (!w || !w->thread || !w->thread->exposedWindow) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - removed after touch event flushing, abort");
+ return;
+ }
+
+ Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync);
+
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ wd->polishItems();
+
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
+
+ w->updateDuringSync = false;
+
+ emit window->afterAnimating();
+
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - lock for sync");
+ w->thread->mutex.lock();
+ lockedForSync = true;
+ w->thread->postEvent(new QSGSoftwareSyncEvent(window, inExpose, w->forceRenderPass));
+ w->forceRenderPass = false;
+
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - wait for sync");
+
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ lockedForSync = false;
+ w->thread->mutex.unlock();
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - unlock after sync");
+
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync);
+
+ if (!animationTimer && m_anim->isRunning()) {
+ qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - advancing animations");
+ m_anim->advance();
+ // We need to trigger another sync to keep animations running...
+ w->window->requestUpdate();
+ emit timeToIncubate();
+ } else if (w->updateDuringSync) {
+ w->window->requestUpdate();
+ }
+
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync);
+}
+
+#include "qsgsoftwarethreadedrenderloop.moc"
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h
new file mode 100644
index 0000000000..99993d651c
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARETHREADEDRENDERLOOP_H
+#define QSGSOFTWARETHREADEDRENDERLOOP_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgrenderloop_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwareRenderThread;
+class QSGSoftwareContext;
+
+class QSGSoftwareThreadedRenderLoop : public QSGRenderLoop
+{
+ Q_OBJECT
+public:
+ QSGSoftwareThreadedRenderLoop();
+ ~QSGSoftwareThreadedRenderLoop();
+
+ void show(QQuickWindow *window) override;
+ void hide(QQuickWindow *window) override;
+ void resize(QQuickWindow *window) override;
+ void windowDestroyed(QQuickWindow *window) override;
+ void exposureChanged(QQuickWindow *window) override;
+ QImage grab(QQuickWindow *window) override;
+ void update(QQuickWindow *window) override;
+ void maybeUpdate(QQuickWindow *window) override;
+ void handleUpdateRequest(QQuickWindow *window) override;
+ QAnimationDriver *animationDriver() const override;
+ QSGContext *sceneGraphContext() const override;
+ QSGRenderContext *createRenderContext(QSGContext *) const override;
+ void releaseResources(QQuickWindow *window) override;
+ void postJob(QQuickWindow *window, QRunnable *job) override;
+ QSurface::SurfaceType windowSurfaceType() const override;
+ bool interleaveIncubation() const override;
+ int flags() const override;
+
+ bool event(QEvent *e) override;
+
+public Q_SLOTS:
+ void onAnimationStarted();
+ void onAnimationStopped();
+
+private:
+ struct WindowData {
+ QQuickWindow *window;
+ QSGSoftwareRenderThread *thread;
+ uint updateDuringSync : 1;
+ uint forceRenderPass : 1;
+ };
+
+ void startOrStopAnimationTimer();
+ void handleExposure(QQuickWindow *window);
+ void handleObscurity(WindowData *w);
+ void scheduleUpdate(WindowData *w);
+ void handleResourceRelease(WindowData *w, bool destroying);
+ void polishAndSync(WindowData *w, bool inExpose);
+
+ QSGSoftwareContext *m_sg;
+ QAnimationDriver *m_anim;
+ int animationTimer = 0;
+ bool lockedForSync = false;
+ QVector<WindowData> m_windows;
+
+ friend class QSGSoftwareRenderThread;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARETHREADEDRENDERLOOP_H
diff --git a/src/quick/scenegraph/adaptations/software/software.pri b/src/quick/scenegraph/adaptations/software/software.pri
index b8cdbc4a25..97644fc36a 100644
--- a/src/quick/scenegraph/adaptations/software/software.pri
+++ b/src/quick/scenegraph/adaptations/software/software.pri
@@ -6,10 +6,10 @@ SOURCES += \
$$PWD/qsgsoftwarecontext.cpp \
$$PWD/qsgabstractsoftwarerenderer.cpp \
$$PWD/qsgsoftwareglyphnode.cpp \
- $$PWD/qsgsoftwareimagenode.cpp \
- $$PWD/qsgsoftwareninepatchnode.cpp \
+ $$PWD/qsgsoftwareinternalimagenode.cpp \
+ $$PWD/qsgsoftwarepublicnodes.cpp \
$$PWD/qsgsoftwarepainternode.cpp \
- $$PWD/qsgsoftwarerectanglenode.cpp \
+ $$PWD/qsgsoftwareinternalrectanglenode.cpp \
$$PWD/qsgsoftwarepixmaprenderer.cpp \
$$PWD/qsgsoftwarepixmaptexture.cpp \
$$PWD/qsgsoftwarerenderablenode.cpp \
@@ -18,22 +18,26 @@ SOURCES += \
$$PWD/qsgsoftwarerenderlistbuilder.cpp \
$$PWD/qsgsoftwarerenderloop.cpp \
$$PWD/qsgsoftwarelayer.cpp \
- $$PWD/qsgsoftwareadaptation.cpp
+ $$PWD/qsgsoftwareadaptation.cpp \
+ $$PWD/qsgsoftwarespritenode.cpp \
+ $$PWD/qsgsoftwarethreadedrenderloop.cpp
HEADERS += \
$$PWD/qsgsoftwarecontext_p.h \
$$PWD/qsgabstractsoftwarerenderer_p.h \
$$PWD/qsgsoftwareglyphnode_p.h \
- $$PWD/qsgsoftwareimagenode_p.h \
- $$PWD/qsgsoftwareninepatchnode_p.h \
+ $$PWD/qsgsoftwareinternalimagenode_p.h \
+ $$PWD/qsgsoftwarepublicnodes_p.h \
$$PWD/qsgsoftwarepainternode_p.h \
$$PWD/qsgsoftwarepixmaprenderer_p.h \
$$PWD/qsgsoftwarepixmaptexture_p.h \
- $$PWD/qsgsoftwarerectanglenode_p.h \
+ $$PWD/qsgsoftwareinternalrectanglenode_p.h \
$$PWD/qsgsoftwarerenderablenode_p.h \
$$PWD/qsgsoftwarerenderablenodeupdater_p.h \
$$PWD/qsgsoftwarerenderer_p.h \
$$PWD/qsgsoftwarerenderlistbuilder_p.h \
$$PWD/qsgsoftwarerenderloop_p.h \
$$PWD/qsgsoftwarelayer_p.h \
- $$PWD/qsgsoftwareadaptation_p.h
+ $$PWD/qsgsoftwareadaptation_p.h \
+ $$PWD/qsgsoftwarespritenode_p.h \
+ $$PWD/qsgsoftwarethreadedrenderloop_p.h
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 9501b3bb3e..49bbbf0ba8 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -1033,11 +1033,13 @@ void Renderer::nodeWasAdded(QSGNode *node, Node *shadowParent)
m_rebuild |= FullRebuild;
} else if (node->type() == QSGNode::RenderNodeType) {
- RenderNodeElement *e = new RenderNodeElement(static_cast<QSGRenderNode *>(node));
+ QSGRenderNode *rn = static_cast<QSGRenderNode *>(node);
+ RenderNodeElement *e = new RenderNodeElement(rn);
snode->data = e;
- Q_ASSERT(!m_renderNodeElements.contains(static_cast<QSGRenderNode *>(node)));
+ Q_ASSERT(!m_renderNodeElements.contains(rn));
m_renderNodeElements.insert(e->renderNode, e);
- m_useDepthBuffer = false;
+ if (!rn->flags().testFlag(QSGRenderNode::DepthAwareRendering))
+ m_useDepthBuffer = false;
m_rebuild |= FullRebuild;
}
@@ -2764,15 +2766,16 @@ void Renderer::render()
struct RenderNodeState : public QSGRenderNode::RenderState
{
const QMatrix4x4 *projectionMatrix() const override { return m_projectionMatrix; }
- QRect scissorRect() const { return m_scissorRect; }
- bool scissorEnabled() const { return m_scissorEnabled; }
- int stencilValue() const { return m_stencilValue; }
- bool stencilEnabled() const { return m_stencilEnabled; }
+ QRect scissorRect() const override { return m_scissorRect; }
+ bool scissorEnabled() const override { return m_scissorEnabled; }
+ int stencilValue() const override { return m_stencilValue; }
+ bool stencilEnabled() const override { return m_stencilEnabled; }
+ const QRegion *clipRegion() const override { return nullptr; }
const QMatrix4x4 *m_projectionMatrix;
QRect m_scissorRect;
- bool m_scissorEnabled;
int m_stencilValue;
+ bool m_scissorEnabled;
bool m_stencilEnabled;
};
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 01e517e65b..d5e94cea3e 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -499,7 +499,7 @@ public:
void updateRootTransforms(Node *n);
void updateRootTransforms(Node *n, Node *root, const QMatrix4x4 &combined);
- void updateStates(QSGNode *n);
+ void updateStates(QSGNode *n) override;
void visitNode(Node *n);
void registerWithParentRoot(QSGNode *subRoot, QSGNode *parentRoot);
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
index 7ec72a6e10..239557d527 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.cpp
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -726,6 +726,27 @@ void QSGGeometry::updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect,
v[3].ty = textureRect.bottom();
}
+/*!
+ Updates the geometry \a g with the coordinates in \a rect.
+
+ The function assumes the geometry object contains a single triangle strip
+ of QSGGeometry::ColoredPoint2D vertices
+ */
+void QSGGeometry::updateColoredRectGeometry(QSGGeometry *g, const QRectF &rect)
+{
+ ColoredPoint2D *v = g->vertexDataAsColoredPoint2D();
+ v[0].x = rect.left();
+ v[0].y = rect.top();
+
+ v[1].x = rect.left();
+ v[1].y = rect.bottom();
+
+ v[2].x = rect.right();
+ v[2].y = rect.top();
+
+ v[3].x = rect.right();
+ v[3].y = rect.bottom();
+}
/*!
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h
index 1f54b7d81b..ae7b2f494c 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.h
+++ b/src/quick/scenegraph/coreapi/qsggeometry.h
@@ -182,6 +182,7 @@ public:
static void updateRectGeometry(QSGGeometry *g, const QRectF &rect);
static void updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &sourceRect);
+ static void updateColoredRectGeometry(QSGGeometry *g, const QRectF &rect);
void setIndexDataPattern(DataPattern p);
DataPattern indexDataPattern() const { return DataPattern(m_index_usage_pattern); }
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 42a4c4abd3..13598bbe1d 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -67,9 +67,9 @@ void qsg_set_material_failure()
#ifndef QT_NO_OPENGL
const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType type) const
{
- QStringList files = m_sourceFiles[type];
+ const QStringList files = m_sourceFiles[type];
QSGShaderSourceBuilder builder;
- Q_FOREACH (const QString &file, files)
+ for (const QString &file : files)
builder.appendSourceFile(file);
m_sources[type] = builder.source();
return m_sources[type].constData();
@@ -681,7 +681,6 @@ QSGMaterial::~QSGMaterial()
the full matrix of the geometry nodes for rendering.
\value CustomCompileStep Starting with Qt 5.2, the scene graph will not always call
-
QSGMaterialShader::compile() when its shader program is compiled and linked.
Set this flag to enforce that the function is called.
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index f5983fc00d..2211f88973 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -337,12 +337,12 @@ QSGNode::~QSGNode()
to the scene graph and will cause the preprocess() function to be called
for every frame the node is rendered.
- The preprocess function is called before the update pass that propegates
+ The preprocess function is called before the update pass that propagates
opacity and transformations through the scene graph. That means that
functions like QSGOpacityNode::combinedOpacity() and
QSGTransformNode::combinedMatrix() will not contain up-to-date values.
If such values are changed during the preprocess, these changes will be
- propegated through the scene graph before it is rendered.
+ propagated through the scene graph before it is rendered.
\warning Beware of deleting nodes while they are being preprocessed. It is
possible, with a small performance hit, to delete a single node during its
@@ -1268,7 +1268,7 @@ QSGRootNode::QSGRootNode()
QSGRootNode::~QSGRootNode()
{
while (!m_renderers.isEmpty())
- m_renderers.last()->setRootNode(0);
+ m_renderers.constLast()->setRootNode(0);
destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode.
}
@@ -1349,7 +1349,7 @@ const qreal OPACITY_THRESHOLD = 0.001;
Sets the opacity of this node to \a opacity.
Before rendering the graph, the renderer will do an update pass
- over the subtree to propegate the opacity to its children.
+ over the subtree to propagate the opacity to its children.
The value will be bounded to the range 0 to 1.
*/
@@ -1466,8 +1466,6 @@ void QSGNodeVisitor::visitChildren(QSGNode *n)
visitNode(c);
}
-
-
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const QSGGeometryNode *n)
{
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
index f7ea6dbe23..1467f2233d 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.h
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -325,7 +325,7 @@ public:
void setCombinedOpacity(qreal opacity);
qreal combinedOpacity() const { return m_combined_opacity; }
- bool isSubtreeBlocked() const;
+ bool isSubtreeBlocked() const override;
private:
qreal m_opacity;
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index 94b78a85b4..3fb23fe3cd 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -138,7 +138,7 @@ class QSGBindableFboId : public QSGBindable
{
public:
QSGBindableFboId(GLuint);
- virtual void bind() const;
+ void bind() const override;
private:
GLuint m_id;
};
@@ -160,8 +160,8 @@ public:
static void dump(QSGNode *n);
QSGNodeDumper() : m_indent(0) {}
- void visitNode(QSGNode *n);
- void visitChildren(QSGNode *n);
+ void visitNode(QSGNode *n) override;
+ void visitChildren(QSGNode *n) override;
private:
int m_indent;
diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
index ffde9d8930..fa543aecad 100644
--- a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
@@ -54,12 +54,21 @@ QT_BEGIN_NAMESPACE
necessary to query certain values, for instance the graphics device (e.g.
the Direct3D or Vulkan device) that is used by the scenegraph.
- \note QSGRendererInterface is only available after the scenegraph is
- initialized. Additionally, there may be backend-specific limitations on
- when the functions can be called. The only way that is guaranteed to
- succeed is calling them when the rendering of a node (i.e. the preparation
- of the command list for the next frame) is active. In practice this
- typically means QSGRenderNode::render().
+ QSGRendererInterface's functions have varying availability. API and
+ language queries, like graphicsApi() or shaderType() are always available,
+ meaning it is sufficient to construct a QQuickWindow or QQuickView, and the
+ graphics API or shading language in use can be queried right after via
+ QQuickWindow::rendererInterface(). This guarantees that utilities like the
+ GraphicsInfo QML type are able to report the correct values as early as
+ possible, without having conditional property values - depending on for
+ instance shaderType() - evaluate to unexpected values.
+
+ Engine-specific accessors, like getResource(), are however available only
+ after the scenegraph is initialized. Additionally, there may be
+ backend-specific limitations on when such functions can be called. The only
+ way that is guaranteed to succeed is calling them when the rendering of a
+ node (i.e. the preparation of the command list for the next frame) is
+ active. In practice this typically means QSGRenderNode::render().
*/
/*!
@@ -68,15 +77,40 @@ QT_BEGIN_NAMESPACE
\value Software The Qt Quick 2D Renderer is in use
\value OpenGL OpenGL ES 2.0 or higher
\value Direct3D12 Direct3D 12
- \value Vulkan Vulkan
- \value Metal Metal
*/
/*!
\enum QSGRendererInterface::Resource
- \value Device The graphics device
- \value CommandQueue The graphics command queue used by the scenergaph
- \value CommandList The command list or buffer used by the scenegraph
+ \value Device The graphics device, when applicable.
+ \value CommandQueue The graphics command queue used by the scenegraph, when applicable.
+ \value CommandList The command list or buffer used by the scenegraph, when applicable.
+ \value Painter The active QPainter used by the scenegraph, when running with the software backend.
+ */
+
+/*!
+ \enum QSGRendererInterface::ShaderType
+ \value UnknownShadingLanguage Not yet known due to no window and scenegraph associated
+ \value GLSL GLSL or GLSL ES
+ \value HLSL HLSL
+ */
+
+/*!
+ \enum QSGRendererInterface::ShaderCompilationType
+ \value RuntimeCompilation Runtime compilation of shader source code is supported
+ \value OfflineCompilation Pre-compiled bytecode supported
+ */
+
+/*!
+ \enum QSGRendererInterface::ShaderSourceType
+
+ \value ShaderSourceString Shader source can be provided as a string in
+ the corresponding properties of ShaderEffect
+
+ \value ShaderSourceFile Local or resource files containing shader source
+ code are supported
+
+ \value ShaderByteCode Local or resource files containing shader bytecode are
+ supported
*/
QSGRendererInterface::~QSGRendererInterface()
@@ -88,10 +122,7 @@ QSGRendererInterface::~QSGRendererInterface()
Returns the graphics API that is in use by the Qt Quick scenegraph.
- \note This function can be called on any thread. However, the renderer
- interface's lifetime may be tied to the render thread and therefore calling
- this function from other threads during the process of application shutdown
- or QQuickWindow closing is likely to become invalid.
+ \note This function can be called on any thread.
*/
/*!
@@ -104,10 +135,13 @@ QSGRendererInterface::~QSGRendererInterface()
example, \c{VkDevice dev = *static_cast<VkDevice *>(result)}). The latter
is necessary since such handles may have sizes different from a pointer.
+ \note The ownership of the returned pointer is never transferred to the caller.
+
\note This function must only be called on the render thread.
*/
-void *QSGRendererInterface::getResource(Resource resource) const
+void *QSGRendererInterface::getResource(QQuickWindow *window, Resource resource) const
{
+ Q_UNUSED(window);
Q_UNUSED(resource);
return nullptr;
}
@@ -117,10 +151,13 @@ void *QSGRendererInterface::getResource(Resource resource) const
allows supporting any future resources that are not listed in the
Resource enum.
+ \note The ownership of the returned pointer is never transferred to the caller.
+
\note This function must only be called on the render thread.
*/
-void *QSGRendererInterface::getResource(const char *resource) const
+void *QSGRendererInterface::getResource(QQuickWindow *window, const char *resource) const
{
+ Q_UNUSED(window);
Q_UNUSED(resource);
return nullptr;
}
@@ -131,10 +168,7 @@ void *QSGRendererInterface::getResource(const char *resource) const
\return the shading language supported by the Qt Quick backend the
application is using.
- \note This function can be called on any thread. However, the renderer
- interface's lifetime may be tied to the render thread and therefore calling
- this function from other threads during the process of application shutdown
- or QQuickWindow closing is likely to become invalid.
+ \note This function can be called on any thread.
\sa QtQuick::GraphicsInfo
*/
@@ -145,10 +179,7 @@ void *QSGRendererInterface::getResource(const char *resource) const
\return a bitmask of the shader compilation approaches supported by the Qt
Quick backend the application is using.
- \note This function can be called on any thread. However, the renderer
- interface's lifetime may be tied to the render thread and therefore calling
- this function from other threads during the process of application shutdown
- or QQuickWindow closing is likely to become invalid.
+ \note This function can be called on any thread.
\sa QtQuick::GraphicsInfo
*/
@@ -156,12 +187,9 @@ void *QSGRendererInterface::getResource(const char *resource) const
/*!
\fn QSGRendererInterface::ShaderSourceTypes QSGRendererInterface::shaderSourceType() const
- \return a bitmask of the supported ways of providing shader sources.
+ \return a bitmask of the supported ways of providing shader sources in ShaderEffect items.
- \note This function can be called on any thread. However, the renderer
- interface's lifetime may be tied to the render thread and therefore calling
- this function from other threads during the process of application shutdown
- or QQuickWindow closing is likely to become invalid.
+ \note This function can be called on any thread.
\sa QtQuick::GraphicsInfo
*/
diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.h b/src/quick/scenegraph/coreapi/qsgrendererinterface.h
index 234a061d0e..a50b362aeb 100644
--- a/src/quick/scenegraph/coreapi/qsgrendererinterface.h
+++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.h
@@ -44,6 +44,8 @@
QT_BEGIN_NAMESPACE
+class QQuickWindow;
+
class Q_QUICK_EXPORT QSGRendererInterface
{
public:
@@ -57,7 +59,8 @@ public:
enum Resource {
Device,
CommandQueue,
- CommandList
+ CommandList,
+ Painter
};
enum ShaderType {
@@ -83,8 +86,8 @@ public:
virtual GraphicsApi graphicsApi() const = 0;
- virtual void *getResource(Resource resource) const;
- virtual void *getResource(const char *resource) const;
+ virtual void *getResource(QQuickWindow *window, Resource resource) const;
+ virtual void *getResource(QQuickWindow *window, const char *resource) const;
virtual ShaderType shaderType() const = 0;
virtual ShaderCompilationTypes shaderCompilationType() const = 0;
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
index 6c61b35aa1..5915d51f2b 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
@@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QSGRenderNode
- \brief The QSGMaterialShader class represents a set of custom rendering commands
+ \brief The QSGRenderNode class represents a set of custom rendering commands
targeting the graphics API that is in use by the scenegraph.
\inmodule QtQuick
\since 5.8
@@ -111,6 +111,10 @@ QSGRenderNodePrivate::QSGRenderNodePrivate()
call related settings (root signature, descriptor heaps, etc.) are always
set again by the scenegraph so render() can freely change them.
+ The software backend exposes its QPainter and saves and restores before and
+ after invoking render(). Therefore reporting any changed states from here
+ is not necessary.
+
\note This function may be called before render().
*/
QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
@@ -125,17 +129,6 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
directly invoking commands in the graphics API (OpenGL, Direct3D, etc.)
currently in use.
- The states necessary for clipping has already been set before the function
- is called. The clip is a combination of a stencil clip and scissor clip.
- Information about the clip is found in \a state.
-
- \note This means that setting viewport, scissor rectangle, stencil
- reference value, and similar is not necessary in render() since the
- corresponding commands are on the command list (or, in case of OpenGL, the
- context) already. However, for APIs other than OpenGL stencil-based
- clipping will need enabling stencil testing in the pipeline state that is
- used by render().
-
The effective opacity can be retrieved with \l inheritedOpacity().
The projection matrix is available through \a state, while the model-view
@@ -156,6 +149,12 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
QQuickFramebufferObject, QQuickWindow::beforeRendering(), or the
equivalents of those for APIs other than OpenGL.
+ Clip information is calculated before the function is called, it is however
+ not enabled. Implementations wishing to take clipping into account can set
+ up scissoring or stencil based on the information in \a state. Some
+ scenegraph backends, software in particular, use no scissor or stencil.
+ There the clip region is provided as an ordinary QRegion.
+
For OpenGL the following states are set on the render thread's context
before this function is called:
\list
@@ -180,6 +179,11 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
default value according to the OpenGL specification. For other APIs, see
the documentation for changedStates() for more information.
+ \note Depth writes are disabled when this function is called (for example,
+ glDepthMask(false) in case of OpenGL). Enabling depth writes can lead to
+ unexpected results, depending on the scenegraph backend in use, so nodes
+ should avoid this.
+
For APIs other than OpenGL, it will likely be necessary to query certain
API-specific resources (for example, the graphics device or the command
list/buffer to add the commands to). This is done via QSGRendererInterface.
@@ -212,6 +216,68 @@ void QSGRenderNode::releaseResources()
}
/*!
+ \enum QSGRenderNode::RenderingFlag
+
+ Possible values for the bitmask returned from flags().
+
+ \value BoundedRectRendering Indicates that the implementation of render()
+ does not render outside the area reported from rect() in item
+ coordinates. Such node implementations can lead to more efficient rendering,
+ depending on the scenegraph backend. For example, the software backend can
+ continue to use the more optimal partial update path when all render nodes
+ in the scene have this flag set.
+
+ \value DepthAwareRendering Indicates that the implementations of render()
+ conforms to scenegraph expectations by only generating a Z value of 0 in
+ scene coordinates which is then transformed by the matrices retrieved from
+ RenderState::projectionMatrix() and matrix(), as described in the notes for
+ render(). Such node implementations can lead to more efficient rendering,
+ depending on the scenegraph backend. For example, the batching OpenGL
+ renderer can continue to use a more optimal path when all render nodes in
+ the scene have this flag set.
+
+ \value OpaqueRendering Indicates that the implementation of render() writes
+ out opaque pixels for the entire area reported from rect(). By default the
+ renderers must assume that render() can also output semi or fully
+ transparent pixels. Setting this flag can improve performance in some
+ cases.
+
+ \sa render(), rect()
+ */
+
+/*!
+ \return flags describing the behavior of this render node.
+
+ The default implementation returns 0.
+
+ \sa RenderingFlag, rect()
+ */
+QSGRenderNode::RenderingFlags QSGRenderNode::flags() const
+{
+ return 0;
+}
+
+/*!
+ \return the bounding rectangle in item coordinates for the area render()
+ touches. The value is only in use when flags() includes
+ BoundedRectRendering, ignored otherwise.
+
+ Reporting the rectangle in combination with BoundedRectRendering is
+ particularly important with the \c software backend because otherwise
+ having a rendernode in the scene would trigger fullscreen updates, skipping
+ all partial update optimizations.
+
+ For rendernodes covering the entire area of a corresponding QQuickItem the
+ return value will be (0, 0, item->width(), item->height()).
+
+ \sa flags()
+*/
+QRectF QSGRenderNode::rect() const
+{
+ return QRectF();
+}
+
+/*!
\return pointer to the current model-view matrix.
*/
const QMatrix4x4 *QSGRenderNode::matrix() const
@@ -287,6 +353,19 @@ QSGRenderNode::RenderState::~RenderState()
*/
/*!
+ \fn const QRegion *QSGRenderNode::clipRegion() const
+
+ \return the current clip region or null for backends where clipping is
+ implemented via stencil or scissoring.
+
+ The software backend uses no projection, scissor or stencil, meaning most
+ of the render state is not in use. However, the clip region that can be set
+ on the QPainter still has to be communicated since reconstructing this
+ manually in render() is not reasonable. It can therefore be queried via
+ this function.
+ */
+
+/*!
\return pointer to a \a state value.
Reserved for future use.
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.h b/src/quick/scenegraph/coreapi/qsgrendernode.h
index 17569f8c59..f6bc40d3ee 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.h
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.h
@@ -61,6 +61,13 @@ public:
};
Q_DECLARE_FLAGS(StateFlags, StateFlag)
+ enum RenderingFlag {
+ BoundedRectRendering = 0x01,
+ DepthAwareRendering = 0x02,
+ OpaqueRendering = 0x04
+ };
+ Q_DECLARE_FLAGS(RenderingFlags, RenderingFlag)
+
struct Q_QUICK_EXPORT RenderState {
virtual ~RenderState();
virtual const QMatrix4x4 *projectionMatrix() const = 0;
@@ -68,6 +75,7 @@ public:
virtual bool scissorEnabled() const = 0;
virtual int stencilValue() const = 0;
virtual bool stencilEnabled() const = 0;
+ virtual const QRegion *clipRegion() const = 0;
virtual void *get(const char *state) const;
};
@@ -77,6 +85,8 @@ public:
virtual StateFlags changedStates() const;
virtual void render(const RenderState *state) = 0;
virtual void releaseResources();
+ virtual RenderingFlags flags() const;
+ virtual QRectF rect() const;
const QMatrix4x4 *matrix() const;
const QSGClipNode *clipList() const;
@@ -88,6 +98,7 @@ private:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::RenderingFlags)
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
index 3a35632d5c..48ab1aa52f 100644
--- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
+++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
@@ -193,13 +193,13 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat
switch (profile) {
case QSurfaceFormat::NoProfile:
case QSurfaceFormat::CompatibilityProfile:
- result += QByteArrayLiteral("attribute highp float _qt_order;\n");
- result += QByteArrayLiteral("uniform highp float _qt_zRange;\n");
+ result += "attribute highp float _qt_order;\n"
+ "uniform highp float _qt_zRange;\n";
break;
case QSurfaceFormat::CoreProfile:
- result += QByteArrayLiteral("in float _qt_order;\n");
- result += QByteArrayLiteral("uniform float _qt_zRange;\n");
+ result += "in float _qt_order;\n"
+ "uniform float _qt_zRange;\n";
break;
}
@@ -214,9 +214,9 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat
case Tokenizer::Token_CloseBrace:
braceDepth--;
if (braceDepth == 0) {
- result += QByteArray::fromRawData(voidPos, tok.pos - 1 - voidPos);
- result += QByteArrayLiteral(" gl_Position.z = (gl_Position.z * _qt_zRange + _qt_order) * gl_Position.w;\n");
- result += QByteArray(tok.pos - 1);
+ result += QByteArray::fromRawData(voidPos, tok.pos - 1 - voidPos)
+ + " gl_Position.z = (gl_Position.z * _qt_zRange + _qt_order) * gl_Position.w;\n"
+ + QByteArray(tok.pos - 1);
return result;
}
break;
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 50986e2528..e219ddd82e 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -46,6 +46,7 @@
#include <private/qrawfont_p.h>
#include <QtGui/qguiapplication.h>
#include <qdir.h>
+#include <qsgrendernode.h>
#include <private/qquickprofiler_p.h>
#include <QElapsedTimer>
@@ -195,7 +196,7 @@ void QSGDistanceFieldGlyphCache::update()
storeGlyphs(distanceFields);
#if defined(QSG_DISTANCEFIELD_CACHE_DEBUG)
- foreach (Texture texture, m_textures)
+ for (Texture texture : qAsConst(m_textures))
saveTexture(texture.textureId, texture.size.width(), texture.size.height());
#endif
@@ -512,6 +513,13 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node)
visitChildren(child);
break;
}
+ case QSGNode::RenderNodeType: {
+ QSGRenderNode *r = static_cast<QSGRenderNode*>(child);
+ if (visit(r))
+ visitChildren(r);
+ endVisit(r);
+ break;
+ }
default:
Q_UNREACHABLE();
break;
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 8fdcf7af64..a74b38dba8 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -76,12 +76,13 @@ class TextureReference;
class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldGlyphNode;
class QOpenGLContext;
-class QSGImageNode;
+class QSGInternalImageNode;
class QSGPainterNode;
-class QSGRectangleNode;
+class QSGInternalRectangleNode;
class QSGGlyphNode;
-class QSGNinePatchNode;
class QSGRootNode;
+class QSGSpriteNode;
+class QSGRenderNode;
class Q_QUICK_PRIVATE_EXPORT QSGNodeVisitorEx
{
@@ -97,18 +98,20 @@ public:
virtual void endVisit(QSGGeometryNode *) = 0;
virtual bool visit(QSGOpacityNode *) = 0;
virtual void endVisit(QSGOpacityNode *) = 0;
- virtual bool visit(QSGImageNode *) = 0;
- virtual void endVisit(QSGImageNode *) = 0;
+ virtual bool visit(QSGInternalImageNode *) = 0;
+ virtual void endVisit(QSGInternalImageNode *) = 0;
virtual bool visit(QSGPainterNode *) = 0;
virtual void endVisit(QSGPainterNode *) = 0;
- virtual bool visit(QSGRectangleNode *) = 0;
- virtual void endVisit(QSGRectangleNode *) = 0;
+ virtual bool visit(QSGInternalRectangleNode *) = 0;
+ virtual void endVisit(QSGInternalRectangleNode *) = 0;
virtual bool visit(QSGGlyphNode *) = 0;
virtual void endVisit(QSGGlyphNode *) = 0;
- virtual bool visit(QSGNinePatchNode *) = 0;
- virtual void endVisit(QSGNinePatchNode *) = 0;
virtual bool visit(QSGRootNode *) = 0;
virtual void endVisit(QSGRootNode *) = 0;
+ virtual bool visit(QSGSpriteNode *) = 0;
+ virtual void endVisit(QSGSpriteNode *) = 0;
+ virtual bool visit(QSGRenderNode *) = 0;
+ virtual void endVisit(QSGRenderNode *) = 0;
void visitChildren(QSGNode *node);
};
@@ -122,7 +125,7 @@ public:
virtual void accept(QSGNodeVisitorEx *) = 0;
};
-class Q_QUICK_PRIVATE_EXPORT QSGRectangleNode : public QSGVisitableNode
+class Q_QUICK_PRIVATE_EXPORT QSGInternalRectangleNode : public QSGVisitableNode
{
public:
virtual void setRect(const QRectF &rect) = 0;
@@ -140,7 +143,7 @@ public:
};
-class Q_QUICK_PRIVATE_EXPORT QSGImageNode : public QSGVisitableNode
+class Q_QUICK_PRIVATE_EXPORT QSGInternalImageNode : public QSGVisitableNode
{
public:
virtual void setTargetRect(const QRectF &rect) = 0;
@@ -186,19 +189,6 @@ public:
virtual void accept(QSGNodeVisitorEx *visitor) { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
};
-class Q_QUICK_PRIVATE_EXPORT QSGNinePatchNode : public QSGVisitableNode
-{
-public:
- virtual void setTexture(QSGTexture *texture) = 0;
- virtual void setBounds(const QRectF &bounds) = 0;
- virtual void setDevicePixelRatio(qreal ratio) = 0;
- virtual void setPadding(qreal left, qreal top, qreal right, qreal bottom) = 0;
-
- virtual void update() = 0;
-
- virtual void accept(QSGNodeVisitorEx *visitor) { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
-};
-
class Q_QUICK_EXPORT QSGLayer : public QSGDynamicTexture
{
Q_OBJECT
@@ -223,6 +213,23 @@ Q_SIGNALS:
void scheduledUpdateCompleted();
};
+class Q_QUICK_PRIVATE_EXPORT QSGSpriteNode : public QSGVisitableNode
+{
+public:
+ virtual void setTexture(QSGTexture *texture) = 0;
+ virtual void setTime(float time) = 0;
+ virtual void setSourceA(const QPoint &source) = 0;
+ virtual void setSourceB(const QPoint &source) = 0;
+ virtual void setSpriteSize(const QSize &size) = 0;
+ virtual void setSheetSize(const QSize &size) = 0;
+ virtual void setSize(const QSizeF &size) = 0;
+ virtual void setFiltering(QSGTexture::Filtering filtering) = 0;
+
+ virtual void update() = 0;
+
+ virtual void accept(QSGNodeVisitorEx *visitor) { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
+};
+
class Q_QUICK_PRIVATE_EXPORT QSGGuiThreadShaderEffectManager : public QObject
{
Q_OBJECT
@@ -273,9 +280,10 @@ public:
uint constantDataSize;
};
- virtual bool reflect(const QByteArray &src, ShaderInfo *result) = 0;
+ virtual void prepareShaderCode(ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result) = 0;
Q_SIGNALS:
+ void shaderCodePrepared(bool ok, ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result);
void textureChanged();
void logAndStatusChanged();
};
@@ -536,7 +544,8 @@ inline bool QSGDistanceFieldGlyphCache::containsGlyph(glyph_t glyph)
return glyphData(glyph).texCoord.isValid();
}
-
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QSGGuiThreadShaderEffectManager::ShaderInfo::Type)
+
#endif
diff --git a/src/quick/scenegraph/qsgbasicimagenode.cpp b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp
index 24077cc947..685a51550d 100644
--- a/src/quick/scenegraph/qsgbasicimagenode.cpp
+++ b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qsgbasicimagenode_p.h"
+#include "qsgbasicinternalimagenode_p.h"
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qmath.h>
@@ -65,7 +65,7 @@ namespace
}
}
-QSGBasicImageNode::QSGBasicImageNode()
+QSGBasicInternalImageNode::QSGBasicInternalImageNode()
: m_innerSourceRect(0, 0, 1, 1)
, m_subSourceRect(0, 0, 1, 1)
, m_antialiasing(false)
@@ -77,11 +77,11 @@ QSGBasicImageNode::QSGBasicImageNode()
setGeometry(&m_geometry);
#ifdef QSG_RUNTIME_DESCRIPTION
- qsgnode_set_description(this, QLatin1String("image"));
+ qsgnode_set_description(this, QLatin1String("internalimage"));
#endif
}
-void QSGBasicImageNode::setTargetRect(const QRectF &rect)
+void QSGBasicInternalImageNode::setTargetRect(const QRectF &rect)
{
if (rect == m_targetRect)
return;
@@ -89,7 +89,7 @@ void QSGBasicImageNode::setTargetRect(const QRectF &rect)
m_dirtyGeometry = true;
}
-void QSGBasicImageNode::setInnerTargetRect(const QRectF &rect)
+void QSGBasicInternalImageNode::setInnerTargetRect(const QRectF &rect)
{
if (rect == m_innerTargetRect)
return;
@@ -97,7 +97,7 @@ void QSGBasicImageNode::setInnerTargetRect(const QRectF &rect)
m_dirtyGeometry = true;
}
-void QSGBasicImageNode::setInnerSourceRect(const QRectF &rect)
+void QSGBasicInternalImageNode::setInnerSourceRect(const QRectF &rect)
{
if (rect == m_innerSourceRect)
return;
@@ -105,7 +105,7 @@ void QSGBasicImageNode::setInnerSourceRect(const QRectF &rect)
m_dirtyGeometry = true;
}
-void QSGBasicImageNode::setSubSourceRect(const QRectF &rect)
+void QSGBasicInternalImageNode::setSubSourceRect(const QRectF &rect)
{
if (rect == m_subSourceRect)
return;
@@ -113,7 +113,7 @@ void QSGBasicImageNode::setSubSourceRect(const QRectF &rect)
m_dirtyGeometry = true;
}
-void QSGBasicImageNode::setTexture(QSGTexture *texture)
+void QSGBasicInternalImageNode::setTexture(QSGTexture *texture)
{
Q_ASSERT(texture);
@@ -126,7 +126,7 @@ void QSGBasicImageNode::setTexture(QSGTexture *texture)
m_dirtyGeometry = true;
}
-void QSGBasicImageNode::setAntialiasing(bool antialiasing)
+void QSGBasicInternalImageNode::setAntialiasing(bool antialiasing)
{
if (antialiasing == m_antialiasing)
return;
@@ -142,7 +142,7 @@ void QSGBasicImageNode::setAntialiasing(bool antialiasing)
m_dirtyGeometry = true;
}
-void QSGBasicImageNode::setMirror(bool mirror)
+void QSGBasicInternalImageNode::setMirror(bool mirror)
{
if (mirror == m_mirror)
return;
@@ -151,13 +151,13 @@ void QSGBasicImageNode::setMirror(bool mirror)
}
-void QSGBasicImageNode::update()
+void QSGBasicInternalImageNode::update()
{
if (m_dirtyGeometry)
updateGeometry();
}
-void QSGBasicImageNode::preprocess()
+void QSGBasicInternalImageNode::preprocess()
{
bool doDirty = false;
QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(materialTexture());
@@ -200,7 +200,7 @@ static inline void appendQuad(quint16 **indices, quint16 topLeft, quint16 topRig
*(*indices)++ = topLeft;
}
-QSGGeometry *QSGBasicImageNode::updateGeometry(const QRectF &targetRect,
+QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect,
const QRectF &innerTargetRect,
const QRectF &sourceRect,
const QRectF &innerSourceRect,
@@ -458,7 +458,7 @@ QSGGeometry *QSGBasicImageNode::updateGeometry(const QRectF &targetRect,
return geometry;
}
-void QSGBasicImageNode::updateGeometry()
+void QSGBasicInternalImageNode::updateGeometry()
{
Q_ASSERT(!m_targetRect.isEmpty());
const QSGTexture *t = materialTexture();
diff --git a/src/quick/scenegraph/qsgbasicimagenode_p.h b/src/quick/scenegraph/qsgbasicinternalimagenode_p.h
index 4a96e1a9f6..a5689b20aa 100644
--- a/src/quick/scenegraph/qsgbasicimagenode_p.h
+++ b/src/quick/scenegraph/qsgbasicinternalimagenode_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QSGBASICIMAGENODE_P_H
-#define QSGBASICIMAGENODE_P_H
+#ifndef QSGBASICINTERNALIMAGENODE_P_H
+#define QSGBASICINTERNALIMAGENODE_P_H
//
// W A R N I N G
@@ -55,10 +55,10 @@
QT_BEGIN_NAMESPACE
-class Q_QUICK_PRIVATE_EXPORT QSGBasicImageNode : public QSGImageNode
+class Q_QUICK_PRIVATE_EXPORT QSGBasicInternalImageNode : public QSGInternalImageNode
{
public:
- QSGBasicImageNode();
+ QSGBasicInternalImageNode();
void setTargetRect(const QRectF &rect) override;
void setInnerTargetRect(const QRectF &rect) override;
diff --git a/src/quick/scenegraph/qsgbasicrectanglenode.cpp b/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp
index 14d2dc9677..8fc850b60c 100644
--- a/src/quick/scenegraph/qsgbasicrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qsgbasicrectanglenode_p.h"
+#include "qsgbasicinternalrectanglenode_p.h"
#include <QtCore/qmath.h>
@@ -96,7 +96,7 @@ namespace
}
}
-QSGBasicRectangleNode::QSGBasicRectangleNode()
+QSGBasicInternalRectangleNode::QSGBasicInternalRectangleNode()
: m_radius(0)
, m_pen_width(0)
, m_aligned(true)
@@ -108,11 +108,11 @@ QSGBasicRectangleNode::QSGBasicRectangleNode()
setGeometry(&m_geometry);
#ifdef QSG_RUNTIME_DESCRIPTION
- qsgnode_set_description(this, QLatin1String("rectangle"));
+ qsgnode_set_description(this, QLatin1String("internalrectangle"));
#endif
}
-void QSGBasicRectangleNode::setRect(const QRectF &rect)
+void QSGBasicInternalRectangleNode::setRect(const QRectF &rect)
{
if (rect == m_rect)
return;
@@ -120,7 +120,7 @@ void QSGBasicRectangleNode::setRect(const QRectF &rect)
m_dirty_geometry = true;
}
-void QSGBasicRectangleNode::setColor(const QColor &color)
+void QSGBasicInternalRectangleNode::setColor(const QColor &color)
{
if (color == m_color)
return;
@@ -129,7 +129,7 @@ void QSGBasicRectangleNode::setColor(const QColor &color)
m_dirty_geometry = true;
}
-void QSGBasicRectangleNode::setPenColor(const QColor &color)
+void QSGBasicInternalRectangleNode::setPenColor(const QColor &color)
{
if (color == m_border_color)
return;
@@ -138,7 +138,7 @@ void QSGBasicRectangleNode::setPenColor(const QColor &color)
m_dirty_geometry = true;
}
-void QSGBasicRectangleNode::setPenWidth(qreal width)
+void QSGBasicInternalRectangleNode::setPenWidth(qreal width)
{
if (width == m_pen_width)
return;
@@ -147,7 +147,7 @@ void QSGBasicRectangleNode::setPenWidth(qreal width)
}
-void QSGBasicRectangleNode::setGradientStops(const QGradientStops &stops)
+void QSGBasicInternalRectangleNode::setGradientStops(const QGradientStops &stops)
{
if (stops.constData() == m_gradient_stops.constData())
return;
@@ -160,7 +160,7 @@ void QSGBasicRectangleNode::setGradientStops(const QGradientStops &stops)
m_dirty_geometry = true;
}
-void QSGBasicRectangleNode::setRadius(qreal radius)
+void QSGBasicInternalRectangleNode::setRadius(qreal radius)
{
if (radius == m_radius)
return;
@@ -168,7 +168,7 @@ void QSGBasicRectangleNode::setRadius(qreal radius)
m_dirty_geometry = true;
}
-void QSGBasicRectangleNode::setAntialiasing(bool antialiasing)
+void QSGBasicInternalRectangleNode::setAntialiasing(bool antialiasing)
{
if (!supportsAntialiasing())
return;
@@ -187,7 +187,7 @@ void QSGBasicRectangleNode::setAntialiasing(bool antialiasing)
m_dirty_geometry = true;
}
-void QSGBasicRectangleNode::setAligned(bool aligned)
+void QSGBasicInternalRectangleNode::setAligned(bool aligned)
{
if (aligned == m_aligned)
return;
@@ -195,7 +195,7 @@ void QSGBasicRectangleNode::setAligned(bool aligned)
m_dirty_geometry = true;
}
-void QSGBasicRectangleNode::update()
+void QSGBasicInternalRectangleNode::update()
{
if (m_dirty_geometry) {
updateGeometry();
@@ -207,7 +207,7 @@ void QSGBasicRectangleNode::update()
}
}
-void QSGBasicRectangleNode::updateGeometry()
+void QSGBasicInternalRectangleNode::updateGeometry()
{
float width = float(m_rect.width());
float height = float(m_rect.height());
diff --git a/src/quick/scenegraph/qsgbasicrectanglenode_p.h b/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h
index b1d1457590..98e53669ce 100644
--- a/src/quick/scenegraph/qsgbasicrectanglenode_p.h
+++ b/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h
@@ -38,8 +38,8 @@
****************************************************************************/
-#ifndef QSGBASICRECTANGLENODE_P_H
-#define QSGBASICRECTANGLENODE_P_H
+#ifndef QSGBASICINTERNALRECTANGLENODE_P_H
+#define QSGBASICINTERNALRECTANGLENODE_P_H
//
// W A R N I N G
@@ -56,10 +56,10 @@
QT_BEGIN_NAMESPACE
-class Q_QUICK_PRIVATE_EXPORT QSGBasicRectangleNode : public QSGRectangleNode
+class Q_QUICK_PRIVATE_EXPORT QSGBasicInternalRectangleNode : public QSGInternalRectangleNode
{
public:
- QSGBasicRectangleNode();
+ QSGBasicInternalRectangleNode();
void setRect(const QRectF &rect) override;
void setColor(const QColor &color) override;
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 40d65d99aa..688fc7db08 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE
// Used for very high-level info about the renderering and gl context
// Includes GL_VERSION, type of render loop, atlas size, etc.
-Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.info")
+Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.general")
// Used to debug the renderloop logic. Primarily useful for platform integrators
// and when investigating the render loop logic.
@@ -268,9 +268,9 @@ void QSGContext::renderContextInvalidated(QSGRenderContext *)
/*!
Convenience factory function for creating a colored rectangle with the given geometry.
*/
-QSGRectangleNode *QSGContext::createRectangleNode(const QRectF &rect, const QColor &c)
+QSGInternalRectangleNode *QSGContext::createInternalRectangleNode(const QRectF &rect, const QColor &c)
{
- QSGRectangleNode *node = createRectangleNode();
+ QSGInternalRectangleNode *node = createInternalRectangleNode();
node->setRect(rect);
node->setColor(c);
node->update();
@@ -318,7 +318,15 @@ QSize QSGContext::minimumFBOSize() const
Returns a pointer to the (presumably) global renderer interface.
\note This function may be called on the gui thread in order to get access
- to QSGRendererInterface::graphicsApi().
+ to QSGRendererInterface::graphicsApi() and other getters.
+
+ \note it is expected that the simple queries (graphicsApi, shaderType,
+ etc.) are available regardless of the render context validity (i.e.
+ scenegraph status). This does not apply to engine-specific getters like
+ getResource(). In the end this means that this function must always return
+ a valid object in subclasses, even when renderContext->isValid() is false.
+ The typical pattern is to implement the QSGRendererInterface in the
+ QSGContext or QSGRenderContext subclass itself, whichever is more suitable.
*/
QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderContext)
{
@@ -335,7 +343,6 @@ QSGRenderContext::QSGRenderContext(QSGContext *context)
QSGRenderContext::~QSGRenderContext()
{
- invalidate();
}
void QSGRenderContext::initialize(void *context)
@@ -345,8 +352,6 @@ void QSGRenderContext::initialize(void *context)
void QSGRenderContext::invalidate()
{
- m_sg->renderContextInvalidated(this);
- emit invalidated();
}
void QSGRenderContext::endSync()
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 2fef0ff1e8..899278843e 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -66,11 +66,10 @@
QT_BEGIN_NAMESPACE
class QSGContextPrivate;
-class QSGRectangleNode;
-class QSGImageNode;
+class QSGInternalRectangleNode;
+class QSGInternalImageNode;
class QSGPainterNode;
class QSGGlyphNode;
-class QSGNinePatchNode;
class QSGRenderer;
class QSGDistanceFieldGlyphCache;
class QQuickWindow;
@@ -85,6 +84,10 @@ class QQuickPaintedItem;
class QSGRendererInterface;
class QSGShaderEffectNode;
class QSGGuiThreadShaderEffectManager;
+class QSGRectangleNode;
+class QSGImageNode;
+class QSGNinePatchNode;
+class QSGSpriteNode;
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION)
@@ -122,6 +125,10 @@ public:
virtual QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const = 0;
virtual QSGRenderer *createRenderer() = 0;
+ virtual void setAttachToGraphicsContext(bool attach) { Q_UNUSED(attach); }
+
+ virtual int maxTextureSize() const = 0;
+
void registerFontengineForCleanup(QFontEngine *engine);
Q_SIGNALS:
@@ -132,7 +139,8 @@ public Q_SLOTS:
void textureFactoryDestroyed(QObject *o);
protected:
- QSGContext *m_sg;
+ // Hold m_sg with QPointer in the rare case it gets deleted before us.
+ QPointer<QSGContext> m_sg;
QMutex m_mutex;
QHash<QQuickTextureFactory *, QSGTexture *> m_textures;
@@ -161,16 +169,16 @@ public:
virtual void renderContextInvalidated(QSGRenderContext *renderContext);
virtual QSGRenderContext *createRenderContext() = 0;
- QSGRectangleNode *createRectangleNode(const QRectF &rect, const QColor &c);
- virtual QSGRectangleNode *createRectangleNode() = 0;
- virtual QSGImageNode *createImageNode() = 0;
+ QSGInternalRectangleNode *createInternalRectangleNode(const QRectF &rect, const QColor &c);
+ virtual QSGInternalRectangleNode *createInternalRectangleNode() = 0;
+ virtual QSGInternalImageNode *createInternalImageNode() = 0;
virtual QSGPainterNode *createPainterNode(QQuickPaintedItem *item) = 0;
virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) = 0;
- virtual QSGNinePatchNode *createNinePatchNode() = 0;
virtual QSGLayer *createLayer(QSGRenderContext *renderContext) = 0;
virtual QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager();
virtual QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext,
QSGGuiThreadShaderEffectManager *mgr);
+ virtual QSGSpriteNode *createSpriteNode() = 0;
virtual QAnimationDriver *createAnimationDriver(QObject *parent);
virtual QSize minimumFBOSize() const;
@@ -178,6 +186,10 @@ public:
virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext);
+ virtual QSGRectangleNode *createRectangleNode() = 0;
+ virtual QSGImageNode *createImageNode() = 0;
+ virtual QSGNinePatchNode *createNinePatchNode() = 0;
+
static QSGContext *createDefaultContext();
static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
static QSGRenderLoop *createWindowManager();
diff --git a/src/quick/scenegraph/qsgcontextplugin.cpp b/src/quick/scenegraph/qsgcontextplugin.cpp
index 7569cd2495..3751891455 100644
--- a/src/quick/scenegraph/qsgcontextplugin.cpp
+++ b/src/quick/scenegraph/qsgcontextplugin.cpp
@@ -136,9 +136,7 @@ QSGAdaptationBackendData *contextFactory()
#endif
if (!requestedBackend.isEmpty()) {
-#ifndef QT_NO_DEBUG
qCDebug(QSG_LOG_INFO) << "Loading backend" << requestedBackend;
-#endif
// First look for a built-in adaptation.
for (QSGContextFactoryInterface *builtInBackend : qAsConst(backendData->builtIns)) {
@@ -160,14 +158,12 @@ QSGAdaptationBackendData *contextFactory()
backendData->name = requestedBackend;
backendData->flags = backendData->factory->flags(requestedBackend);
}
-#ifndef QT_NO_DEBUG
if (!backendData->factory) {
qWarning("Could not create scene graph context for backend '%s'"
" - check that plugins are installed correctly in %s",
qPrintable(requestedBackend),
qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
}
-#endif
}
#endif // QT_NO_LIBRARY
}
diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp
index f9978e816c..6964b74dc8 100644
--- a/src/quick/scenegraph/qsgdefaultcontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultcontext.cpp
@@ -40,8 +40,8 @@
#include "qsgdefaultcontext_p.h"
#include <QtQuick/private/qsgdistancefieldutil_p.h>
-#include <QtQuick/private/qsgdefaultrectanglenode_p.h>
-#include <QtQuick/private/qsgdefaultimagenode_p.h>
+#include <QtQuick/private/qsgdefaultinternalrectanglenode_p.h>
+#include <QtQuick/private/qsgdefaultinternalimagenode_p.h>
#include <QtQuick/private/qsgdefaultpainternode_p.h>
#include <QtQuick/private/qsgdefaultglyphnode_p.h>
#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
@@ -49,6 +49,10 @@
#include <QtQuick/private/qsgrenderloop_p.h>
#include <QtQuick/private/qsgdefaultlayer_p.h>
#include <QtQuick/private/qsgdefaultrendercontext_p.h>
+#include <QtQuick/private/qsgdefaultrectanglenode_p.h>
+#include <QtQuick/private/qsgdefaultimagenode_p.h>
+#include <QtQuick/private/qsgdefaultninepatchnode_p.h>
+#include <QtQuick/private/qsgdefaultspritenode_p.h>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFramebufferObject>
@@ -60,13 +64,13 @@
QT_BEGIN_NAMESPACE
namespace QSGMultisampleAntialiasing {
- class ImageNode : public QSGDefaultImageNode {
+ class ImageNode : public QSGDefaultInternalImageNode {
public:
void setAntialiasing(bool) { }
};
- class RectangleNode : public QSGDefaultRectangleNode {
+ class RectangleNode : public QSGDefaultInternalRectangleNode {
public:
void setAntialiasing(bool) { }
};
@@ -152,7 +156,9 @@ void QSGDefaultContext::renderContextInitialized(QSGRenderContext *renderContext
qCDebug(QSG_LOG_INFO) << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER);
qCDebug(QSG_LOG_INFO) << "GL_VERSION: " << (const char *) funcs->glGetString(GL_VERSION);
QSet<QByteArray> exts = openglRenderContext->openglContext()->extensions();
- QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e;
+ QByteArray all;
+ for (const QByteArray &e : qAsConst(exts))
+ all += ' ' + e;
qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData();
qCDebug(QSG_LOG_INFO) << "Max Texture Size: " << openglRenderContext->maxTextureSize();
qCDebug(QSG_LOG_INFO) << "Debug context: " << format.testOption(QSurfaceFormat::DebugContext);
@@ -170,18 +176,18 @@ QSGRenderContext *QSGDefaultContext::createRenderContext()
return new QSGDefaultRenderContext(this);
}
-QSGRectangleNode *QSGDefaultContext::createRectangleNode()
+QSGInternalRectangleNode *QSGDefaultContext::createInternalRectangleNode()
{
return m_antialiasingMethod == MsaaAntialiasing
? new QSGMultisampleAntialiasing::RectangleNode
- : new QSGDefaultRectangleNode;
+ : new QSGDefaultInternalRectangleNode;
}
-QSGImageNode *QSGDefaultContext::createImageNode()
+QSGInternalImageNode *QSGDefaultContext::createInternalImageNode()
{
return m_antialiasingMethod == MsaaAntialiasing
? new QSGMultisampleAntialiasing::ImageNode
- : new QSGDefaultImageNode;
+ : new QSGDefaultInternalImageNode;
}
QSGPainterNode *QSGDefaultContext::createPainterNode(QQuickPaintedItem *item)
@@ -200,15 +206,6 @@ QSGGlyphNode *QSGDefaultContext::createGlyphNode(QSGRenderContext *rc, bool pref
}
}
-/*!
- * Factory function for scene graph backends of the QStyle stylable elements. Returns a
- * null pointer if the backend doesn't provide its own node type.
- */
-QSGNinePatchNode *QSGDefaultContext::createNinePatchNode()
-{
- return nullptr;
-}
-
QSGLayer *QSGDefaultContext::createLayer(QSGRenderContext *renderContext)
{
return new QSGDefaultLayer(renderContext);
@@ -246,6 +243,26 @@ QSGRendererInterface *QSGDefaultContext::rendererInterface(QSGRenderContext *ren
return this;
}
+QSGRectangleNode *QSGDefaultContext::createRectangleNode()
+{
+ return new QSGDefaultRectangleNode;
+}
+
+QSGImageNode *QSGDefaultContext::createImageNode()
+{
+ return new QSGDefaultImageNode;
+}
+
+QSGNinePatchNode *QSGDefaultContext::createNinePatchNode()
+{
+ return new QSGDefaultNinePatchNode;
+}
+
+QSGSpriteNode *QSGDefaultContext::createSpriteNode()
+{
+ return new QSGDefaultSpriteNode;
+}
+
QSGRendererInterface::GraphicsApi QSGDefaultContext::graphicsApi() const
{
return OpenGL;
@@ -263,7 +280,7 @@ QSGRendererInterface::ShaderCompilationTypes QSGDefaultContext::shaderCompilatio
QSGRendererInterface::ShaderSourceTypes QSGDefaultContext::shaderSourceType() const
{
- return ShaderSourceString;
+ return ShaderSourceString | ShaderSourceFile;
}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultcontext_p.h b/src/quick/scenegraph/qsgdefaultcontext_p.h
index 6686ab98a0..88db5e1e9a 100644
--- a/src/quick/scenegraph/qsgdefaultcontext_p.h
+++ b/src/quick/scenegraph/qsgdefaultcontext_p.h
@@ -57,7 +57,7 @@
QT_BEGIN_NAMESPACE
-class QSGDefaultContext : public QSGContext, public QSGRendererInterface
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultContext : public QSGContext, public QSGRendererInterface
{
public:
QSGDefaultContext(QObject *parent = 0);
@@ -66,14 +66,17 @@ public:
void renderContextInitialized(QSGRenderContext *renderContext) override;
void renderContextInvalidated(QSGRenderContext *) override;
QSGRenderContext *createRenderContext() override;
- QSGRectangleNode *createRectangleNode() override;
- QSGImageNode *createImageNode() override;
+ QSGInternalRectangleNode *createInternalRectangleNode() override;
+ QSGInternalImageNode *createInternalImageNode() override;
QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override;
QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override;
- QSGNinePatchNode *createNinePatchNode() override;
QSGLayer *createLayer(QSGRenderContext *renderContext) override;
QSurfaceFormat defaultSurfaceFormat() const override;
QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
+ QSGRectangleNode *createRectangleNode() override;
+ QSGImageNode *createImageNode() override;
+ QSGNinePatchNode *createNinePatchNode() override;
+ QSGSpriteNode *createSpriteNode() override;
void setDistanceFieldEnabled(bool enabled);
bool isDistanceFieldEnabled() const;
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 650700e37a..f0a336e229 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -103,8 +103,10 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
glyph_t glyphIndex = *it;
int padding = QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING;
- int glyphWidth = qCeil(glyphData(glyphIndex).boundingRect.width()) + distanceFieldRadius() * 2;
- QSize glyphSize(glyphWidth + padding * 2, QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()) + padding * 2);
+ QRectF boundingRect = glyphData(glyphIndex).boundingRect;
+ 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);
if (alloc.isNull()) {
@@ -113,11 +115,13 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
glyph_t unusedGlyph = *m_unusedGlyphs.constBegin();
TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
- int unusedGlyphWidth = qCeil(glyphData(unusedGlyph).boundingRect.width()) + distanceFieldRadius() * 2;
+ QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect;
+ 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,
- padding * 2 + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution())));
+ padding * 2 + unusedGlyphHeight));
m_unusedGlyphs.remove(unusedGlyph);
m_glyphsTexture.remove(unusedGlyph);
@@ -255,7 +259,8 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int
const GLenum format = GL_ALPHA;
#endif
- m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, 0);
+ QByteArray zeroBuf(width * height, 0);
+ m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, zeroBuf.constData());
texInfo->size = QSize(width, height);
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
index eeea104e91..9ad99e5c54 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -116,9 +116,8 @@ private:
{
m_blitProgram = new QOpenGLShaderProgram;
{
- QString source;
- source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader));
- source.append(QLatin1String(qopenglslUntransformedPositionVertexShader));
+ const QString source = QLatin1String(qopenglslMainWithTexCoordsVertexShader)
+ + QLatin1String(qopenglslUntransformedPositionVertexShader);
QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram);
vertexShader->compileSourceCode(source);
@@ -126,9 +125,8 @@ private:
m_blitProgram->addShader(vertexShader);
}
{
- QString source;
- source.append(QLatin1String(qopenglslMainFragmentShader));
- source.append(QLatin1String(qopenglslImageSrcFragmentShader));
+ const QString source = QLatin1String(qopenglslMainFragmentShader)
+ + QLatin1String(qopenglslImageSrcFragmentShader);
QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram);
fragmentShader->compileSourceCode(source);
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 7c2663d5a3..3501f30487 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -41,6 +41,7 @@
#include <private/qsgmaterialshader_p.h>
#include <qopenglshaderprogram.h>
+#include <qopenglframebufferobject.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -210,6 +211,7 @@ public:
void activate();
void deactivate();
+ bool useSRGB() const;
uint m_useSRGB : 1;
};
@@ -229,11 +231,26 @@ void QSG24BitTextMaskShader::initialize()
}
}
+bool QSG24BitTextMaskShader::useSRGB() const
+{
+#ifdef Q_OS_MACOS
+ if (!m_useSRGB)
+ return false;
+
+ // m_useSRGB is true, but if some QOGLFBO was bound check it's texture format:
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QOpenGLFramebufferObject *qfbo = QOpenGLContextPrivate::get(ctx)->qgl_current_fbo;
+ return !qfbo || qfbo->format().internalTextureFormat() == GL_SRGB8_ALPHA8_EXT;
+#else
+ return m_useSRGB;
+#endif
+}
+
void QSG24BitTextMaskShader::activate()
{
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
funcs->glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
- if (m_useSRGB)
+ if (useSRGB())
funcs->glEnable(GL_FRAMEBUFFER_SRGB);
}
@@ -241,7 +258,7 @@ void QSG24BitTextMaskShader::deactivate()
{
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
funcs->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- if (m_useSRGB)
+ if (useSRGB())
funcs->glDisable(GL_FRAMEBUFFER_SRGB);
}
@@ -266,7 +283,7 @@ void QSG24BitTextMaskShader::updateState(const RenderState &state, QSGMaterial *
if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) {
QVector4D color = material->color();
- if (m_useSRGB)
+ if (useSRGB())
color = qt_sRGB_to_linear_RGB(color);
QOpenGLContext::currentContext()->functions()->glBlendColor(color.x(), color.y(), color.z(), color.w());
color = qsg_premultiply(color, state.opacity());
diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp
index 9fed70a7de..1d54628acd 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qsgdefaultimagenode_p.h"
+#include "qsgdefaultinternalimagenode_p.h"
#include <private/qsgmaterialshader_p.h>
#include <private/qsgtexturematerial_p.h>
#include <QtGui/qopenglfunctions.h>
@@ -117,13 +117,13 @@ void SmoothTextureMaterialShader::initialize()
QSGTextureMaterialShader::initialize();
}
-QSGDefaultImageNode::QSGDefaultImageNode()
+QSGDefaultInternalImageNode::QSGDefaultInternalImageNode()
{
setMaterial(&m_materialO);
setOpaqueMaterial(&m_material);
}
-void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
+void QSGDefaultInternalImageNode::setFiltering(QSGTexture::Filtering filtering)
{
if (m_material.filtering() == filtering)
return;
@@ -134,7 +134,7 @@ void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
markDirty(DirtyMaterial);
}
-void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
+void QSGDefaultInternalImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
{
if (m_material.mipmapFiltering() == filtering)
return;
@@ -145,7 +145,7 @@ void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
markDirty(DirtyMaterial);
}
-void QSGDefaultImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
+void QSGDefaultInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
{
if (m_material.verticalWrapMode() == wrapMode)
return;
@@ -156,7 +156,7 @@ void QSGDefaultImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
markDirty(DirtyMaterial);
}
-void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
+void QSGDefaultInternalImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
{
if (m_material.horizontalWrapMode() == wrapMode)
return;
@@ -167,7 +167,7 @@ void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
markDirty(DirtyMaterial);
}
-void QSGDefaultImageNode::updateMaterialAntialiasing()
+void QSGDefaultInternalImageNode::updateMaterialAntialiasing()
{
if (m_antialiasing) {
setMaterial(&m_smoothMaterial);
@@ -178,19 +178,19 @@ void QSGDefaultImageNode::updateMaterialAntialiasing()
}
}
-void QSGDefaultImageNode::setMaterialTexture(QSGTexture *texture)
+void QSGDefaultInternalImageNode::setMaterialTexture(QSGTexture *texture)
{
m_material.setTexture(texture);
m_materialO.setTexture(texture);
m_smoothMaterial.setTexture(texture);
}
-QSGTexture *QSGDefaultImageNode::materialTexture() const
+QSGTexture *QSGDefaultInternalImageNode::materialTexture() const
{
return m_material.texture();
}
-bool QSGDefaultImageNode::updateMaterialBlending()
+bool QSGDefaultInternalImageNode::updateMaterialBlending()
{
const bool alpha = m_material.flags() & QSGMaterial::Blending;
if (materialTexture() && alpha != materialTexture()->hasAlphaChannel()) {
@@ -206,7 +206,7 @@ inline static bool isPowerOfTwo(int x)
return x == (x & -x);
}
-bool QSGDefaultImageNode::supportsWrap(const QSize &size) const
+bool QSGDefaultInternalImageNode::supportsWrap(const QSize &size) const
{
bool wrapSupported = true;
diff --git a/src/quick/scenegraph/qsgdefaultimagenode_p.h b/src/quick/scenegraph/qsgdefaultinternalimagenode_p.h
index 688c5a5039..1fc7834bd1 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode_p.h
+++ b/src/quick/scenegraph/qsgdefaultinternalimagenode_p.h
@@ -38,8 +38,8 @@
****************************************************************************/
-#ifndef QSGDEFAULTIMAGENODE_P_H
-#define QSGDEFAULTIMAGENODE_P_H
+#ifndef QSGDEFAULTINTERNALIMAGENODE_P_H
+#define QSGDEFAULTINTERNALIMAGENODE_P_H
//
// W A R N I N G
@@ -53,7 +53,7 @@
//
#include <private/qsgadaptationlayer_p.h>
-#include <private/qsgbasicimagenode_p.h>
+#include <private/qsgbasicinternalimagenode_p.h>
#include <QtQuick/qsgtexturematerial.h>
QT_BEGIN_NAMESPACE
@@ -70,10 +70,10 @@ protected:
QSGMaterialShader *createShader() const override;
};
-class Q_QUICK_PRIVATE_EXPORT QSGDefaultImageNode : public QSGBasicImageNode
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultInternalImageNode : public QSGBasicInternalImageNode
{
public:
- QSGDefaultImageNode();
+ QSGDefaultInternalImageNode();
void setMipmapFiltering(QSGTexture::Filtering filtering) override;
void setFiltering(QSGTexture::Filtering filtering) override;
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp
index 117a9272e5..94414444ba 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp
@@ -38,7 +38,7 @@
**
****************************************************************************/
-#include "qsgdefaultrectanglenode_p.h"
+#include "qsgdefaultinternalrectanglenode_p.h"
#include <QtQuick/qsgvertexcolormaterial.h>
#include <QtQuick/qsgtexturematerial.h>
@@ -128,12 +128,12 @@ QSGMaterialShader *QSGSmoothColorMaterial::createShader() const
return new SmoothColorMaterialShader;
}
-QSGDefaultRectangleNode::QSGDefaultRectangleNode()
+QSGDefaultInternalRectangleNode::QSGDefaultInternalRectangleNode()
{
setMaterial(&m_material);
}
-void QSGDefaultRectangleNode::updateMaterialAntialiasing()
+void QSGDefaultInternalRectangleNode::updateMaterialAntialiasing()
{
if (m_antialiasing)
setMaterial(&m_smoothMaterial);
@@ -141,7 +141,7 @@ void QSGDefaultRectangleNode::updateMaterialAntialiasing()
setMaterial(&m_material);
}
-void QSGDefaultRectangleNode::updateMaterialBlending(QSGNode::DirtyState *state)
+void QSGDefaultInternalRectangleNode::updateMaterialBlending(QSGNode::DirtyState *state)
{
// smoothed material is always blended, so no change in material state
if (material() == &m_material) {
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/qsgdefaultinternalrectanglenode_p.h
index f30a3beed7..a3f734a7b3 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
+++ b/src/quick/scenegraph/qsgdefaultinternalrectanglenode_p.h
@@ -38,8 +38,8 @@
****************************************************************************/
-#ifndef QSGDEFAULTRECTANGLENODE_P_H
-#define QSGDEFAULTRECTANGLENODE_P_H
+#ifndef QSGDEFAULTINTERNALRECTANGLENODE_P_H
+#define QSGDEFAULTINTERNALRECTANGLENODE_P_H
//
// W A R N I N G
@@ -53,7 +53,7 @@
//
#include <private/qsgadaptationlayer_p.h>
-#include <private/qsgbasicrectanglenode_p.h>
+#include <private/qsgbasicinternalrectanglenode_p.h>
#include <QtQuick/qsgvertexcolormaterial.h>
QT_BEGIN_NAMESPACE
@@ -65,17 +65,17 @@ class Q_QUICK_PRIVATE_EXPORT QSGSmoothColorMaterial : public QSGMaterial
public:
QSGSmoothColorMaterial();
- int compare(const QSGMaterial *other) const;
+ int compare(const QSGMaterial *other) const override;
protected:
QSGMaterialType *type() const override;
QSGMaterialShader *createShader() const override;
};
-class Q_QUICK_PRIVATE_EXPORT QSGDefaultRectangleNode : public QSGBasicRectangleNode
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultInternalRectangleNode : public QSGBasicInternalRectangleNode
{
public:
- QSGDefaultRectangleNode();
+ QSGDefaultInternalRectangleNode();
private:
void updateMaterialAntialiasing() override;
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index 92e7f983a0..6f10611ba3 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -70,6 +70,9 @@ QSGDefaultRenderContext::QSGDefaultRenderContext(QSGContext *context)
*/
void QSGDefaultRenderContext::initialize(void *context)
{
+ if (!m_sg)
+ return;
+
QOpenGLContext *openglContext = static_cast<QOpenGLContext *>(context);
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
@@ -163,7 +166,9 @@ void QSGDefaultRenderContext::invalidate()
m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
m_gl = 0;
- QSGRenderContext::invalidate();
+ if (m_sg)
+ m_sg->renderContextInvalidated(this);
+ emit invalidated();
}
static QBasicMutex qsg_framerender_mutex;
@@ -273,7 +278,7 @@ void QSGDefaultRenderContext::initializeShader(QSGMaterialShader *shader)
shader->initialize();
}
-void QSGDefaultRenderContext::setAttachToGLContext(bool attach)
+void QSGDefaultRenderContext::setAttachToGraphicsContext(bool attach)
{
Q_ASSERT(!isValid());
m_attachToGLContext = attach;
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
index bfb15b1eb9..0aed46b658 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h
+++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
@@ -64,7 +64,7 @@ namespace QSGAtlasTexture {
class Manager;
}
-class QSGDefaultRenderContext : public QSGRenderContext
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultRenderContext : public QSGRenderContext
{
Q_OBJECT
public:
@@ -88,12 +88,12 @@ public:
virtual void compileShader(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0);
virtual void initializeShader(QSGMaterialShader *shader);
- void setAttachToGLContext(bool attach);
+ void setAttachToGraphicsContext(bool attach) override;
static QSGDefaultRenderContext *from(QOpenGLContext *context);
bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
- int maxTextureSize() const { return m_maxTextureSize; }
+ int maxTextureSize() const override { return m_maxTextureSize; }
protected:
QOpenGLContext *m_gl;
diff --git a/src/quick/scenegraph/qsgdefaultspritenode.cpp b/src/quick/scenegraph/qsgdefaultspritenode.cpp
new file mode 100644
index 0000000000..89b26f8660
--- /dev/null
+++ b/src/quick/scenegraph/qsgdefaultspritenode.cpp
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultspritenode_p.h"
+
+#include <QtQuick/QSGMaterial>
+#include <QtGui/QOpenGLShaderProgram>
+
+QT_BEGIN_NAMESPACE
+
+struct SpriteVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+};
+
+struct SpriteVertices {
+ SpriteVertex v1;
+ SpriteVertex v2;
+ SpriteVertex v3;
+ SpriteVertex v4;
+};
+
+class QQuickSpriteMaterial : public QSGMaterial
+{
+public:
+ QQuickSpriteMaterial();
+ ~QQuickSpriteMaterial();
+ QSGMaterialType *type() const override { static QSGMaterialType type; return &type; }
+ QSGMaterialShader *createShader() const override;
+ int compare(const QSGMaterial *other) const override
+ {
+ return this - static_cast<const QQuickSpriteMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ float animT;
+ float animX1;
+ float animY1;
+ float animX2;
+ float animY2;
+ float animW;
+ float animH;
+};
+
+QQuickSpriteMaterial::QQuickSpriteMaterial()
+ : texture(0)
+ , animT(0.0f)
+ , animX1(0.0f)
+ , animY1(0.0f)
+ , animX2(0.0f)
+ , animY2(0.0f)
+ , animW(1.0f)
+ , animH(1.0f)
+{
+ setFlag(Blending, true);
+}
+
+QQuickSpriteMaterial::~QQuickSpriteMaterial()
+{
+ delete texture;
+}
+
+class SpriteMaterialData : public QSGMaterialShader
+{
+public:
+ SpriteMaterialData()
+ : QSGMaterialShader()
+ {
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/sprite.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/sprite.frag"));
+ }
+
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE
+ {
+ QQuickSpriteMaterial *m = static_cast<QQuickSpriteMaterial *>(newEffect);
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT);
+ program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ void initialize() Q_DECL_OVERRIDE {
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_opacity_id = program()->uniformLocation("qt_Opacity");
+ m_animData_id = program()->uniformLocation("animData");
+ m_animPos_id = program()->uniformLocation("animPos");
+ }
+
+ char const *const *attributeNames() const Q_DECL_OVERRIDE {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ 0
+ };
+ return attr;
+ }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_animData_id;
+ int m_animPos_id;
+};
+
+QSGMaterialShader *QQuickSpriteMaterial::createShader() const
+{
+ return new SpriteMaterialData;
+}
+
+static QSGGeometry::Attribute Sprite_Attributes[] = {
+ QSGGeometry::Attribute::create(0, 2, QSGGeometry::TypeFloat, true), // pos
+ QSGGeometry::Attribute::create(1, 2, QSGGeometry::TypeFloat), // tex
+};
+
+static QSGGeometry::AttributeSet Sprite_AttributeSet =
+{
+ 2, // Attribute Count
+ (2+2) * sizeof(float),
+ Sprite_Attributes
+};
+
+QSGDefaultSpriteNode::QSGDefaultSpriteNode()
+ : m_material(new QQuickSpriteMaterial)
+ , m_geometryDirty(true)
+ , m_sheetSize(QSize(64, 64))
+{
+ // Setup geometry data
+ m_geometry = new QSGGeometry(Sprite_AttributeSet, 4, 6);
+ m_geometry->setDrawingMode(QSGGeometry::DrawTriangles);
+ quint16 *indices = m_geometry->indexDataAsUShort();
+ indices[0] = 0;
+ indices[1] = 1;
+ indices[2] = 2;
+ indices[3] = 1;
+ indices[4] = 3;
+ indices[5] = 2;
+
+ setGeometry(m_geometry);
+ setMaterial(m_material);
+ setFlag(OwnsGeometry, true);
+ setFlag(OwnsMaterial, true);
+}
+
+void QSGDefaultSpriteNode::setTexture(QSGTexture *texture)
+{
+ m_material->texture = texture;
+ m_geometryDirty = true;
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultSpriteNode::setTime(float time)
+{
+ m_material->animT = time;
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultSpriteNode::setSourceA(const QPoint &source)
+{
+ if (m_sourceA != source) {
+ m_sourceA = source;
+ m_material->animX1 = static_cast<float>(source.x()) / m_sheetSize.width();
+ m_material->animY1 = static_cast<float>(source.y()) / m_sheetSize.height();
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGDefaultSpriteNode::setSourceB(const QPoint &source)
+{
+ if (m_sourceB != source) {
+ m_sourceB = source;
+ m_material->animX2 = static_cast<float>(source.x()) / m_sheetSize.width();
+ m_material->animY2 = static_cast<float>(source.y()) / m_sheetSize.height();
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGDefaultSpriteNode::setSpriteSize(const QSize &size)
+{
+ if (m_spriteSize != size) {
+ m_spriteSize = size;
+ m_material->animW = static_cast<float>(size.width()) / m_sheetSize.width();
+ m_material->animH = static_cast<float>(size.height()) / m_sheetSize.height();
+ markDirty(DirtyMaterial);
+ }
+
+}
+
+void QSGDefaultSpriteNode::setSheetSize(const QSize &size)
+{
+ if (m_sheetSize != size) {
+ m_sheetSize = size;
+
+ // Update all dependent properties
+ m_material->animX1 = static_cast<float>(m_sourceA.x()) / m_sheetSize.width();
+ m_material->animY1 = static_cast<float>(m_sourceA.y()) / m_sheetSize.height();
+ m_material->animX2 = static_cast<float>(m_sourceB.x()) / m_sheetSize.width();
+ m_material->animY2 = static_cast<float>(m_sourceB.y()) / m_sheetSize.height();
+ m_material->animW = static_cast<float>(m_spriteSize.width()) / m_sheetSize.width();
+ m_material->animH = static_cast<float>(m_spriteSize.height()) / m_sheetSize.height();
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGDefaultSpriteNode::setSize(const QSizeF &size)
+{
+ if (m_size != size) {
+ m_size = size;
+ m_geometryDirty = true;
+ }
+}
+
+void QSGDefaultSpriteNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ m_material->texture->setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultSpriteNode::update()
+{
+ if (m_geometryDirty) {
+ updateGeometry();
+ m_geometryDirty = false;
+ }
+}
+
+void QSGDefaultSpriteNode::updateGeometry()
+{
+ if (!m_material->texture)
+ return;
+
+ SpriteVertices *p = (SpriteVertices *) m_geometry->vertexData();
+
+ QRectF texRect = m_material->texture->normalizedTextureSubRect();
+
+ p->v1.tx = texRect.topLeft().x();
+ p->v1.ty = texRect.topLeft().y();
+
+ p->v2.tx = texRect.topRight().x();
+ p->v2.ty = texRect.topRight().y();
+
+ p->v3.tx = texRect.bottomLeft().x();
+ p->v3.ty = texRect.bottomLeft().y();
+
+ p->v4.tx = texRect.bottomRight().x();
+ p->v4.ty = texRect.bottomRight().y();
+
+ p->v1.x = 0;
+ p->v1.y = 0;
+
+ p->v2.x = m_size.width();
+ p->v2.y = 0;
+
+ p->v3.x = 0;
+ p->v3.y = m_size.height();
+
+ p->v4.x = m_size.width();
+ p->v4.y = m_size.height();
+ markDirty(DirtyGeometry);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultspritenode_p.h b/src/quick/scenegraph/qsgdefaultspritenode_p.h
new file mode 100644
index 0000000000..cb76bf8d83
--- /dev/null
+++ b/src/quick/scenegraph/qsgdefaultspritenode_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDEFAULTSPRITENODE_H
+#define QSGDEFAULTSPRITENODE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+class QQuickSpriteMaterial;
+class QSGDefaultSpriteNode : public QSGSpriteNode
+{
+public:
+ QSGDefaultSpriteNode();
+
+ void setTexture(QSGTexture *texture) override;
+ void setTime(float time) override;
+ void setSourceA(const QPoint &source) override;
+ void setSourceB(const QPoint &source) override;
+ void setSpriteSize(const QSize &size) override;
+ void setSheetSize(const QSize &size) override;
+ void setSize(const QSizeF &size) override;
+ void setFiltering(QSGTexture::Filtering filtering) override;
+ void update() override;
+private:
+ void updateGeometry();
+
+ QQuickSpriteMaterial *m_material;
+ QSGGeometry *m_geometry;
+ bool m_geometryDirty;
+ QPoint m_sourceA;
+ QPoint m_sourceB;
+ QSize m_spriteSize;
+ QSize m_sheetSize;
+ QSizeF m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGDEFAULTSPRITENODE_H
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 1a9b576af4..a59f9ddcc7 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -100,7 +100,7 @@ void QSGRenderLoop::cleanup()
{
if (!s_instance)
return;
- foreach (QQuickWindow *w, s_instance->windows()) {
+ for (QQuickWindow *w : s_instance->windows()) {
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(w);
if (wd->windowManager == s_instance) {
s_instance->windowDestroyed(w);
@@ -209,11 +209,11 @@ QSGRenderLoop *QSGRenderLoop::instance()
if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_RENDER_LOOP"))) {
const QByteArray loopName = qgetenv("QSG_RENDER_LOOP");
- if (loopName == QByteArrayLiteral("windows"))
+ if (loopName == "windows")
loopType = WindowsRenderLoop;
- else if (loopName == QByteArrayLiteral("basic"))
+ else if (loopName == "basic")
loopType = BasicRenderLoop;
- else if (loopName == QByteArrayLiteral("threaded"))
+ else if (loopName == "threaded")
loopType = ThreadedRenderLoop;
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 3ff32b360d..6b9c67b2bd 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -600,7 +600,7 @@ void QSGRenderThread::syncAndRender()
#endif
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
- if (!syncResultedInChanges && !repaintRequested) {
+ if (!syncResultedInChanges && !repaintRequested && sgrc->isValid()) {
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted";
int waitTime = vsyncDelta - (int) waitTimer.elapsed();
if (waitTime > 0)
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 371f512c6e..743e524a36 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -263,7 +263,7 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
bool QSGWindowsRenderLoop::anyoneShowing() const
{
- foreach (const WindowData &wd, m_windows)
+ for (const WindowData &wd : qAsConst(m_windows))
if (wd.window->isVisible() && wd.window->isExposed() && wd.window->size().isValid())
return true;
return false;
@@ -382,7 +382,7 @@ void QSGWindowsRenderLoop::render()
{
RLDEBUG("render");
bool rendered = false;
- foreach (const WindowData &wd, m_windows) {
+ for (const WindowData &wd : qAsConst(m_windows)) {
if (wd.pendingUpdate) {
const_cast<WindowData &>(wd).pendingUpdate = false;
renderWindow(wd.window);
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index d8dfd01e7a..a659ca5e10 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -1,5 +1,3 @@
-!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL
-
# DEFINES += QSG_SEPARATE_INDEX_BUFFER
# DEFINES += QSG_DISTANCEFIELD_CACHE_DEBUG
@@ -29,7 +27,7 @@ SOURCES += \
$$PWD/coreapi/qsgrendernode.cpp \
$$PWD/coreapi/qsgrendererinterface.cpp
-contains(QT_CONFIG, opengl(es1|es2)?) {
+qtConfig(opengl(es1|es2)?) {
HEADERS += \
$$PWD/coreapi/qsgbatchrenderer_p.h
SOURCES += \
@@ -52,7 +50,10 @@ HEADERS += \
$$PWD/util/qsgsimplematerial.h \
$$PWD/util/qsgtexturematerial.h \
$$PWD/util/qsgtexturematerial_p.h \
- $$PWD/util/qsgvertexcolormaterial.h
+ $$PWD/util/qsgvertexcolormaterial.h \
+ $$PWD/util/qsgrectanglenode.h \
+ $$PWD/util/qsgimagenode.h \
+ $$PWD/util/qsgninepatchnode.h
SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
@@ -65,8 +66,12 @@ SOURCES += \
$$PWD/util/qsgflatcolormaterial.cpp \
$$PWD/util/qsgsimplematerial.cpp \
$$PWD/util/qsgtexturematerial.cpp \
- $$PWD/util/qsgvertexcolormaterial.cpp
-contains(QT_CONFIG, opengl(es1|es2)?) {
+ $$PWD/util/qsgvertexcolormaterial.cpp \
+ $$PWD/util/qsgrectanglenode.cpp \
+ $$PWD/util/qsgimagenode.cpp \
+ $$PWD/util/qsgninepatchnode.cpp
+
+qtConfig(opengl(es1|es2)?) {
HEADERS += \
$$PWD/util/qsgdepthstencilbuffer_p.h \
$$PWD/util/qsgshadersourcebuilder_p.h \
@@ -83,8 +88,8 @@ HEADERS += \
$$PWD/qsgadaptationlayer_p.h \
$$PWD/qsgcontext_p.h \
$$PWD/qsgcontextplugin_p.h \
- $$PWD/qsgbasicrectanglenode_p.h \
- $$PWD/qsgbasicimagenode_p.h \
+ $$PWD/qsgbasicinternalrectanglenode_p.h \
+ $$PWD/qsgbasicinternalimagenode_p.h \
$$PWD/qsgbasicglyphnode_p.h \
$$PWD/qsgrenderloop_p.h
@@ -92,23 +97,27 @@ SOURCES += \
$$PWD/qsgadaptationlayer.cpp \
$$PWD/qsgcontext.cpp \
$$PWD/qsgcontextplugin.cpp \
- $$PWD/qsgbasicrectanglenode.cpp \
- $$PWD/qsgbasicimagenode.cpp \
+ $$PWD/qsgbasicinternalrectanglenode.cpp \
+ $$PWD/qsgbasicinternalimagenode.cpp \
$$PWD/qsgbasicglyphnode.cpp \
$$PWD/qsgrenderloop.cpp
-contains(QT_CONFIG, opengl(es1|es2)?) {
+qtConfig(opengl(es1|es2)?) {
SOURCES += \
$$PWD/qsgdefaultglyphnode.cpp \
$$PWD/qsgdefaultglyphnode_p.cpp \
$$PWD/qsgdefaultdistancefieldglyphcache.cpp \
$$PWD/qsgdistancefieldglyphnode.cpp \
$$PWD/qsgdistancefieldglyphnode_p.cpp \
- $$PWD/qsgdefaultimagenode.cpp \
- $$PWD/qsgdefaultrectanglenode.cpp \
+ $$PWD/qsgdefaultinternalimagenode.cpp \
+ $$PWD/qsgdefaultinternalrectanglenode.cpp \
$$PWD/qsgdefaultrendercontext.cpp \
$$PWD/qsgdefaultcontext.cpp \
+ $$PWD/qsgdefaultspritenode.cpp \
$$PWD/util/qsgdefaultpainternode.cpp \
+ $$PWD/util/qsgdefaultrectanglenode.cpp \
+ $$PWD/util/qsgdefaultimagenode.cpp \
+ $$PWD/util/qsgdefaultninepatchnode.cpp \
$$PWD/qsgdefaultlayer.cpp \
$$PWD/qsgthreadedrenderloop.cpp \
$$PWD/qsgwindowsrenderloop.cpp
@@ -118,11 +127,15 @@ contains(QT_CONFIG, opengl(es1|es2)?) {
$$PWD/qsgdistancefieldglyphnode_p.h \
$$PWD/qsgdistancefieldglyphnode_p_p.h \
$$PWD/qsgdefaultglyphnode_p_p.h \
- $$PWD/qsgdefaultimagenode_p.h \
- $$PWD/qsgdefaultrectanglenode_p.h \
+ $$PWD/qsgdefaultinternalimagenode_p.h \
+ $$PWD/qsgdefaultinternalrectanglenode_p.h \
+ $$PWD/qsgdefaultspritenode_p.h \
$$PWD/qsgdefaultrendercontext_p.h \
$$PWD/qsgdefaultcontext_p.h \
$$PWD/util/qsgdefaultpainternode_p.h \
+ $$PWD/util/qsgdefaultrectanglenode_p.h \
+ $$PWD/util/qsgdefaultimagenode_p.h \
+ $$PWD/util/qsgdefaultninepatchnode_p.h \
$$PWD/qsgdefaultlayer_p.h \
$$PWD/qsgthreadedrenderloop_p.h \
$$PWD/qsgwindowsrenderloop_p.h
@@ -135,7 +148,7 @@ RESOURCES += \
$$PWD/scenegraph.qrc
# OpenGL Shaders
-contains(QT_CONFIG, opengl(es1|es2)?) {
+qtConfig(opengl(es1|es2)?) {
OTHER_FILES += \
$$PWD/shaders/24bittextmask.frag \
$$PWD/shaders/8bittextmask.frag \
diff --git a/src/quick/scenegraph/scenegraph.qrc b/src/quick/scenegraph/scenegraph.qrc
index ef6da71334..0687530be1 100644
--- a/src/quick/scenegraph/scenegraph.qrc
+++ b/src/quick/scenegraph/scenegraph.qrc
@@ -68,5 +68,9 @@
<file>shaders/vertexcolor_core.vert</file>
<file>shaders/visualization.vert</file>
<file>shaders/visualization.frag</file>
+ <file>shaders/sprite.frag</file>
+ <file>shaders/sprite.vert</file>
+ <file>shaders/sprite_core.frag</file>
+ <file>shaders/sprite_core.vert</file>
</qresource>
</RCC>
diff --git a/src/quick/items/shaders/sprite.frag b/src/quick/scenegraph/shaders/sprite.frag
index e1fcb0f006..e1fcb0f006 100644
--- a/src/quick/items/shaders/sprite.frag
+++ b/src/quick/scenegraph/shaders/sprite.frag
diff --git a/src/quick/items/shaders/sprite.vert b/src/quick/scenegraph/shaders/sprite.vert
index fc826f60b4..fc826f60b4 100644
--- a/src/quick/items/shaders/sprite.vert
+++ b/src/quick/scenegraph/shaders/sprite.vert
diff --git a/src/quick/items/shaders/sprite_core.frag b/src/quick/scenegraph/shaders/sprite_core.frag
index c1087a8754..c1087a8754 100644
--- a/src/quick/items/shaders/sprite_core.frag
+++ b/src/quick/scenegraph/shaders/sprite_core.frag
diff --git a/src/quick/items/shaders/sprite_core.vert b/src/quick/scenegraph/shaders/sprite_core.vert
index 5027bf03fc..5027bf03fc 100644
--- a/src/quick/items/shaders/sprite_core.vert
+++ b/src/quick/scenegraph/shaders/sprite_core.vert
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index 098a4a666b..40c3293c7b 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -158,13 +158,13 @@ Atlas::Atlas(const QSize &size)
wrongfullyReportsBgra8888Support = false;
const char *ext = (const char *) QOpenGLContext::currentContext()->functions()->glGetString(GL_EXTENSIONS);
- if (!wrongfullyReportsBgra8888Support
+ if (ext && !wrongfullyReportsBgra8888Support
&& (strstr(ext, "GL_EXT_bgra")
|| strstr(ext, "GL_EXT_texture_format_BGRA8888")
|| strstr(ext, "GL_IMG_texture_format_BGRA8888"))) {
m_internalFormat = m_externalFormat = GL_BGRA;
#if defined(Q_OS_DARWIN) && !defined(Q_OS_OSX)
- } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) {
+ } else if (ext && strstr(ext, "GL_APPLE_texture_format_BGRA8888")) {
m_internalFormat = GL_RGBA;
m_externalFormat = GL_BGRA;
#endif // IOS || TVOS
diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h
index cd24645fcf..3dee539547 100644
--- a/src/quick/scenegraph/util/qsgatlastexture_p.h
+++ b/src/quick/scenegraph/util/qsgatlastexture_p.h
@@ -131,26 +131,26 @@ public:
Texture(Atlas *atlas, const QRect &textureRect, const QImage &image);
~Texture();
- int textureId() const { return m_atlas->textureId(); }
- QSize textureSize() const { return atlasSubRectWithoutPadding().size(); }
+ int textureId() const override { return m_atlas->textureId(); }
+ QSize textureSize() const override { return atlasSubRectWithoutPadding().size(); }
void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; }
- bool hasAlphaChannel() const { return m_has_alpha; }
- bool hasMipmaps() const { return false; }
- bool isAtlasTexture() const { return true; }
+ bool hasAlphaChannel() const override { return m_has_alpha; }
+ bool hasMipmaps() const override { return false; }
+ bool isAtlasTexture() const override { return true; }
- QRectF normalizedTextureSubRect() const { return m_texture_coords_rect; }
+ QRectF normalizedTextureSubRect() const override { return m_texture_coords_rect; }
QRect atlasSubRect() const { return m_allocated_rect; }
QRect atlasSubRectWithoutPadding() const { return m_allocated_rect.adjusted(1, 1, -1, -1); }
bool isTexture() const { return true; }
- QSGTexture *removedFromAtlas() const;
+ QSGTexture *removedFromAtlas() const override;
void releaseImage() { m_image = QImage(); }
const QImage &image() const { return m_image; }
- void bind();
+ void bind() override;
private:
QRect m_allocated_rect;
diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp
new file mode 100644
index 0000000000..6afe591dca
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultimagenode_p.h"
+#include <private/qsgnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultImageNode::QSGDefaultImageNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+ , m_texCoordMode(QSGDefaultImageNode::NoTransform)
+ , m_isAtlasTexture(false)
+ , m_ownsTexture(false)
+{
+ setGeometry(&m_geometry);
+ setMaterial(&m_material);
+ setOpaqueMaterial(&m_opaque_material);
+ m_material.setMipmapFiltering(QSGTexture::None);
+ m_opaque_material.setMipmapFiltering(QSGTexture::None);
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(this, QLatin1String("image"));
+#endif
+}
+
+QSGDefaultImageNode::~QSGDefaultImageNode()
+{
+ if (m_ownsTexture)
+ delete m_material.texture();
+}
+
+void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ m_opaque_material.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture::Filtering QSGDefaultImageNode::filtering() const
+{
+ return m_material.filtering();
+}
+
+void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.mipmapFiltering() == filtering)
+ return;
+
+ m_material.setMipmapFiltering(filtering);
+ m_opaque_material.setMipmapFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture::Filtering QSGDefaultImageNode::mipmapFiltering() const
+{
+ return m_material.mipmapFiltering();
+}
+
+void QSGDefaultImageNode::setRect(const QRectF &r)
+{
+ if (m_rect == r)
+ return;
+
+ m_rect = r;
+ rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode);
+ markDirty(DirtyGeometry);
+}
+
+QRectF QSGDefaultImageNode::rect() const
+{
+ return m_rect;
+}
+
+void QSGDefaultImageNode::setSourceRect(const QRectF &r)
+{
+ if (m_sourceRect == r)
+ return;
+
+ m_sourceRect = r;
+ rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode);
+ markDirty(DirtyGeometry);
+}
+
+QRectF QSGDefaultImageNode::sourceRect() const
+{
+ return m_sourceRect;
+}
+
+void QSGDefaultImageNode::setTexture(QSGTexture *texture)
+{
+ Q_ASSERT(texture);
+ if (m_ownsTexture)
+ delete m_material.texture();
+ m_material.setTexture(texture);
+ m_opaque_material.setTexture(texture);
+ rebuildGeometry(&m_geometry, texture, m_rect, m_sourceRect, m_texCoordMode);
+
+ DirtyState dirty = DirtyMaterial;
+ // It would be tempting to skip the extra bit here and instead use
+ // m_material.texture to get the old state, but that texture could
+ // have been deleted in the mean time.
+ bool wasAtlas = m_isAtlasTexture;
+ m_isAtlasTexture = texture->isAtlasTexture();
+ if (wasAtlas || m_isAtlasTexture)
+ dirty |= DirtyGeometry;
+ markDirty(dirty);
+}
+
+QSGTexture *QSGDefaultImageNode::texture() const
+{
+ return m_material.texture();
+}
+
+void QSGDefaultImageNode::setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode)
+{
+ if (m_texCoordMode == mode)
+ return;
+ m_texCoordMode = mode;
+ rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode);
+ markDirty(DirtyMaterial);
+}
+
+QSGDefaultImageNode::TextureCoordinatesTransformMode QSGDefaultImageNode::textureCoordinatesTransform() const
+{
+ return m_texCoordMode;
+}
+
+void QSGDefaultImageNode::setOwnsTexture(bool owns)
+{
+ m_ownsTexture = owns;
+}
+
+bool QSGDefaultImageNode::ownsTexture() const
+{
+ return m_ownsTexture;
+}
+
+void QSGDefaultImageNode::rebuildGeometry(QSGGeometry *g,
+ QSGTexture *texture,
+ const QRectF &rect,
+ QRectF sourceRect,
+ TextureCoordinatesTransformMode texCoordMode)
+{
+ if (!texture)
+ return;
+
+ if (!sourceRect.width() || !sourceRect.height()) {
+ QSize ts = texture->textureSize();
+ sourceRect = QRectF(0, 0, ts.width(), ts.height());
+ }
+
+ // Maybe transform the texture coordinates
+ if (texCoordMode.testFlag(QSGImageNode::MirrorHorizontally)) {
+ float tmp = sourceRect.left();
+ sourceRect.setLeft(sourceRect.right());
+ sourceRect.setRight(tmp);
+ }
+ if (texCoordMode.testFlag(QSGImageNode::MirrorVertically)) {
+ float tmp = sourceRect.top();
+ sourceRect.setTop(sourceRect.bottom());
+ sourceRect.setBottom(tmp);
+ }
+
+ QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect));
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h
new file mode 100644
index 0000000000..eb6c487c18
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDEFAULTIMAGENODE_P_H
+#define QSGDEFAULTIMAGENODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qtquickglobal_p.h>
+#include <QtQuick/qsgimagenode.h>
+#include <QtQuick/qsggeometry.h>
+#include <QtQuick/qsgtexturematerial.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultImageNode : public QSGImageNode
+{
+public:
+ QSGDefaultImageNode();
+ ~QSGDefaultImageNode();
+
+ void setRect(const QRectF &rect) override;
+ QRectF rect() const override;
+
+ void setSourceRect(const QRectF &r) override;
+ QRectF sourceRect() const override;
+
+ void setTexture(QSGTexture *texture) override;
+ QSGTexture *texture() const override;
+
+ void setFiltering(QSGTexture::Filtering filtering) override;
+ QSGTexture::Filtering filtering() const override;
+
+ void setMipmapFiltering(QSGTexture::Filtering filtering) override;
+ QSGTexture::Filtering mipmapFiltering() const override;
+
+ void setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode) override;
+ TextureCoordinatesTransformMode textureCoordinatesTransform() const override;
+
+ void setOwnsTexture(bool owns) override;
+ bool ownsTexture() const override;
+
+ static void rebuildGeometry(QSGGeometry *g,
+ QSGTexture *texture,
+ const QRectF &rect,
+ QRectF sourceRect,
+ TextureCoordinatesTransformMode texCoordMode);
+
+private:
+ QSGGeometry m_geometry;
+ QSGOpaqueTextureMaterial m_opaque_material;
+ QSGTextureMaterial m_material;
+ QRectF m_rect;
+ QRectF m_sourceRect;
+ TextureCoordinatesTransformMode m_texCoordMode;
+ uint m_isAtlasTexture : 1;
+ uint m_ownsTexture : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGDEFAULTIMAGENODE_P_H
diff --git a/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp b/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp
new file mode 100644
index 0000000000..e5a53a3617
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultninepatchnode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultNinePatchNode::QSGDefaultNinePatchNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ m_geometry.setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ setGeometry(&m_geometry);
+ setMaterial(&m_material);
+}
+
+QSGDefaultNinePatchNode::~QSGDefaultNinePatchNode()
+{
+ delete m_material.texture();
+}
+
+void QSGDefaultNinePatchNode::setTexture(QSGTexture *texture)
+{
+ delete m_material.texture();
+ m_material.setTexture(texture);
+}
+
+void QSGDefaultNinePatchNode::setBounds(const QRectF &bounds)
+{
+ m_bounds = bounds;
+}
+
+void QSGDefaultNinePatchNode::setDevicePixelRatio(qreal ratio)
+{
+ m_devicePixelRatio = ratio;
+}
+
+void QSGDefaultNinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom)
+{
+ m_padding = QVector4D(left, top, right, bottom);
+}
+
+void QSGDefaultNinePatchNode::update()
+{
+ rebuildGeometry(m_material.texture(), &m_geometry, m_padding, m_bounds, m_devicePixelRatio);
+ markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial);
+}
+
+void QSGDefaultNinePatchNode::rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, const QVector4D &padding,
+ const QRectF &bounds, qreal dpr)
+{
+ if (padding.x() <= 0 && padding.y() <= 0 && padding.z() <= 0 && padding.w() <= 0) {
+ geometry->allocate(4, 0);
+ QSGGeometry::updateTexturedRectGeometry(geometry, bounds, texture->normalizedTextureSubRect());
+ return;
+ }
+
+ QRectF tc = texture->normalizedTextureSubRect();
+ QSize ts = texture->textureSize();
+ ts.setHeight(ts.height() / dpr);
+ ts.setWidth(ts.width() / dpr);
+
+ qreal invtw = tc.width() / ts.width();
+ qreal invth = tc.height() / ts.height();
+
+ struct Coord { qreal p; qreal t; };
+ Coord cx[4] = { { bounds.left(), tc.left() },
+ { bounds.left() + padding.x(), tc.left() + padding.x() * invtw },
+ { bounds.right() - padding.z(), tc.right() - padding.z() * invtw },
+ { bounds.right(), tc.right() }
+ };
+ Coord cy[4] = { { bounds.top(), tc.top() },
+ { bounds.top() + padding.y(), tc.top() + padding.y() * invth },
+ { bounds.bottom() - padding.w(), tc.bottom() - padding.w() * invth },
+ { bounds.bottom(), tc.bottom() }
+ };
+
+ geometry->allocate(16, 28);
+ QSGGeometry::TexturedPoint2D *v = geometry->vertexDataAsTexturedPoint2D();
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ v->set(cx[x].p, cy[y].p, cx[x].t, cy[y].t);
+ ++v;
+ }
+ }
+
+ quint16 *i = geometry->indexDataAsUShort();
+ for (int r = 0; r < 3; ++r) {
+ if (r > 0)
+ *i++ = 4 * r;
+ for (int c = 0; c < 4; ++c) {
+ i[0] = 4 * r + c;
+ i[1] = 4 * r + c + 4;
+ i += 2;
+ }
+ if (r < 2)
+ *i++ = 4 * r + 3 + 4;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h b/src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h
index bc7aec1b5a..675cf48f47 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h
+++ b/src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h
@@ -37,10 +37,8 @@
**
****************************************************************************/
-#ifndef QSGSOFTWARENINEPATCHNODE_H
-#define QSGSOFTWARENINEPATCHNODE_H
-
-#include <private/qsgadaptationlayer_p.h>
+#ifndef QSGDEFAULTNINEPATCHNODE_P_H
+#define QSGDEFAULTNINEPATCHNODE_P_H
//
// W A R N I N G
@@ -53,12 +51,18 @@
// We mean it.
//
+#include <private/qtquickglobal_p.h>
+#include <QtQuick/qsgninepatchnode.h>
+#include <QtQuick/qsggeometry.h>
+#include <QtQuick/qsgtexturematerial.h>
+
QT_BEGIN_NAMESPACE
-class QSGSoftwareNinePatchNode : public QSGNinePatchNode
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultNinePatchNode : public QSGNinePatchNode
{
public:
- QSGSoftwareNinePatchNode();
+ QSGDefaultNinePatchNode();
+ ~QSGDefaultNinePatchNode();
void setTexture(QSGTexture *texture) override;
void setBounds(const QRectF &bounds) override;
@@ -66,17 +70,17 @@ public:
void setPadding(qreal left, qreal top, qreal right, qreal bottom) override;
void update() override;
- void paint(QPainter *painter);
-
- QRectF bounds() const;
+ static void rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, const QVector4D &padding,
+ const QRectF &bounds, qreal dpr);
private:
- QPixmap m_pixmap;
QRectF m_bounds;
- qreal m_pixelRatio;
- QMargins m_margins;
+ qreal m_devicePixelRatio;
+ QVector4D m_padding;
+ QSGGeometry m_geometry;
+ QSGTextureMaterial m_material;
};
QT_END_NAMESPACE
-#endif // QSGSOFTWARENINEPATCHNODE_H
+#endif // QSGDEFAULTNINEPATCHNODE_P_H
diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
index 4dd60c76f5..e1aea290a3 100644
--- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
@@ -225,7 +225,7 @@ void QSGDefaultPainterNode::updateGeometry()
if (m_actualRenderTarget == QQuickPaintedItem::Image)
source = QRectF(0, 0, 1, 1);
else
- source = QRectF(0, 0, qreal(m_size.width()) / m_fboSize.width(), qreal(m_size.height()) / m_fboSize.height());
+ source = QRectF(0, 0, qreal(m_textureSize.width()) / m_fboSize.width(), qreal(m_textureSize.height()) / m_fboSize.height());
QRectF dest(0, 0, m_size.width(), m_size.height());
if (m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject)
dest = QRectF(QPointF(0, m_size.height()), QPointF(m_size.width(), 0));
@@ -307,7 +307,7 @@ void QSGDefaultPainterNode::updateRenderTarget()
QSGPainterTexture *texture = new QSGPainterTexture;
if (m_actualRenderTarget == QQuickPaintedItem::Image) {
texture->setOwnsTexture(true);
- texture->setTextureSize(m_size);
+ texture->setTextureSize(m_textureSize);
} else {
texture->setTextureId(m_fbo->texture());
texture->setOwnsTexture(false);
@@ -317,7 +317,6 @@ void QSGDefaultPainterNode::updateRenderTarget()
if (m_texture)
delete m_texture;
- texture->setTextureSize(m_size);
m_texture = texture;
}
diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
index 069ef155b1..a433b3292a 100644
--- a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
+++ b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
@@ -72,7 +72,7 @@ public:
void setDirtyRect(const QRect &rect) { m_dirty_rect = rect; }
- void bind();
+ void bind() override;
private:
QRect m_dirty_rect;
@@ -84,43 +84,43 @@ public:
QSGDefaultPainterNode(QQuickPaintedItem *item);
virtual ~QSGDefaultPainterNode();
- void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target);
+ void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target) override;
- void setSize(const QSize &size);
+ void setSize(const QSize &size) override;
QSize size() const { return m_size; }
- void setDirty(const QRect &dirtyRect = QRect());
+ void setDirty(const QRect &dirtyRect = QRect()) override;
- void setOpaquePainting(bool opaque);
+ void setOpaquePainting(bool opaque) override;
bool opaquePainting() const { return m_opaquePainting; }
- void setLinearFiltering(bool linearFiltering);
+ void setLinearFiltering(bool linearFiltering) override;
bool linearFiltering() const { return m_linear_filtering; }
- void setMipmapping(bool mipmapping);
+ void setMipmapping(bool mipmapping) override;
bool mipmapping() const { return m_mipmapping; }
- void setSmoothPainting(bool s);
+ void setSmoothPainting(bool s) override;
bool smoothPainting() const { return m_smoothPainting; }
- void setFillColor(const QColor &c);
+ void setFillColor(const QColor &c) override;
QColor fillColor() const { return m_fillColor; }
- void setContentsScale(qreal s);
+ void setContentsScale(qreal s) override;
qreal contentsScale() const { return m_contentsScale; }
- void setFastFBOResizing(bool dynamic);
+ void setFastFBOResizing(bool dynamic) override;
bool fastFBOResizing() const { return m_fastFBOResizing; }
- void setTextureSize(const QSize &textureSize);
+ void setTextureSize(const QSize &textureSize) override;
QSize textureSize() const { return m_textureSize; }
- QImage toImage() const;
- void update();
+ QImage toImage() const override;
+ void update() override;
void paint();
- QSGTexture *texture() const { return m_texture; }
+ QSGTexture *texture() const override { return m_texture; }
private:
void updateTexture();
diff --git a/src/quick/scenegraph/util/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/util/qsgdefaultrectanglenode.cpp
new file mode 100644
index 0000000000..e1c8672add
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgdefaultrectanglenode.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultrectanglenode_p.h"
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_NAMESPACE
+
+// Unlike our predecessor, QSGSimpleRectNode, use QSGVertexColorMaterial
+// instead of Flat in order to allow better batching in the renderer.
+
+QSGDefaultRectangleNode::QSGDefaultRectangleNode()
+ : m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 4)
+{
+ QSGGeometry::updateColoredRectGeometry(&m_geometry, QRectF());
+ setMaterial(&m_material);
+ setGeometry(&m_geometry);
+ setColor(QColor(255, 255, 255));
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(this, QLatin1String("rectangle"));
+#endif
+}
+
+void QSGDefaultRectangleNode::setRect(const QRectF &rect)
+{
+ QSGGeometry::updateColoredRectGeometry(&m_geometry, rect);
+ markDirty(QSGNode::DirtyGeometry);
+}
+
+QRectF QSGDefaultRectangleNode::rect() const
+{
+ const QSGGeometry::ColoredPoint2D *pts = m_geometry.vertexDataAsColoredPoint2D();
+ return QRectF(pts[0].x,
+ pts[0].y,
+ pts[3].x - pts[0].x,
+ pts[3].y - pts[0].y);
+}
+
+void QSGDefaultRectangleNode::setColor(const QColor &color)
+{
+ if (color != m_color) {
+ m_color = color;
+ QSGGeometry::ColoredPoint2D *pts = m_geometry.vertexDataAsColoredPoint2D();
+ for (int i = 0; i < 4; ++i) {
+ pts[i].r = uchar(qRound(m_color.redF() * m_color.alphaF() * 255));
+ pts[i].g = uchar(qRound(m_color.greenF() * m_color.alphaF() * 255));
+ pts[i].b = uchar(qRound(m_color.blueF() * m_color.alphaF() * 255));
+ pts[i].a = uchar(qRound(m_color.alphaF() * 255));
+ }
+ markDirty(QSGNode::DirtyGeometry);
+ }
+}
+
+QColor QSGDefaultRectangleNode::color() const
+{
+ return m_color;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/util/qsgdefaultrectanglenode_p.h
new file mode 100644
index 0000000000..965aa8dabb
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgdefaultrectanglenode_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDEFAULTRECTANGLENODE_P_H
+#define QSGDEFAULTRECTANGLENODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qcolor.h>
+#include <QtQuick/qsgrectanglenode.h>
+#include <QtQuick/qsgvertexcolormaterial.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGDefaultRectangleNode : public QSGRectangleNode
+{
+public:
+ QSGDefaultRectangleNode();
+
+ void setRect(const QRectF &rect) override;
+ QRectF rect() const override;
+
+ void setColor(const QColor &color) override;
+ QColor color() const override;
+
+private:
+ QSGVertexColorMaterial m_material;
+ QSGGeometry m_geometry;
+ QColor m_color;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGDEFAULTRECTANGLENODE_P_H
diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h b/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h
index c2d0590532..f7c6923021 100644
--- a/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h
+++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h
@@ -119,7 +119,7 @@ public:
virtual ~QSGDefaultDepthStencilBuffer();
protected:
- virtual void free();
+ void free() override;
};
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
index 26a3d66077..ad1fcfa470 100644
--- a/src/quick/scenegraph/util/qsgengine.cpp
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -115,23 +115,21 @@ QSGEngine::~QSGEngine()
*/
void QSGEngine::initialize(QOpenGLContext *context)
{
-#ifndef QT_NO_OPENGL
Q_D(QSGEngine);
- if (QOpenGLContext::currentContext() != context) {
+#ifndef QT_NO_OPENGL
+ if (context && QOpenGLContext::currentContext() != context) {
qWarning("WARNING: The context must be current before calling QSGEngine::initialize.");
return;
}
-
- auto openGLRenderContext = static_cast<QSGDefaultRenderContext *>(d->sgRenderContext.data());
-
- if (openGLRenderContext != nullptr && !openGLRenderContext->isValid()) {
- openGLRenderContext->setAttachToGLContext(false);
- openGLRenderContext->initialize(context);
- connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &QSGEngine::invalidate);
- }
-#else
- Q_UNUSED(context)
#endif
+ if (d->sgRenderContext && !d->sgRenderContext->isValid()) {
+ d->sgRenderContext->setAttachToGraphicsContext(false);
+ d->sgRenderContext->initialize(context);
+#ifndef QT_NO_OPENGL
+ if (context)
+ connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &QSGEngine::invalidate);
+#endif
+ }
}
/*!
@@ -223,4 +221,45 @@ QSGRendererInterface *QSGEngine::rendererInterface() const
: nullptr;
}
+/*!
+ Creates a simple rectangle node. When the scenegraph is not initialized, the return value is null.
+
+ This is cross-backend alternative to constructing a QSGSimpleRectNode directly.
+
+ \since 5.8
+ \sa QSGRectangleNode
+ */
+QSGRectangleNode *QSGEngine::createRectangleNode() const
+{
+ Q_D(const QSGEngine);
+ return d->sgRenderContext->isValid() ? d->sgRenderContext->sceneGraphContext()->createRectangleNode() : nullptr;
+}
+
+/*!
+ Creates a simple image node. When the scenegraph is not initialized, the return value is null.
+
+ This is cross-backend alternative to constructing a QSGSimpleTextureNode directly.
+
+ \since 5.8
+ \sa QSGImageNode
+ */
+
+QSGImageNode *QSGEngine::createImageNode() const
+{
+ Q_D(const QSGEngine);
+ return d->sgRenderContext->isValid() ? d->sgRenderContext->sceneGraphContext()->createImageNode() : nullptr;
+}
+
+/*!
+ Creates a nine patch node. When the scenegraph is not initialized, the return value is null.
+
+ \since 5.8
+ */
+
+QSGNinePatchNode *QSGEngine::createNinePatchNode() const
+{
+ Q_D(const QSGEngine);
+ return d->sgRenderContext->isValid() ? d->sgRenderContext->sceneGraphContext()->createNinePatchNode() : nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h
index 9d27fb5525..3c8b61852e 100644
--- a/src/quick/scenegraph/util/qsgengine.h
+++ b/src/quick/scenegraph/util/qsgengine.h
@@ -50,6 +50,9 @@ class QSGAbstractRenderer;
class QSGEnginePrivate;
class QSGTexture;
class QSGRendererInterface;
+class QSGRectangleNode;
+class QSGImageNode;
+class QSGNinePatchNode;
class Q_QUICK_EXPORT QSGEngine : public QObject
{
@@ -74,6 +77,9 @@ public:
QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption()) const;
QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const;
QSGRendererInterface *rendererInterface() const;
+ QSGRectangleNode *createRectangleNode() const;
+ QSGImageNode *createImageNode() const;
+ QSGNinePatchNode *createNinePatchNode() const;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
index 5d7817163e..2ce27275cd 100644
--- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
@@ -57,9 +57,10 @@ public:
private:
virtual void initialize();
-
+#ifndef QT_NO_OPENGL
int m_matrix_id;
int m_color_id;
+#endif
};
QSGMaterialType FlatColorMaterialShader::type;
diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.h b/src/quick/scenegraph/util/qsgflatcolormaterial.h
index 7f292a2a9b..4829ac3279 100644
--- a/src/quick/scenegraph/util/qsgflatcolormaterial.h
+++ b/src/quick/scenegraph/util/qsgflatcolormaterial.h
@@ -49,13 +49,13 @@ class Q_QUICK_EXPORT QSGFlatColorMaterial : public QSGMaterial
{
public:
QSGFlatColorMaterial();
- virtual QSGMaterialType *type() const;
- virtual QSGMaterialShader *createShader() const;
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
void setColor(const QColor &color);
const QColor &color() const { return m_color; }
- int compare(const QSGMaterial *other) const;
+ int compare(const QSGMaterial *other) const override;
private:
QColor m_color;
diff --git a/src/quick/scenegraph/util/qsgimagenode.cpp b/src/quick/scenegraph/util/qsgimagenode.cpp
new file mode 100644
index 0000000000..a78bfc1c66
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgimagenode.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgimagenode.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGImageNode
+ \brief The QSGImageNode class is provided for convenience to easily draw
+ textured content using the QML scene graph.
+
+ \inmodule QtQuick
+ \since 5.8
+
+ \warning The image node class must have a texture before being
+ added to the scene graph to be rendered.
+ */
+
+/*!
+ \fn void QSGImageNode::setRect(const QRectF &rect)
+
+ Sets the target rect of this image node to \a rect.
+ */
+
+/*!
+ \fn void QSGImageNode::setRect(qreal x, qreal y, qreal w, qreal h)
+ \overload
+
+ Sets the rectangle of this image node to begin at (\a x, \a y) and have
+ width \a w and height \a h.
+ */
+
+/*!
+ \fn QRectF QSGImageNode::rect() const
+
+ Returns the target rect of this image node.
+ */
+
+/*!
+ \fn void QSGImageNode::setSourceRect(const QRectF &rect)
+
+ Sets the source rect of this image node to \a rect.
+ */
+
+/*!
+ \fn void QSGImageNode::setSourceRect(qreal x, qreal y, qreal w, qreal h)
+ \overload
+
+ Sets the rectangle of this image node to show its texture from (\a x, \a y) and
+ have width \a w and height \a h relatively to the QSGTexture::textureSize.
+ */
+
+/*!
+ \fn QRectF QSGImageNode::sourceRect() const
+
+ Returns the source rect of this image node.
+ */
+
+/*!
+ \fn void QSGImageNode::setTexture(QSGTexture *texture)
+
+ Sets the texture of this image node to \a texture.
+
+ Use setOwnsTexture() to set whether the node should take
+ ownership of the texture. By default, the node does not
+ take ownership.
+
+ \warning An image node must have a texture before being added to the
+ scenegraph to be rendered.
+ */
+
+/*!
+ \fn QSGTexture *QSGImageNode::texture() const
+
+ Returns the texture for this image node.
+ */
+
+/*!
+ \fn void QSGImageNode::setFiltering(QSGTexture::Filtering filtering)
+
+ Sets the filtering to be used for this image node to \a filtering.
+
+ For smooth scaling, use QSGTexture::Linear. For normal scaling, use
+ QSGTexture::Nearest.
+ */
+
+/*!
+ \fn QSGTexture::Filtering QSGImageNode::filtering() const
+
+ Returns the filtering for this image node.
+ */
+
+/*!
+ \fn void QSGImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
+
+ Sets the mipmap filtering to be used for this image node to \a filtering.
+
+ For smooth scaling between mip maps, use QSGTexture::Linear.
+ For normal scaling, use QSGTexture::Nearest.
+ */
+
+/*!
+ \fn QSGTexture::Filtering QSGImageNode::mipmapFiltering() const
+
+ Returns the mipmap filtering for this image node.
+ */
+
+/*!
+ \enum QSGImageNode::TextureCoordinatesTransformFlag
+
+ The TextureCoordinatesTransformFlag enum is used to specify the mode used
+ to generate texture coordinates for a textured quad.
+
+ \value NoTransform Texture coordinates are oriented with window coordinates
+ i.e. with origin at top-left.
+
+ \value MirrorHorizontally Texture coordinates are inverted in the horizontal axis with
+ respect to window coordinates
+
+ \value MirrorVertically Texture coordinates are inverted in the vertical axis with
+ respect to window coordinates
+ */
+
+/*!
+ \fn void QSGImageNode::setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode)
+
+ Sets the method used to generate texture coordinates to \a mode. This can
+ be used to obtain correct orientation of the texture. This is commonly
+ needed when using a third-party OpenGL library to render to texture as
+ OpenGL has an inverted y-axis relative to Qt Quick.
+ */
+
+/*!
+ \fn QSGImageNode::TextureCoordinatesTransformMode textureCoordinatesTransform() const
+
+ Returns the mode used to generate texture coordinates for this node.
+ */
+
+/*!
+ \fn void QSGImageNode::setOwnsTexture(bool owns)
+
+ Sets whether the node takes ownership of the texture to \a owns.
+
+ By default, the node does not take ownership of the texture.
+ */
+
+/*!
+ \fn bool QSGImageNode::ownsTexture() const
+
+ \return \c true if the node takes ownership of the texture; otherwise \c false.
+ */
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgimagenode.h b/src/quick/scenegraph/util/qsgimagenode.h
new file mode 100644
index 0000000000..7eab42c4e6
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgimagenode.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGENODE_H
+#define QSGIMAGENODE_H
+
+#include <QtQuick/qsgnode.h>
+#include <QtQuick/qsgtexture.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QSGImageNode : public QSGGeometryNode
+{
+public:
+ virtual ~QSGImageNode() { }
+
+ virtual void setRect(const QRectF &rect) = 0;
+ inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); }
+ virtual QRectF rect() const = 0;
+
+ virtual void setSourceRect(const QRectF &r) = 0;
+ inline void setSourceRect(qreal x, qreal y, qreal w, qreal h) { setSourceRect(QRectF(x, y, w, h)); }
+ virtual QRectF sourceRect() const = 0;
+
+ virtual void setTexture(QSGTexture *texture) = 0;
+ virtual QSGTexture *texture() const = 0;
+
+ virtual void setFiltering(QSGTexture::Filtering filtering) = 0;
+ virtual QSGTexture::Filtering filtering() const = 0;
+
+ virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0;
+ virtual QSGTexture::Filtering mipmapFiltering() const = 0;
+
+ enum TextureCoordinatesTransformFlag {
+ NoTransform = 0x00,
+ MirrorHorizontally = 0x01,
+ MirrorVertically = 0x02
+ };
+ Q_DECLARE_FLAGS(TextureCoordinatesTransformMode, TextureCoordinatesTransformFlag)
+
+ virtual void setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode) = 0;
+ virtual TextureCoordinatesTransformMode textureCoordinatesTransform() const = 0;
+
+ virtual void setOwnsTexture(bool owns) = 0;
+ virtual bool ownsTexture() const = 0;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGImageNode::TextureCoordinatesTransformMode)
+
+QT_END_NAMESPACE
+
+#endif // QSGIMAGENODE_H
diff --git a/src/quick/scenegraph/util/qsgninepatchnode.cpp b/src/quick/scenegraph/util/qsgninepatchnode.cpp
new file mode 100644
index 0000000000..9c167ca76f
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgninepatchnode.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgninepatchnode.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGNinePatchNode
+ \inmodule QtQuick
+ \since 5.8
+ \internal
+ */
+
+/*!
+ \fn void QSGNinePatchNode::setTexture(QSGTexture *texture)
+ \internal
+ */
+
+/*!
+ \fn void QSGNinePatchNode::setBounds(const QRectF &bounds)
+ \internal
+ */
+
+/*!
+ \fn void QSGNinePatchNode::setDevicePixelRatio(qreal ratio)
+ \internal
+ */
+
+/*!
+ \fn void QSGNinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom)
+ \internal
+ */
+
+
+/*!
+ \fn void QSGNinePatchNode::update()
+ \internal
+ */
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgninepatchnode.h b/src/quick/scenegraph/util/qsgninepatchnode.h
new file mode 100644
index 0000000000..8677a432ba
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgninepatchnode.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGNINEPATCHNODE_H
+#define QSGNINEPATCHNODE_H
+
+#include <QtQuick/qsgnode.h>
+#include <QtQuick/qsgtexture.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QSGNinePatchNode : public QSGGeometryNode
+{
+public:
+ virtual ~QSGNinePatchNode() { }
+
+ virtual void setTexture(QSGTexture *texture) = 0;
+ virtual void setBounds(const QRectF &bounds) = 0;
+ virtual void setDevicePixelRatio(qreal ratio) = 0;
+ virtual void setPadding(qreal left, qreal top, qreal right, qreal bottom) = 0;
+ virtual void update() = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGNINEPATCHNODE_H
diff --git a/src/quick/scenegraph/util/qsgrectanglenode.cpp b/src/quick/scenegraph/util/qsgrectanglenode.cpp
new file mode 100644
index 0000000000..38c1f16a63
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrectanglenode.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrectanglenode.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGRectangleNode
+
+ \brief The QSGRectangleNode class is a convenience class for drawing
+ solid filled rectangles using scenegraph.
+ \inmodule QtQuick
+ \since 5.8
+ */
+
+/*!
+ \fn void QSGRectangleNode::setRect(const QRectF &rect)
+
+ Sets the rectangle of this rect node to \a rect.
+ */
+
+/*!
+ \fn void QSGRectangleNode::setRect(qreal x, qreal y, qreal w, qreal h)
+ \overload
+
+ Sets the rectangle of this rect node to begin at (\a x, \a y) and have
+ width \a w and height \a h.
+ */
+
+/*!
+ \fn QRectF QSGRectangleNode::rect() const
+
+ Returns the rectangle that this rect node covers.
+ */
+
+/*!
+ \fn void QSGRectangleNode::setColor(const QColor &color)
+
+ Sets the color of this rectangle to \a color. The default color will be
+ white.
+ */
+
+/*!
+ \fn QColor QSGRectangleNode::color() const
+
+ Returns the color of this rectangle.
+ */
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/quick/scenegraph/util/qsgrectanglenode.h
index 9fcba64038..8e0da1d9c7 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/quick/scenegraph/util/qsgrectanglenode.h
@@ -3,7 +3,7 @@
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -37,24 +37,26 @@
**
****************************************************************************/
-#include "qv4debugging_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4function_p.h"
-#include "qv4instr_moth_p.h"
-#include "qv4runtime_p.h"
-#include "qv4script_p.h"
-#include "qv4identifier_p.h"
-#include "qv4string_p.h"
-#include "qv4objectiterator_p.h"
+#ifndef QSGRECTANGLENODE_H
+#define QSGRECTANGLENODE_H
-#include <iostream>
-#include <algorithm>
-
-#include <QtCore/QJsonArray>
-#include <QtCore/QJsonDocument>
-#include <QtCore/QJsonValue>
+#include <QtQuick/qsgnode.h>
QT_BEGIN_NAMESPACE
+class Q_QUICK_EXPORT QSGRectangleNode : public QSGGeometryNode
+{
+public:
+ virtual ~QSGRectangleNode() { }
+
+ virtual void setRect(const QRectF &rect) = 0;
+ inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); }
+ virtual QRectF rect() const = 0;
+
+ virtual void setColor(const QColor &color) = 0;
+ virtual QColor color() const = 0;
+};
+
QT_END_NAMESPACE
+
+#endif // QSGRECTANGLENODE_H
diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
index caa296451e..25af1997a8 100644
--- a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
+++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
@@ -310,13 +310,10 @@ void QSGShaderSourceBuilder::addDefinition(const QByteArray &definition)
const char *insertionPos = extensionPos ? extensionPos : (versionPos ? versionPos : input);
// Construct a new shader string, inserting the definition
- QByteArray newSource;
- newSource.reserve(m_source.size() + definition.size() + 9);
- newSource += QByteArray::fromRawData(input, insertionPos - input);
- newSource += QByteArrayLiteral("#define ") + definition + QByteArrayLiteral("\n");
- newSource += QByteArray::fromRawData(insertionPos, m_source.size() - (insertionPos - input));
-
- m_source = newSource;
+ QByteArray newSource = QByteArray::fromRawData(input, insertionPos - input)
+ + "#define " + definition + '\n'
+ + QByteArray::fromRawData(insertionPos, m_source.size() - (insertionPos - input));
+ m_source = std::move(newSource);
}
void QSGShaderSourceBuilder::removeVersion()
diff --git a/src/quick/scenegraph/util/qsgsimplematerial.h b/src/quick/scenegraph/util/qsgsimplematerial.h
index d07a68e850..01f98767fd 100644
--- a/src/quick/scenegraph/util/qsgsimplematerial.h
+++ b/src/quick/scenegraph/util/qsgsimplematerial.h
@@ -149,8 +149,8 @@ public:
{
}
- QSGMaterialShader *createShader() const { return m_func(); }
- QSGMaterialType *type() const { return &m_type; }
+ QSGMaterialShader *createShader() const override { return m_func(); }
+ QSGMaterialType *type() const override { return &m_type; }
State *state() { return &m_state; }
const State *state() const { return &m_state; }
diff --git a/src/quick/scenegraph/util/qsgsimplerectnode.cpp b/src/quick/scenegraph/util/qsgsimplerectnode.cpp
index 3f6b8b0eec..28b177be84 100644
--- a/src/quick/scenegraph/util/qsgsimplerectnode.cpp
+++ b/src/quick/scenegraph/util/qsgsimplerectnode.cpp
@@ -49,6 +49,12 @@ QT_BEGIN_NAMESPACE
solid filled rectangles using scenegraph.
\inmodule QtQuick
+ \warning This utility class is only functional when running with the OpenGL
+ or software backends of the Qt Quick scenegraph. For a proper cross-platform
+ alternative prefer using QSGRectangleNode via
+ QQuickWindow::createRectangleNode() or QSGEngine::createRectangleNode().
+
+ \deprecated
*/
diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
index 1208a6bc72..6ce37de7cb 100644
--- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
+++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
@@ -97,6 +97,13 @@ static void qsgsimpletexturenode_update(QSGGeometry *g,
\warning The simple texture node class must have a texture before being
added to the scene graph to be rendered.
+
+ \warning This utility class is only functional when running with the OpenGL
+ or software backends of the Qt Quick scenegraph. For a proper cross-platform
+ alternative prefer using QSGImageNode via
+ QQuickWindow::createImageNode() or QSGEngine::createImageNode().
+
+ \deprecated
*/
/*!
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index 19403deb73..4cf339aeb8 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -70,7 +70,9 @@
#include <QHash>
#endif
+#ifndef QT_NO_OPENGL
static QElapsedTimer qsg_renderer_timer;
+#endif
#ifndef QT_NO_DEBUG
static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
@@ -84,11 +86,13 @@ static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_OPENGL
inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
return x == (x & -x);
}
+#endif
QSGTexturePrivate::QSGTexturePrivate()
: wrapChanged(false)
diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h
index a0d7eb41e3..e09cbdbef1 100644
--- a/src/quick/scenegraph/util/qsgtexture_p.h
+++ b/src/quick/scenegraph/util/qsgtexture_p.h
@@ -87,19 +87,19 @@ public:
bool ownsTexture() const { return m_owns_texture; }
void setTextureId(int id);
- int textureId() const;
+ int textureId() const override;
void setTextureSize(const QSize &size) { m_texture_size = size; }
- QSize textureSize() const { return m_texture_size; }
+ QSize textureSize() const override { return m_texture_size; }
void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; }
- bool hasAlphaChannel() const { return m_has_alpha; }
+ bool hasAlphaChannel() const override { return m_has_alpha; }
- bool hasMipmaps() const { return mipmapFiltering() != QSGTexture::None; }
+ bool hasMipmaps() const override { return mipmapFiltering() != QSGTexture::None; }
void setImage(const QImage &image);
const QImage &image() { return m_image; }
- virtual void bind();
+ void bind() override;
static QSGPlainTexture *fromImage(const QImage &image) {
QSGPlainTexture *t = new QSGPlainTexture();
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index 3db8163376..119828bc81 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -46,11 +46,13 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_OPENGL
inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
return x == (x & -x);
}
+#endif
QSGMaterialType QSGOpaqueTextureMaterialShader::type;
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.h b/src/quick/scenegraph/util/qsgtexturematerial.h
index 02b59108b3..dc87131773 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.h
+++ b/src/quick/scenegraph/util/qsgtexturematerial.h
@@ -50,9 +50,9 @@ class Q_QUICK_EXPORT QSGOpaqueTextureMaterial : public QSGMaterial
public:
QSGOpaqueTextureMaterial();
- virtual QSGMaterialType *type() const;
- virtual QSGMaterialShader *createShader() const;
- virtual int compare(const QSGMaterial *other) const;
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
+ int compare(const QSGMaterial *other) const override;
void setTexture(QSGTexture *texture);
QSGTexture *texture() const { return m_texture; }
@@ -84,8 +84,8 @@ protected:
class Q_QUICK_EXPORT QSGTextureMaterial : public QSGOpaqueTextureMaterial
{
public:
- virtual QSGMaterialType *type() const;
- virtual QSGMaterialShader *createShader() const;
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgtexturematerial_p.h b/src/quick/scenegraph/util/qsgtexturematerial_p.h
index 75e5877a72..093d820801 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial_p.h
+++ b/src/quick/scenegraph/util/qsgtexturematerial_p.h
@@ -61,13 +61,13 @@ class Q_QUICK_PRIVATE_EXPORT QSGOpaqueTextureMaterialShader : public QSGMaterial
public:
QSGOpaqueTextureMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual char const *const *attributeNames() const;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
static QSGMaterialType type;
protected:
- virtual void initialize();
+ void initialize() override;
int m_matrix_id;
};
@@ -77,8 +77,8 @@ class QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader
public:
QSGTextureMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual void initialize();
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ void initialize() override;
static QSGMaterialType type;
diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
index dedbc86385..847ec289d8 100644
--- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -55,9 +55,10 @@ public:
private:
virtual void initialize();
-
+#ifndef QT_NO_OPENGL
int m_matrix_id;
int m_opacity_id;
+#endif
};
QSGMaterialType QSGVertexColorMaterialShader::type;
diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.h b/src/quick/scenegraph/util/qsgvertexcolormaterial.h
index 68f32d8af0..65cb642d92 100644
--- a/src/quick/scenegraph/util/qsgvertexcolormaterial.h
+++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.h
@@ -49,11 +49,11 @@ class Q_QUICK_EXPORT QSGVertexColorMaterial : public QSGMaterial
public:
QSGVertexColorMaterial();
- int compare(const QSGMaterial *other) const;
+ int compare(const QSGMaterial *other) const override;
protected:
- virtual QSGMaterialType *type() const;
- virtual QSGMaterialShader *createShader() const;
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 741a583803..9de474ac36 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -1198,14 +1198,14 @@ QAbstractAnimationJob* QQuickPropertyAction::transition(QQuickStateActions &acti
struct QQuickSetPropertyAnimationAction : public QAbstractAnimationAction
{
QQuickStateActions actions;
- virtual void doAction()
+ void doAction() override
{
for (int ii = 0; ii < actions.count(); ++ii) {
const QQuickStateAction &action = actions.at(ii);
- QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
}
}
- virtual void debugAction(QDebug d, int indentLevel) const {
+ void debugAction(QDebug d, int indentLevel) const override {
QByteArray ind(indentLevel, ' ');
for (int ii = 0; ii < actions.count(); ++ii) {
const QQuickStateAction &action = actions.at(ii);
@@ -2535,7 +2535,7 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v)
QQuickStateAction &action = actions[ii];
if (v == 1.) {
- QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
} else {
if (!fromSourced && !fromDefined) {
action.fromValue = action.property.read();
@@ -2551,7 +2551,7 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v)
}
}
if (interpolator)
- QQmlPropertyPrivate::write(action.property, interpolator(action.fromValue.constData(), action.toValue.constData(), v), QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::write(action.property, interpolator(action.fromValue.constData(), action.toValue.constData(), v), QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
}
if (deleted)
return;
@@ -2643,7 +2643,7 @@ QQuickStateActions QQuickPropertyAnimation::createTransitionActions(QQuickStateA
}
if (!successfullyCreatedDefaultProperty) {
- foreach (const QString &errorMessage, errorMessages)
+ for (const QString &errorMessage : qAsConst(errorMessages))
qmlInfo(this) << errorMessage;
}
}
diff --git a/src/quick/util/qquickanimation_p.h b/src/quick/util/qquickanimation_p.h
index 145f2656d2..e27871dcaa 100644
--- a/src/quick/util/qquickanimation_p.h
+++ b/src/quick/util/qquickanimation_p.h
@@ -114,8 +114,8 @@ public:
void setDisableUserControl();
void setEnableUserControl();
bool userControlDisabled() const;
- void classBegin();
- void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
virtual ThreadingModel threadingModel() const;
@@ -150,7 +150,7 @@ public:
private Q_SLOTS:
void componentFinalized();
private:
- virtual void setTarget(const QQmlProperty &);
+ void setTarget(const QQmlProperty &) override;
void notifyRunningChanged(bool running);
friend class QQuickBehavior;
friend class QQuickBehaviorPrivate;
@@ -179,7 +179,7 @@ protected:
QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0);
+ QObject *defaultTarget = 0) override;
};
class QQuickScriptActionPrivate;
@@ -202,10 +202,10 @@ public:
void setStateChangeScriptName(const QString &);
protected:
- virtual QAbstractAnimationJob* transition(QQuickStateActions &actions,
+ QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0);
+ QObject *defaultTarget = 0) override;
};
class QQuickPropertyActionPrivate;
@@ -247,10 +247,10 @@ Q_SIGNALS:
void propertyChanged();
protected:
- virtual QAbstractAnimationJob* transition(QQuickStateActions &actions,
+ QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0);
+ QObject *defaultTarget = 0) override;
};
class QQuickPropertyAnimationPrivate;
@@ -303,10 +303,10 @@ protected:
QObject *defaultTarget = 0);
QQuickPropertyAnimation(QQuickPropertyAnimationPrivate &dd, QObject *parent);
- virtual QAbstractAnimationJob* transition(QQuickStateActions &actions,
+ QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0);
+ QObject *defaultTarget = 0) override;
Q_SIGNALS:
void durationChanged(int);
void fromChanged(const QVariant &);
@@ -438,11 +438,11 @@ public:
virtual ~QQuickSequentialAnimation();
protected:
- virtual ThreadingModel threadingModel() const;
- virtual QAbstractAnimationJob* transition(QQuickStateActions &actions,
+ ThreadingModel threadingModel() const override;
+ QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0);
+ QObject *defaultTarget = 0) override;
};
class Q_QUICK_PRIVATE_EXPORT QQuickParallelAnimation : public QQuickAnimationGroup
@@ -455,11 +455,11 @@ public:
virtual ~QQuickParallelAnimation();
protected:
- virtual ThreadingModel threadingModel() const;
- virtual QAbstractAnimationJob* transition(QQuickStateActions &actions,
+ ThreadingModel threadingModel() const override;
+ QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0);
+ QObject *defaultTarget = 0) override;
};
diff --git a/src/quick/util/qquickanimation_p_p.h b/src/quick/util/qquickanimation_p_p.h
index ea7bf62171..a7abc5a004 100644
--- a/src/quick/util/qquickanimation_p_p.h
+++ b/src/quick/util/qquickanimation_p_p.h
@@ -88,8 +88,8 @@ class QAnimationActionProxy : public QAbstractAnimationAction
{
public:
QAnimationActionProxy(T *instance) : m_instance(instance) {}
- virtual void doAction() { (m_instance->*method)(); }
- virtual void debugAction(QDebug d, int indentLevel) const { (m_instance->*debugMethod)(d, indentLevel); }
+ void doAction() override { (m_instance->*method)(); }
+ void debugAction(QDebug d, int indentLevel) const override { (m_instance->*debugMethod)(d, indentLevel); }
private:
T *m_instance;
};
@@ -104,13 +104,13 @@ public:
QActionAnimation(QAbstractAnimationAction *action);
~QActionAnimation();
- virtual int duration() const;
+ int duration() const override;
void setAnimAction(QAbstractAnimationAction *action);
protected:
- virtual void updateCurrentTime(int);
- virtual void updateState(State newState, State oldState);
- void debugAnimation(QDebug d) const;
+ void updateCurrentTime(int) override;
+ void updateState(State newState, State oldState) override;
+ void debugAnimation(QDebug d) const override;
private:
QAbstractAnimationAction *animAction;
@@ -137,16 +137,16 @@ public:
void setFromSourcedValue(bool *value) { fromSourced = value; }
- int duration() const { return m_duration; }
+ int duration() const override { return m_duration; }
void setDuration(int msecs) { m_duration = msecs; }
QEasingCurve easingCurve() const { return easing; }
void setEasingCurve(const QEasingCurve &curve) { easing = curve; }
protected:
- void updateCurrentTime(int currentTime);
- void topLevelAnimationLoopChanged();
- void debugAnimation(QDebug d) const;
+ void updateCurrentTime(int currentTime) override;
+ void topLevelAnimationLoopChanged() override;
+ void debugAnimation(QDebug d) const override;
private:
QQuickBulkValueUpdater *animValue;
@@ -162,9 +162,9 @@ class QTickAnimationProxy : public QAbstractAnimationJob
Q_DISABLE_COPY(QTickAnimationProxy)
public:
QTickAnimationProxy(T *instance) : QAbstractAnimationJob(), m_instance(instance) {}
- virtual int duration() const { return -1; }
+ int duration() const override { return -1; }
protected:
- virtual void updateCurrentTime(int msec) { (m_instance->*method)(msec); }
+ void updateCurrentTime(int msec) override { (m_instance->*method)(msec); }
private:
T *m_instance;
@@ -192,7 +192,7 @@ public:
int loopCount;
void commence();
- virtual void animationFinished(QAbstractAnimationJob *);
+ void animationFinished(QAbstractAnimationJob *) override;
QQmlProperty defaultProperty;
@@ -309,9 +309,9 @@ public:
QQuickAnimationPropertyUpdater() : interpolatorType(0), interpolator(0), prevInterpolatorType(0), reverse(false), fromSourced(false), fromDefined(false), wasDeleted(0) {}
~QQuickAnimationPropertyUpdater();
- void setValue(qreal v);
+ void setValue(qreal v) override;
- void debugUpdater(QDebug d, int indentLevel) const;
+ void debugUpdater(QDebug d, int indentLevel) const override;
QQuickStateActions actions;
int interpolatorType; //for Number/ColorAnimation
diff --git a/src/quick/util/qquickanimationcontroller.cpp b/src/quick/util/qquickanimationcontroller.cpp
index 8b6968ad98..4bc2d6319e 100644
--- a/src/quick/util/qquickanimationcontroller.cpp
+++ b/src/quick/util/qquickanimationcontroller.cpp
@@ -50,8 +50,8 @@ class QQuickAnimationControllerPrivate : public QObjectPrivate, QAnimationJobCha
public:
QQuickAnimationControllerPrivate()
: progress(0.0), animation(0), animationInstance(0), finalized(false) {}
- virtual void animationFinished(QAbstractAnimationJob *job);
- virtual void animationCurrentTimeChanged(QAbstractAnimationJob *job, int currentTime);
+ void animationFinished(QAbstractAnimationJob *job) override;
+ void animationCurrentTimeChanged(QAbstractAnimationJob *job, int currentTime) override;
qreal progress;
diff --git a/src/quick/util/qquickanimationcontroller_p.h b/src/quick/util/qquickanimationcontroller_p.h
index e37bb90a0a..43555ac1c1 100644
--- a/src/quick/util/qquickanimationcontroller_p.h
+++ b/src/quick/util/qquickanimationcontroller_p.h
@@ -78,8 +78,8 @@ public:
QQuickAbstractAnimation *animation() const;
void setAnimation(QQuickAbstractAnimation *animation);
- void classBegin();
- void componentComplete() {}
+ void classBegin() override;
+ void componentComplete() override {}
Q_SIGNALS:
void progressChanged();
void animationChanged();
diff --git a/src/quick/util/qquickanimator_p.h b/src/quick/util/qquickanimator_p.h
index f1e2d4e1d9..807ed6da58 100644
--- a/src/quick/util/qquickanimator_p.h
+++ b/src/quick/util/qquickanimator_p.h
@@ -86,13 +86,13 @@ public:
void setFrom(qreal from);
protected:
- ThreadingModel threadingModel() const { return RenderThread; }
+ ThreadingModel threadingModel() const override { return RenderThread; }
virtual QQuickAnimatorJob *createJob() const = 0;
virtual QString propertyName() const = 0;
QAbstractAnimationJob *transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection,
- QObject *);
+ QObject *) override;
QQuickAnimator(QQuickAnimatorPrivate &dd, QObject *parent = 0);
QQuickAnimator(QObject *parent = 0);
@@ -112,8 +112,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickScaleAnimator : public QQuickAnimator
public:
QQuickScaleAnimator(QObject *parent = 0);
protected:
- QQuickAnimatorJob *createJob() const;
- QString propertyName() const { return QStringLiteral("scale"); }
+ QQuickAnimatorJob *createJob() const override;
+ QString propertyName() const override { return QStringLiteral("scale"); }
};
class Q_QUICK_PRIVATE_EXPORT QQuickXAnimator : public QQuickAnimator
@@ -122,8 +122,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickXAnimator : public QQuickAnimator
public:
QQuickXAnimator(QObject *parent = 0);
protected:
- QQuickAnimatorJob *createJob() const;
- QString propertyName() const{ return QStringLiteral("x"); }
+ QQuickAnimatorJob *createJob() const override;
+ QString propertyName() const override { return QStringLiteral("x"); }
};
class Q_QUICK_PRIVATE_EXPORT QQuickYAnimator : public QQuickAnimator
@@ -132,8 +132,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickYAnimator : public QQuickAnimator
public:
QQuickYAnimator(QObject *parent = 0);
protected:
- QQuickAnimatorJob *createJob() const;
- QString propertyName() const { return QStringLiteral("y"); }
+ QQuickAnimatorJob *createJob() const override;
+ QString propertyName() const override { return QStringLiteral("y"); }
};
class Q_QUICK_PRIVATE_EXPORT QQuickOpacityAnimator : public QQuickAnimator
@@ -142,8 +142,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickOpacityAnimator : public QQuickAnimator
public:
QQuickOpacityAnimator(QObject *parent = 0);
protected:
- QQuickAnimatorJob *createJob() const;
- QString propertyName() const { return QStringLiteral("opacity"); }
+ QQuickAnimatorJob *createJob() const override;
+ QString propertyName() const override { return QStringLiteral("opacity"); }
};
class QQuickRotationAnimatorPrivate;
@@ -166,8 +166,8 @@ Q_SIGNALS:
void directionChanged(RotationDirection dir);
protected:
- QQuickAnimatorJob *createJob() const;
- QString propertyName() const { return QStringLiteral("rotation"); }
+ QQuickAnimatorJob *createJob() const override;
+ QString propertyName() const override { return QStringLiteral("rotation"); }
};
#ifndef QT_NO_OPENGL
class QQuickUniformAnimatorPrivate;
@@ -187,8 +187,8 @@ Q_SIGNALS:
void uniformChanged(const QString &);
protected:
- QQuickAnimatorJob *createJob() const;
- QString propertyName() const;
+ QQuickAnimatorJob *createJob() const override;
+ QString propertyName() const override;
};
#endif
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index 3fc7d87840..ed3380b9ca 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Gunnar Sletta <gunnar@sletta.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -50,228 +51,116 @@
QT_BEGIN_NAMESPACE
-QQuickAnimatorController::QQuickAnimatorController(QQuickWindow *window)
- : m_window(window)
- , m_nodesAreInvalid(false)
-{
- m_guiEntity = new QQuickAnimatorControllerGuiThreadEntity();
- m_guiEntity->controller = this;
- connect(window, SIGNAL(frameSwapped()), m_guiEntity, SLOT(frameSwapped()));
-}
-
-void QQuickAnimatorControllerGuiThreadEntity::frameSwapped()
+QQuickAnimatorController::~QQuickAnimatorController()
{
- if (!controller.isNull())
- controller->stopProxyJobs();
}
-QQuickAnimatorController::~QQuickAnimatorController()
+QQuickAnimatorController::QQuickAnimatorController(QQuickWindow *window)
+ : m_window(window)
{
- // The proxy job might already have been deleted, in which case we
- // need to avoid calling functions on them. Then delete the job.
- foreach (QAbstractAnimationJob *job, m_deleting) {
- m_starting.take(job);
- m_stopping.take(job);
- m_animatorRoots.take(job);
- delete job;
- }
-
- foreach (QQuickAnimatorProxyJob *proxy, m_animatorRoots)
- proxy->controllerWasDeleted();
- for (auto it = m_animatorRoots.keyBegin(), end = m_animatorRoots.keyEnd(); it != end; ++it)
- delete *it;
-
- // Delete those who have been started, stopped and are now still
- // pending for restart.
- for (auto it = m_starting.keyBegin(), end = m_starting.keyEnd(); it != end; ++it) {
- QAbstractAnimationJob *job = *it;
- if (!m_animatorRoots.contains(job))
- delete job;
- }
-
- delete m_guiEntity;
}
-static void qquickanimator_invalidate_node(QAbstractAnimationJob *job)
+static void qquickanimator_invalidate_jobs(QAbstractAnimationJob *job)
{
if (job->isRenderThreadJob()) {
- static_cast<QQuickAnimatorJob *>(job)->nodeWasDestroyed();
+ static_cast<QQuickAnimatorJob *>(job)->invalidate();
} else if (job->isGroup()) {
QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
- qquickanimator_invalidate_node(a);
+ qquickanimator_invalidate_jobs(a);
}
}
void QQuickAnimatorController::windowNodesDestroyed()
{
m_nodesAreInvalid = true;
- for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
- it != m_animatorRoots.constEnd(); ++it) {
- qquickanimator_invalidate_node(it.key());
- }
-}
-void QQuickAnimatorController::itemDestroyed(QObject *o)
-{
- m_deletedSinceLastFrame << (QQuickItem *) o;
+ for (const QSharedPointer<QAbstractAnimationJob> &toStop : qAsConst(m_rootsPendingStop))
+ toStop->stop();
+ m_rootsPendingStop.clear();
+
+ // Clear animation roots and iterate over a temporary to avoid that job->stop()
+ // modifies the m_animationRoots and messes with our iteration
+ const auto roots = m_animationRoots;
+ m_animationRoots.clear();
+ for (const QSharedPointer<QAbstractAnimationJob> &job : roots) {
+ qquickanimator_invalidate_jobs(job.data());
+
+ // Stop it and add it to the list of pending start so it might get
+ // started later on.
+ job->stop();
+ m_rootsPendingStart.insert(job);
+ }
}
void QQuickAnimatorController::advance()
{
bool running = false;
- for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
- !running && it != m_animatorRoots.constEnd(); ++it) {
- if (it.key()->isRunning())
+ for (const QSharedPointer<QAbstractAnimationJob> &job : qAsConst(m_animationRoots)) {
+ if (job->isRunning()) {
running = true;
+ break;
+ }
}
- // It was tempting to only run over the active animations, but we need to push
- // the values for the transforms that finished in the last frame and those will
- // have been removed already...
- lock();
- for (QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *>::const_iterator it = m_transforms.constBegin();
- it != m_transforms.constEnd(); ++it) {
- QQuickTransformAnimatorJob::Helper *xform = *it;
- // Set to zero when the item was deleted in beforeNodeSync().
- if (!xform->item)
- continue;
- (*it)->apply();
- }
- unlock();
+ for (QQuickAnimatorJob *job : qAsConst(m_runningAnimators))
+ job->commit();
if (running)
m_window->update();
}
-static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c, bool attachListener)
+static void qquickanimator_sync_before_start(QAbstractAnimationJob *job)
{
if (job->isRenderThreadJob()) {
- QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
- // Note: since a QQuickAnimatorJob::m_target is a QPointer,
- // if m_target is destroyed between the time it was set
- // as the target of the animator job and before this step,
- // (e.g a Loader being set inactive just after starting the animator)
- // we are sure it will be NULL and won't be dangling around
- if (!j->target()) {
- return;
- } else if (c->m_deletedSinceLastFrame.contains(j->target())) {
- j->targetWasDeleted();
- } else {
- if (attachListener)
- j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange);
- j->initialize(c);
- }
+ static_cast<QQuickAnimatorJob *>(job)->preSync();
} else if (job->isGroup()) {
QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
- qquick_initialize_helper(a, c, attachListener);
+ qquickanimator_sync_before_start(a);
}
}
void QQuickAnimatorController::beforeNodeSync()
{
- foreach (QAbstractAnimationJob *job, m_deleting) {
- m_starting.take(job);
- m_stopping.take(job);
- m_animatorRoots.take(job);
- job->stop();
- delete job;
- }
- m_deleting.clear();
+ for (const QSharedPointer<QAbstractAnimationJob> &toStop : qAsConst(m_rootsPendingStop))
+ toStop->stop();
+ m_rootsPendingStop.clear();
- if (m_starting.size())
- m_window->update();
- foreach (QQuickAnimatorProxyJob *proxy, m_starting) {
- QAbstractAnimationJob *job = proxy->job();
- job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
- qquick_initialize_helper(job, this, true);
- m_animatorRoots[job] = proxy;
- job->start();
- proxy->startedByController();
- }
- m_starting.clear();
- foreach (QQuickAnimatorProxyJob *proxy, m_stopping) {
- QAbstractAnimationJob *job = proxy->job();
- job->stop();
- }
- m_stopping.clear();
-
- // First sync after a window was hidden or otherwise invalidated.
- // call initialize again to pick up new nodes..
- if (m_nodesAreInvalid) {
- for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
- it != m_animatorRoots.constEnd(); ++it) {
- qquick_initialize_helper(it.key(), this, false);
- }
- m_nodesAreInvalid = false;
- }
+ for (QQuickAnimatorJob *job : qAsConst(m_runningAnimators))
+ job->preSync();
- foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
- if (!job->target())
- continue;
- else if (m_deletedSinceLastFrame.contains(job->target()))
- job->targetWasDeleted();
- else if (job->isTransform()) {
- QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(job);
- xform->transformHelper()->sync();
- }
- }
- foreach (QQuickItem *wiped, m_deletedSinceLastFrame) {
- QQuickTransformAnimatorJob::Helper *helper = m_transforms.take(wiped);
- // Helper will now already have been reset in all animators referencing it.
- delete helper;
- }
+ // Start pending jobs
+ for (const QSharedPointer<QAbstractAnimationJob> &job : qAsConst(m_rootsPendingStart)) {
+ Q_ASSERT(!job->isRunning());
- m_deletedSinceLastFrame.clear();
-}
+ // We want to make sure that presync is called before
+ // updateAnimationTime is called the very first time, so before
+ // starting a tree of jobs, we go through it and call preSync on all
+ // its animators.
+ qquickanimator_sync_before_start(job.data());
-void QQuickAnimatorController::afterNodeSync()
-{
- foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
- if (job->target())
- job->afterNodeSync();
+ // The start the job..
+ job->start();
+ m_animationRoots.insert(job.data(), job);
}
-}
+ m_rootsPendingStart.clear();
-void QQuickAnimatorController::proxyWasDestroyed(QQuickAnimatorProxyJob *proxy)
-{
- lock();
- m_proxiesToStop.remove(proxy);
- unlock();
+ // Issue an update directly on the window to force another render pass.
+ if (m_animationRoots.size())
+ m_window->update();
}
-void QQuickAnimatorController::stopProxyJobs()
+void QQuickAnimatorController::afterNodeSync()
{
- // Need to make a copy under lock and then stop while unlocked.
- // Stopping triggers writeBack which in turn may lock, so it needs
- // to be outside the lock. It is also safe because deletion of
- // proxies happens on the GUI thread, where this code is also executing.
- lock();
- QSet<QQuickAnimatorProxyJob *> jobs = m_proxiesToStop;
- m_proxiesToStop.clear();
- unlock();
- foreach (QQuickAnimatorProxyJob *p, jobs)
- p->stop();
+ for (QQuickAnimatorJob *job : qAsConst(m_runningAnimators))
+ job->postSync();
}
void QQuickAnimatorController::animationFinished(QAbstractAnimationJob *job)
{
- /* We are currently on the render thread and m_deleting is primarily
- * being written on the GUI Thread and read during sync. However, we don't
- * need to lock here as this is a direct result of animationDriver->advance()
- * which is already locked. For non-threaded render loops no locking is
- * needed in any case.
- */
- if (!m_deleting.contains(job)) {
- QQuickAnimatorProxyJob *proxy = m_animatorRoots[job];
- if (proxy) {
- m_window->update();
- m_proxiesToStop << proxy;
- }
- // else already gone...
- }
+ m_animationRoots.remove(job);
}
void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job,
@@ -281,43 +170,52 @@ void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job,
Q_ASSERT(job->isRenderThreadJob());
QQuickAnimatorJob *animator = static_cast<QQuickAnimatorJob *>(job);
if (newState == QAbstractAnimationJob::Running) {
- m_activeLeafAnimations << animator;
- animator->setHasBeenRunning(true);
+ m_runningAnimators.insert(animator);
} else if (oldState == QAbstractAnimationJob::Running) {
- m_activeLeafAnimations.remove(animator);
+ animator->commit();
+ m_runningAnimators.remove(animator);
}
}
-
void QQuickAnimatorController::requestSync()
{
// Force a "sync" pass as the newly started animation needs to sync properties from GUI.
m_window->maybeUpdate();
}
-// These functions are called on the GUI thread.
-void QQuickAnimatorController::startJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job)
+// All this is being executed on the GUI thread while the animator controller
+// is locked.
+void QQuickAnimatorController::start_helper(QAbstractAnimationJob *job)
{
- proxy->markJobManagedByController();
- m_starting[job] = proxy;
- m_stopping.remove(job);
- requestSync();
+ if (job->isRenderThreadJob()) {
+ QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
+ j->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
+ j->initialize(this);
+ } else if (job->isGroup()) {
+ QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
+ for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
+ start_helper(a);
+ }
}
-void QQuickAnimatorController::stopJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job)
+// Called by the proxy when it is time to kick off an animation job
+void QQuickAnimatorController::start(const QSharedPointer<QAbstractAnimationJob> &job)
{
- m_stopping[job] = proxy;
- m_starting.remove(job);
+ m_rootsPendingStart.insert(job);
+ m_rootsPendingStop.remove(job);
+ job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
+ start_helper(job.data());
requestSync();
}
-void QQuickAnimatorController::deleteJob(QAbstractAnimationJob *job)
+
+// Called by the proxy when it is time to stop an animation job.
+void QQuickAnimatorController::cancel(const QSharedPointer<QAbstractAnimationJob> &job)
{
- lock();
- m_deleting << job;
- requestSync();
- unlock();
+ m_rootsPendingStart.remove(job);
+ m_rootsPendingStop.insert(job);
}
+
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h
index 0a9902cc30..1ec44ccc9d 100644
--- a/src/quick/util/qquickanimatorcontroller_p.h
+++ b/src/quick/util/qquickanimatorcontroller_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Gunnar Sletta <gunnar@sletta.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -60,8 +61,6 @@
QT_BEGIN_NAMESPACE
-class QQuickAnimatorControllerGuiThreadEntity;
-
class QQuickAnimatorController : public QObject, public QAnimationJobChangeListener
{
Q_OBJECT
@@ -74,56 +73,41 @@ public:
void beforeNodeSync();
void afterNodeSync();
- void animationFinished(QAbstractAnimationJob *job);
- void animationStateChanged(QAbstractAnimationJob *job, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void animationFinished(QAbstractAnimationJob *job) override;
+ void animationStateChanged(QAbstractAnimationJob *job, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) override;
void requestSync();
// These are called from the GUI thread (the proxy)
- void startJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job);
- void stopJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job);
- void deleteJob(QAbstractAnimationJob *job);
+ void start(const QSharedPointer<QAbstractAnimationJob> &job);
+ void cancel(const QSharedPointer<QAbstractAnimationJob> &job);
+ bool isPendingStart(const QSharedPointer<QAbstractAnimationJob> &job) const { return m_rootsPendingStart.contains(job); }
void lock() { m_mutex.lock(); }
void unlock() { m_mutex.unlock(); }
-
void proxyWasDestroyed(QQuickAnimatorProxyJob *proxy);
void stopProxyJobs();
void windowNodesDestroyed();
-public Q_SLOTS:
- void itemDestroyed(QObject *);
+ QQuickWindow *window() const { return m_window; }
+
+private:
+ void start_helper(QAbstractAnimationJob *job);
+ void cancel_helper(QAbstractAnimationJob *job);
public:
- // These are manipulated from the GUI thread and should only
- // be updated during the sync() phase.
- QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *> m_starting;
- QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *> m_stopping;
- QSet<QAbstractAnimationJob *> m_deleting;
-
- QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *> m_animatorRoots;
- QSet<QQuickAnimatorJob *> m_activeLeafAnimations;
- QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *> m_transforms;
- QSet<QQuickItem *> m_deletedSinceLastFrame;
+ QSet<QQuickAnimatorJob * > m_runningAnimators;
+ QHash<QAbstractAnimationJob *, QSharedPointer<QAbstractAnimationJob> > m_animationRoots;
+ QSet<QSharedPointer<QAbstractAnimationJob> > m_rootsPendingStop;
+ QSet<QSharedPointer<QAbstractAnimationJob> > m_rootsPendingStart;
+
QQuickWindow *m_window;
- QQuickAnimatorControllerGuiThreadEntity *m_guiEntity;
- QSet<QQuickAnimatorProxyJob *> m_proxiesToStop;
QMutex m_mutex;
bool m_nodesAreInvalid;
};
-class QQuickAnimatorControllerGuiThreadEntity : public QObject
-{
- Q_OBJECT
-public:
- QPointer<QQuickAnimatorController> controller;
-
-public Q_SLOTS:
- void frameSwapped();
-};
-
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index a0c787dae5..11c7c28d5f 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Gunnar Sletta <gunnar@sletta.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -54,12 +55,42 @@
QT_BEGIN_NAMESPACE
+struct QQuickTransformAnimatorHelperStore
+{
+ QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *> store;
+ QMutex mutex;
+
+ QQuickTransformAnimatorJob::Helper *acquire(QQuickItem *item) {
+ mutex.lock();
+ QQuickTransformAnimatorJob::Helper *helper = store.value(item);
+ if (!helper) {
+ helper = new QQuickTransformAnimatorJob::Helper();
+ helper->item = item;
+ store[item] = helper;
+ } else {
+ ++helper->ref;
+ }
+ mutex.unlock();
+ return helper;
+ }
+
+ void release(QQuickTransformAnimatorJob::Helper *helper) {
+ mutex.lock();
+ if (--helper->ref == 0) {
+ store.remove(helper->item);
+ delete helper;
+ }
+ mutex.unlock();
+ }
+};
+Q_GLOBAL_STATIC(QQuickTransformAnimatorHelperStore, qquick_transform_animatorjob_helper_store);
+
QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObject *item)
- : m_controller(0)
- , m_job(job)
+ : m_controller(nullptr)
, m_internalState(State_Stopped)
- , m_jobManagedByController(false)
{
+ m_job.reset(job);
+
m_isRenderThreadProxy = true;
m_animation = qobject_cast<QQuickAbstractAnimation *>(item);
@@ -87,57 +118,58 @@ QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObje
QQuickItem *item = qobject_cast<QQuickItem *>(ctx);
if (item->window())
setWindow(item->window());
-
- qmlobject_connect(item, QQuickItem, SIGNAL(windowChanged(QQuickWindow*)), this, QQuickAnimatorProxyJob, SLOT(windowChanged(QQuickWindow*)));
+ connect(item, &QQuickItem::windowChanged, this, &QQuickAnimatorProxyJob::windowChanged);
}
}
QQuickAnimatorProxyJob::~QQuickAnimatorProxyJob()
{
- deleteJob();
- if (m_controller)
- m_controller->proxyWasDestroyed(this);
-}
-
-void QQuickAnimatorProxyJob::deleteJob()
-{
- if (m_job) {
- // If we have a controller, we might have posted the job to be started
- // so delete it through the controller to clean up properly.
- if (m_controller)
- m_controller->deleteJob(m_job);
-
- // We explicitly delete the job if the animator controller has never touched
- // it. If it has, it will have ownership as well.
- else if (!m_jobManagedByController)
- delete m_job;
- m_job = 0;
- }
+ if (m_job && m_controller)
+ m_controller->cancel(m_job);
+ m_job.reset();
}
QObject *QQuickAnimatorProxyJob::findAnimationContext(QQuickAbstractAnimation *a)
{
QObject *p = a->parent();
- while (p != 0 && qobject_cast<QQuickWindow *>(p) == 0 && qobject_cast<QQuickItem *>(p) == 0)
+ while (p != nullptr && qobject_cast<QQuickWindow *>(p) == nullptr && qobject_cast<QQuickItem *>(p) == nullptr)
p = p->parent();
return p;
}
void QQuickAnimatorProxyJob::updateCurrentTime(int)
{
+ // We do a simple check here to see if the animator has run and stopped on
+ // the render thread. isPendingStart() will perform a check against jobs
+ // that have been scheduled for start, but that will not yet have entered
+ // the actual running state.
+ // Secondly, we make an unprotected read of the job's state to figure out
+ // if it is running, but this is ok, since we're only reading the state
+ // and if the render thread should happen to be writing it concurrently,
+ // we might get the wrong value for this update, but then we'll simply
+ // pick it up on the next iterationm when the job is stopped and render
+ // thread is no longer using it.
+ if (m_internalState == State_Running
+ && !m_controller->isPendingStart(m_job)
+ && !m_job->isRunning()) {
+ stop();
+ }
}
void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
{
if (m_state == Running) {
m_internalState = State_Starting;
- if (m_controller)
- m_controller->startJob(this, m_job);
+ if (m_controller) {
+ m_internalState = State_Running;
+ m_controller->start(m_job);
+ }
+
} else if (newState == Stopped) {
syncBackCurrentValues();
m_internalState = State_Stopped;
if (m_controller) {
- m_controller->stopJob(this, m_job);
+ m_controller->cancel(m_job);
}
}
}
@@ -154,69 +186,55 @@ void QQuickAnimatorProxyJob::windowChanged(QQuickWindow *window)
setWindow(window);
}
-void QQuickAnimatorProxyJob::controllerWasDeleted()
-{
- m_controller = 0;
- m_job = 0;
-}
-
void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window)
{
if (!window) {
- stop();
- deleteJob();
-
- // Upon leaving a window, we reset the controller. This means that
- // animators will only enter the Starting phase and won't be making
- // calls to QQuickAnimatorController::startjob().
- if (m_controller)
- m_controller->proxyWasDestroyed(this);
- m_controller = 0;
+ if (m_job && m_controller)
+ m_controller->cancel(m_job);
+ m_controller = nullptr;
} else if (!m_controller && m_job) {
m_controller = QQuickWindowPrivate::get(window)->animationController;
if (window->isSceneGraphInitialized())
readyToAnimate();
else
- connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(sceneGraphInitialized()));
+ connect(window, &QQuickWindow::sceneGraphInitialized, this, &QQuickAnimatorProxyJob::sceneGraphInitialized);
}
}
void QQuickAnimatorProxyJob::sceneGraphInitialized()
{
+ disconnect(m_controller->window(), &QQuickWindow::sceneGraphInitialized, this, &QQuickAnimatorProxyJob::sceneGraphInitialized);
readyToAnimate();
- disconnect(this, SLOT(sceneGraphInitialized()));
}
void QQuickAnimatorProxyJob::readyToAnimate()
{
- if (m_internalState == State_Starting)
- m_controller->startJob(this, m_job);
-}
-
-void QQuickAnimatorProxyJob::startedByController()
-{
- m_internalState = State_Running;
+ Q_ASSERT(m_controller);
+ if (m_internalState == State_Starting) {
+ m_internalState = State_Running;
+ m_controller->start(m_job);
+ }
}
static void qquick_syncback_helper(QAbstractAnimationJob *job)
{
if (job->isRenderThreadJob()) {
- QQuickAnimatorJob *a = static_cast<QQuickAnimatorJob *>(job);
- // Sync back only those jobs that actually have been running
- if (a->controller() && a->hasBeenRunning())
- a->writeBack();
+ Q_ASSERT(!job->isRunning());
+ static_cast<QQuickAnimatorJob *>(job)->writeBack();
+
} else if (job->isGroup()) {
QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
qquick_syncback_helper(a);
}
+
}
void QQuickAnimatorProxyJob::syncBackCurrentValues()
{
if (m_job)
- qquick_syncback_helper(m_job);
+ qquick_syncback_helper(m_job.data());
}
QQuickAnimatorJob::QQuickAnimatorJob()
@@ -228,7 +246,6 @@ QQuickAnimatorJob::QQuickAnimatorJob()
, m_duration(0)
, m_isTransform(false)
, m_isUniform(false)
- , m_hasBeenRunning(false)
{
m_isRenderThreadJob = true;
}
@@ -244,13 +261,10 @@ qreal QQuickAnimatorJob::progress(int time) const
{
return m_easing.valueForProgress((m_duration == 0) ? qreal(1) : qreal(time) / qreal(m_duration));
}
+
qreal QQuickAnimatorJob::value() const
{
- qreal v;
- m_controller->lock();
- v = m_value;
- m_controller->unlock();
- return v;
+ return m_value;
}
void QQuickAnimatorJob::setTarget(QQuickItem *target)
@@ -263,62 +277,81 @@ void QQuickAnimatorJob::initialize(QQuickAnimatorController *controller)
m_controller = controller;
}
-void QQuickAnimatorJob::targetWasDeleted()
-{
- m_target = 0;
- m_controller = 0;
-}
-
QQuickTransformAnimatorJob::QQuickTransformAnimatorJob()
- : m_helper(0)
+ : m_helper(nullptr)
{
m_isTransform = true;
}
QQuickTransformAnimatorJob::~QQuickTransformAnimatorJob()
{
- if (m_helper && --m_helper->ref == 0) {
- // The only condition for not having a controller is when target was
- // destroyed, in which case we have neither m_helper nor m_contorller.
- Q_ASSERT(m_controller);
- Q_ASSERT(m_helper->item);
- m_controller->m_transforms.remove(m_helper->item);
- delete m_helper;
- }
+ if (m_helper)
+ qquick_transform_animatorjob_helper_store()->release(m_helper);
}
-void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller)
+void QQuickTransformAnimatorJob::setTarget(QQuickItem *item)
{
- QQuickAnimatorJob::initialize(controller);
+ // In the extremely unlikely event that the target of an animator has been
+ // changed into a new item that sits in the exact same pointer address, we
+ // want to force syncing it again.
+ if (m_helper && m_target)
+ m_helper->wasSynced = false;
+ QQuickAnimatorJob::setTarget(item);
+}
- if (m_controller) {
- bool newHelper = m_helper == 0;
- m_helper = m_controller->m_transforms.value(m_target);
- if (!m_helper) {
- m_helper = new Helper();
- m_helper->item = m_target;
- m_controller->m_transforms.insert(m_target, m_helper);
- QObject::connect(m_target, SIGNAL(destroyed(QObject*)), m_controller, SLOT(itemDestroyed(QObject*)), Qt::DirectConnection);
- } else {
- if (newHelper) // only add reference the first time around..
- ++m_helper->ref;
- // Make sure leftovers from previous runs are being used...
- m_helper->wasSynced = false;
- }
- m_helper->sync();
+void QQuickTransformAnimatorJob::preSync()
+{
+ // If the target has changed or become null, release and reset the helper
+ if (m_helper && (m_helper->item != m_target || !m_target)) {
+ qquick_transform_animatorjob_helper_store()->release(m_helper);
+ m_helper = nullptr;
+ }
+
+ if (!m_target)
+ return;
+
+ if (!m_helper) {
+ m_helper = qquick_transform_animatorjob_helper_store()->acquire(m_target);
+
+ // This is a bit superfluous, but it ends up being simpler than the
+ // alternative. When an item happens to land on the same address as a
+ // previous item, that helper might not have been fully cleaned up by
+ // the time it gets taken back into use. As an alternative to storing
+ // connections to each and every item's QObject::destroyed() and
+ // having to clean those up afterwards, we simply sync all helpers on
+ // the first run. The sync is only done once for the run of an
+ // animation and it is a fairly light function (compared to storing
+ // potentially thousands of connections and managing their lifetime.
+ m_helper->wasSynced = false;
}
+
+ m_helper->sync();
}
-void QQuickTransformAnimatorJob::nodeWasDestroyed()
+void QQuickTransformAnimatorJob::postSync()
{
- if (m_helper)
- m_helper->node = 0;
+ Q_ASSERT((m_helper != nullptr) == (m_target != nullptr)); // If there is a target, there should also be a helper, ref: preSync
+ Q_ASSERT(!m_helper || m_helper->item == m_target); // If there is a helper, it should point to our target
+
+ if (!m_target || !m_helper) {
+ invalidate();
+ return;
+ }
+
+ QQuickItemPrivate *d = QQuickItemPrivate::get(m_target);
+ if (d->extra.isAllocated()
+ && d->extra->layer
+ && d->extra->layer->enabled()) {
+ d = QQuickItemPrivate::get(d->extra->layer->m_effectSource);
+ }
+
+ m_helper->node = d->itemNode();
}
-void QQuickTransformAnimatorJob::targetWasDeleted()
+void QQuickTransformAnimatorJob::invalidate()
{
- m_helper = 0;
- QQuickAnimatorJob::targetWasDeleted();
+ if (m_helper)
+ m_helper->node = nullptr;
}
void QQuickTransformAnimatorJob::Helper::sync()
@@ -364,7 +397,7 @@ void QQuickTransformAnimatorJob::Helper::sync()
}
}
-void QQuickTransformAnimatorJob::Helper::apply()
+void QQuickTransformAnimatorJob::Helper::commit()
{
if (!wasChanged || !node)
return;
@@ -380,7 +413,11 @@ void QQuickTransformAnimatorJob::Helper::apply()
wasChanged = false;
}
-
+void QQuickTransformAnimatorJob::commit()
+{
+ if (m_helper)
+ m_helper->commit();
+}
void QQuickXAnimatorJob::writeBack()
{
@@ -390,7 +427,8 @@ void QQuickXAnimatorJob::writeBack()
void QQuickXAnimatorJob::updateCurrentTime(int time)
{
- if (!m_controller)
+ Q_ASSERT(!m_controller || !m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+ if (!m_helper)
return;
m_value = m_from + (m_to - m_from) * progress(time);
@@ -406,7 +444,9 @@ void QQuickYAnimatorJob::writeBack()
void QQuickYAnimatorJob::updateCurrentTime(int time)
{
- if (!m_controller)
+ Q_ASSERT(!m_controller || !m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+
+ if (!m_helper)
return;
m_value = m_from + (m_to - m_from) * progress(time);
@@ -414,22 +454,93 @@ void QQuickYAnimatorJob::updateCurrentTime(int time)
m_helper->wasChanged = true;
}
+void QQuickScaleAnimatorJob::writeBack()
+{
+ if (m_target)
+ m_target->setScale(value());
+}
+
+void QQuickScaleAnimatorJob::updateCurrentTime(int time)
+{
+ Q_ASSERT(!m_controller || !m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+
+ if (!m_helper)
+ return;
+
+ m_value = m_from + (m_to - m_from) * progress(time);
+ m_helper->scale = m_value;
+ m_helper->wasChanged = true;
+}
+
+
+QQuickRotationAnimatorJob::QQuickRotationAnimatorJob()
+ : m_direction(QQuickRotationAnimator::Numerical)
+{
+}
+
+extern QVariant _q_interpolateShortestRotation(qreal &f, qreal &t, qreal progress);
+extern QVariant _q_interpolateClockwiseRotation(qreal &f, qreal &t, qreal progress);
+extern QVariant _q_interpolateCounterclockwiseRotation(qreal &f, qreal &t, qreal progress);
+
+void QQuickRotationAnimatorJob::updateCurrentTime(int time)
+{
+ Q_ASSERT(!m_controller || !m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+
+ if (!m_helper)
+ return;
+
+ float t = progress(time);
+
+ switch (m_direction) {
+ case QQuickRotationAnimator::Clockwise:
+ m_value = _q_interpolateClockwiseRotation(m_from, m_to, t).toFloat();
+ // The logic in _q_interpolateClockwise comes out a bit wrong
+ // for the case of X->0 where 0<X<360. It ends on 360 which it
+ // shouldn't.
+ if (t == 1)
+ m_value = m_to;
+ break;
+ case QQuickRotationAnimator::Counterclockwise:
+ m_value = _q_interpolateCounterclockwiseRotation(m_from, m_to, t).toFloat();
+ break;
+ case QQuickRotationAnimator::Shortest:
+ m_value = _q_interpolateShortestRotation(m_from, m_to, t).toFloat();
+ break;
+ case QQuickRotationAnimator::Numerical:
+ m_value = m_from + (m_to - m_from) * t;
+ break;
+ }
+ m_helper->rotation = m_value;
+ m_helper->wasChanged = true;
+}
+
+void QQuickRotationAnimatorJob::writeBack()
+{
+ if (m_target)
+ m_target->setRotation(value());
+}
+
+
QQuickOpacityAnimatorJob::QQuickOpacityAnimatorJob()
- : m_opacityNode(0)
+ : m_opacityNode(nullptr)
{
}
-void QQuickOpacityAnimatorJob::initialize(QQuickAnimatorController *controller)
+void QQuickOpacityAnimatorJob::postSync()
{
- QQuickAnimatorJob::initialize(controller);
+ if (!m_target) {
+ invalidate();
+ return;
+ }
+
QQuickItemPrivate *d = QQuickItemPrivate::get(m_target);
if (d->extra.isAllocated()
&& d->extra->layer
&& d->extra->layer->enabled()) {
d = QQuickItemPrivate::get(d->extra->layer->m_effectSource);
}
-
m_opacityNode = d->opacityNode();
+
if (!m_opacityNode) {
m_opacityNode = new QSGOpacityNode();
@@ -460,11 +571,12 @@ void QQuickOpacityAnimatorJob::initialize(QQuickAnimatorController *controller)
d->extra.value().opacityNode = m_opacityNode;
}
+ Q_ASSERT(m_opacityNode);
}
-void QQuickOpacityAnimatorJob::nodeWasDestroyed()
+void QQuickOpacityAnimatorJob::invalidate()
{
- m_opacityNode = 0;
+ m_opacityNode = nullptr;
}
void QQuickOpacityAnimatorJob::writeBack()
@@ -475,77 +587,19 @@ void QQuickOpacityAnimatorJob::writeBack()
void QQuickOpacityAnimatorJob::updateCurrentTime(int time)
{
- if (!m_controller || !m_opacityNode)
- return;
+ Q_ASSERT(!m_controller || !m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
- m_value = m_from + (m_to - m_from) * progress(time);
- m_opacityNode->setOpacity(m_value);
-}
-
-void QQuickScaleAnimatorJob::writeBack()
-{
- if (m_target)
- m_target->setScale(value());
-}
-
-void QQuickScaleAnimatorJob::updateCurrentTime(int time)
-{
- if (!m_controller)
+ if (!m_opacityNode)
return;
m_value = m_from + (m_to - m_from) * progress(time);
- m_helper->scale = m_value;
- m_helper->wasChanged = true;
-}
-
-QQuickRotationAnimatorJob::QQuickRotationAnimatorJob()
- : m_direction(QQuickRotationAnimator::Numerical)
-{
-}
-
-extern QVariant _q_interpolateShortestRotation(qreal &f, qreal &t, qreal progress);
-extern QVariant _q_interpolateClockwiseRotation(qreal &f, qreal &t, qreal progress);
-extern QVariant _q_interpolateCounterclockwiseRotation(qreal &f, qreal &t, qreal progress);
-
-void QQuickRotationAnimatorJob::updateCurrentTime(int time)
-{
- if (!m_controller)
- return;
-
- float t = progress(time);
-
- switch (m_direction) {
- case QQuickRotationAnimator::Clockwise:
- m_value = _q_interpolateClockwiseRotation(m_from, m_to, t).toFloat();
- // The logic in _q_interpolateClockwise comes out a bit wrong
- // for the case of X->0 where 0<X<360. It ends on 360 which it
- // shouldn't.
- if (t == 1)
- m_value = m_to;
- break;
- case QQuickRotationAnimator::Counterclockwise:
- m_value = _q_interpolateCounterclockwiseRotation(m_from, m_to, t).toFloat();
- break;
- case QQuickRotationAnimator::Shortest:
- m_value = _q_interpolateShortestRotation(m_from, m_to, t).toFloat();
- break;
- case QQuickRotationAnimator::Numerical:
- m_value = m_from + (m_to - m_from) * t;
- break;
- }
- m_helper->rotation = m_value;
- m_helper->wasChanged = true;
+ m_opacityNode->setOpacity(m_value);
}
-void QQuickRotationAnimatorJob::writeBack()
-{
- if (m_target)
- m_target->setRotation(value());
-}
#ifndef QT_NO_OPENGL
QQuickUniformAnimatorJob::QQuickUniformAnimatorJob()
- : m_node(0)
+ : m_node(nullptr)
, m_uniformIndex(-1)
, m_uniformType(-1)
{
@@ -554,19 +608,24 @@ QQuickUniformAnimatorJob::QQuickUniformAnimatorJob()
void QQuickUniformAnimatorJob::setTarget(QQuickItem *target)
{
- if (qobject_cast<QQuickOpenGLShaderEffect *>(target) != 0)
+ if (qobject_cast<QQuickOpenGLShaderEffect *>(target) != nullptr)
m_target = target;
}
-void QQuickUniformAnimatorJob::nodeWasDestroyed()
+void QQuickUniformAnimatorJob::invalidate()
{
- m_node = 0;
+ m_node = nullptr;
m_uniformIndex = -1;
m_uniformType = -1;
}
-void QQuickUniformAnimatorJob::afterNodeSync()
+void QQuickUniformAnimatorJob::postSync()
{
+ if (!m_target) {
+ invalidate();
+ return;
+ }
+
m_node = static_cast<QQuickOpenGLShaderEffectNode *>(QQuickItemPrivate::get(m_target)->paintNode);
if (m_node && m_uniformIndex == -1 && m_uniformType == -1) {
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 64e849d322..d7aaa988a9 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Gunnar Sletta <gunnar@sletta.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -80,25 +81,20 @@ public:
QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObject *item);
~QQuickAnimatorProxyJob();
- int duration() const Q_DECL_OVERRIDE { return m_duration; }
+ int duration() const override { return m_duration; }
- QAbstractAnimationJob *job() const { return m_job; }
-
- void startedByController();
- void controllerWasDeleted();
- void markJobManagedByController() { m_jobManagedByController = true; }
+ const QSharedPointer<QAbstractAnimationJob> &job() const { return m_job; }
protected:
- void updateCurrentTime(int) Q_DECL_OVERRIDE;
- void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) Q_DECL_OVERRIDE;
- void debugAnimation(QDebug d) const Q_DECL_OVERRIDE;
+ void updateCurrentTime(int) override;
+ void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) override;
+ void debugAnimation(QDebug d) const override;
public Q_SLOTS:
void windowChanged(QQuickWindow *window);
void sceneGraphInitialized();
private:
- void deleteJob();
void syncBackCurrentValues();
void readyToAnimate();
void setWindow(QQuickWindow *window);
@@ -106,7 +102,7 @@ private:
QPointer<QQuickAnimatorController> m_controller;
QQuickAbstractAnimation *m_animation;
- QAbstractAnimationJob *m_job;
+ QSharedPointer<QAbstractAnimationJob> m_job;
int m_duration;
enum InternalState {
@@ -117,7 +113,6 @@ private:
};
InternalState m_internalState;
- bool m_jobManagedByController;
};
class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorJob : public QAbstractAnimationJob
@@ -126,37 +121,53 @@ public:
virtual void setTarget(QQuickItem *target);
QQuickItem *target() const { return m_target; }
- void setFrom(qreal scale) { m_from = scale; }
+ void setFrom(qreal from) { m_from = from; }
qreal from() const { return m_from; }
void setTo(qreal to) { m_to = to; }
qreal to() const { return m_to; }
void setDuration(int duration) { m_duration = duration; }
- int duration() const Q_DECL_OVERRIDE { return m_duration; }
+ int duration() const override { return m_duration; }
QEasingCurve easingCurve() const { return m_easing; }
void setEasingCurve(const QEasingCurve &curve) { m_easing = curve; }
- virtual void targetWasDeleted();
+ // Initialize is called on the GUI thread just before it is started
+ // and taken over on the render thread.
virtual void initialize(QQuickAnimatorController *controller);
+
+ // Called on the render thread during SG shutdown.
+ virtual void invalidate() = 0;
+
+ // Called on the GUI thread after a complete render thread animation job
+ // has been completed to write back a given animator's result to the
+ // source item.
virtual void writeBack() = 0;
- virtual void nodeWasDestroyed() = 0;
- virtual void afterNodeSync() { }
+
+ // Called before the SG sync on the render thread. The GUI thread is
+ // locked during this call.
+ virtual void preSync() { }
+
+ // Called after the SG sync on the render thread. The GUI thread is
+ // locked during this call.
+ virtual void postSync() { }
+
+ // Called after animations have ticked on the render thread. No locks are
+ // held at this time, so synchronization needs to be taken into account
+ // if applicable.
+ virtual void commit() { }
bool isTransform() const { return m_isTransform; }
bool isUniform() const { return m_isUniform; }
- bool hasBeenRunning() const { return m_hasBeenRunning; }
- void setHasBeenRunning(bool has) { m_hasBeenRunning = has; }
-
qreal value() const;
QQuickAnimatorController *controller() const { return m_controller; }
protected:
QQuickAnimatorJob();
- void debugAnimation(QDebug d) const Q_DECL_OVERRIDE;
+ void debugAnimation(QDebug d) const override;
qreal progress(int time) const;
@@ -173,7 +184,6 @@ protected:
uint m_isTransform : 1;
uint m_isUniform : 1;
- uint m_hasBeenRunning : 1;
};
class QQuickTransformAnimatorJob : public QQuickAnimatorJob
@@ -197,7 +207,7 @@ public:
}
void sync();
- void apply();
+ void commit();
int ref;
QQuickItem *item;
@@ -217,13 +227,16 @@ public:
};
~QQuickTransformAnimatorJob();
- Helper *transformHelper() const { return m_helper; }
+
+ void commit() override;
+ void preSync() override;
+
+ void setTarget(QQuickItem *item) override;
protected:
QQuickTransformAnimatorJob();
- void initialize(QQuickAnimatorController *controller) Q_DECL_OVERRIDE;
- void nodeWasDestroyed() Q_DECL_OVERRIDE;
- void targetWasDeleted() Q_DECL_OVERRIDE;
+ void postSync() override;
+ void invalidate() override;
Helper *m_helper;
};
@@ -231,22 +244,22 @@ protected:
class Q_QUICK_PRIVATE_EXPORT QQuickScaleAnimatorJob : public QQuickTransformAnimatorJob
{
public:
- void updateCurrentTime(int time) Q_DECL_OVERRIDE;
- void writeBack() Q_DECL_OVERRIDE;
+ void updateCurrentTime(int time) override;
+ void writeBack() override;
};
class Q_QUICK_PRIVATE_EXPORT QQuickXAnimatorJob : public QQuickTransformAnimatorJob
{
public:
- void updateCurrentTime(int time) Q_DECL_OVERRIDE;
- void writeBack() Q_DECL_OVERRIDE;
+ void updateCurrentTime(int time) override;
+ void writeBack() override;
};
class Q_QUICK_PRIVATE_EXPORT QQuickYAnimatorJob : public QQuickTransformAnimatorJob
{
public:
- void updateCurrentTime(int time) Q_DECL_OVERRIDE;
- void writeBack() Q_DECL_OVERRIDE;
+ void updateCurrentTime(int time) override;
+ void writeBack() override;
};
class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimatorJob : public QQuickTransformAnimatorJob
@@ -254,8 +267,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimatorJob : public QQuickTransformA
public:
QQuickRotationAnimatorJob();
- void updateCurrentTime(int time) Q_DECL_OVERRIDE;
- void writeBack() Q_DECL_OVERRIDE;
+ void updateCurrentTime(int time) override;
+ void writeBack() override;
void setDirection(QQuickRotationAnimator::RotationDirection direction) { m_direction = direction; }
QQuickRotationAnimator::RotationDirection direction() const { return m_direction; }
@@ -269,10 +282,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickOpacityAnimatorJob : public QQuickAnimatorJob
public:
QQuickOpacityAnimatorJob();
- void initialize(QQuickAnimatorController *controller) Q_DECL_OVERRIDE;
- void updateCurrentTime(int time) Q_DECL_OVERRIDE;
- void writeBack() Q_DECL_OVERRIDE;
- void nodeWasDestroyed() Q_DECL_OVERRIDE;
+ void invalidate() override;
+ void updateCurrentTime(int time) override;
+ void writeBack() override;
+ void postSync() override;
private:
QSGOpacityNode *m_opacityNode;
@@ -283,16 +296,17 @@ class Q_QUICK_PRIVATE_EXPORT QQuickUniformAnimatorJob : public QQuickAnimatorJob
public:
QQuickUniformAnimatorJob();
- void setTarget(QQuickItem *target) Q_DECL_OVERRIDE;
+ void setTarget(QQuickItem *target) override;
void setUniform(const QByteArray &uniform) { m_uniform = uniform; }
QByteArray uniform() const { return m_uniform; }
- void afterNodeSync() Q_DECL_OVERRIDE;
+ void postSync() override;
+
+ void updateCurrentTime(int time) override;
+ void writeBack() override;
- void updateCurrentTime(int time) Q_DECL_OVERRIDE;
- void writeBack() Q_DECL_OVERRIDE;
- void nodeWasDestroyed() Q_DECL_OVERRIDE;
+ void invalidate() override;
private:
QByteArray m_uniform;
diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp
index 5c26b23ff7..ca4a5bfb56 100644
--- a/src/quick/util/qquickapplication.cpp
+++ b/src/quick/util/qquickapplication.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qquickapplication_p.h"
-
+#include <private/qquickscreen_p.h>
#include <private/qobject_p.h>
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -63,6 +63,10 @@ QQuickApplication::QQuickApplication(QObject *parent)
this, SIGNAL(stateChanged(Qt::ApplicationState)));
connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
this, SIGNAL(activeChanged()));
+
+ connect(qApp, &QGuiApplication::screenAdded, this, &QQuickApplication::updateScreens);
+ connect(qApp, &QGuiApplication::screenRemoved, this, &QQuickApplication::updateScreens);
+ updateScreens();
}
}
@@ -95,4 +99,32 @@ QFont QQuickApplication::font() const
return QGuiApplication::font();
}
+int screens_count(QQmlListProperty<QQuickScreenInfo> *prop)
+{
+ return static_cast<QVector<QQuickScreenInfo *> *>(prop->data)->count();
+}
+
+QQuickScreenInfo *screens_at(QQmlListProperty<QQuickScreenInfo> *prop, int idx)
+{
+ return static_cast<QVector<QQuickScreenInfo *> *>(prop->data)->at(idx);
+}
+
+QQmlListProperty<QQuickScreenInfo> QQuickApplication::screens()
+{
+ return QQmlListProperty<QQuickScreenInfo>(this,
+ const_cast<QVector<QQuickScreenInfo *> *>(&m_screens), &screens_count, &screens_at);
+}
+
+void QQuickApplication::updateScreens()
+{
+ const QList<QScreen *> screenList = QGuiApplication::screens();
+ m_screens.resize(screenList.count());
+ for (int i = 0; i < screenList.count(); ++i) {
+ if (!m_screens[i])
+ m_screens[i] = new QQuickScreenInfo(this);
+ m_screens[i]->setWrappedScreen(screenList[i]);
+ }
+ emit screensChanged();
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickapplication_p.h b/src/quick/util/qquickapplication_p.h
index 091cb094ed..70381553b4 100644
--- a/src/quick/util/qquickapplication_p.h
+++ b/src/quick/util/qquickapplication_p.h
@@ -56,10 +56,10 @@
#include <qqml.h>
#include <QtQml/private/qqmlglobal_p.h>
#include <private/qtquickglobal_p.h>
+#include "../items/qquickscreen_p.h"
QT_BEGIN_NAMESPACE
-
class Q_AUTOTEST_EXPORT QQuickApplication : public QQmlApplication
{
Q_OBJECT
@@ -68,6 +68,7 @@ class Q_AUTOTEST_EXPORT QQuickApplication : public QQmlApplication
Q_PROPERTY(bool supportsMultipleWindows READ supportsMultipleWindows CONSTANT)
Q_PROPERTY(Qt::ApplicationState state READ state NOTIFY stateChanged)
Q_PROPERTY(QFont font READ font CONSTANT)
+ Q_PROPERTY(QQmlListProperty<QQuickScreenInfo> screens READ screens NOTIFY screensChanged)
public:
explicit QQuickApplication(QObject *parent = 0);
@@ -77,14 +78,20 @@ public:
bool supportsMultipleWindows() const;
Qt::ApplicationState state() const;
QFont font() const;
+ QQmlListProperty<QQuickScreenInfo> screens();
Q_SIGNALS:
void activeChanged();
void layoutDirectionChanged();
void stateChanged(Qt::ApplicationState state);
+ void screensChanged();
+
+private Q_SLOTS:
+ void updateScreens();
private:
Q_DISABLE_COPY(QQuickApplication)
+ QVector<QQuickScreenInfo *> m_screens;
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp
index 147380037d..9af1d41b29 100644
--- a/src/quick/util/qquickbehavior.cpp
+++ b/src/quick/util/qquickbehavior.cpp
@@ -60,7 +60,7 @@ public:
QQuickBehaviorPrivate() : animation(0), animationInstance(0), enabled(true), finalized(false)
, blockRunningChanged(false) {}
- virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) override;
QQmlProperty property;
QVariant targetValue;
@@ -180,7 +180,7 @@ void QQuickBehavior::write(const QVariant &value)
if (!d->animation || bypass) {
if (d->animationInstance)
d->animationInstance->stop();
- QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::write(d->property, value, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
d->targetValue = value;
return;
}
@@ -206,7 +206,7 @@ void QQuickBehavior::write(const QVariant &value)
// is needed (value has not changed). If the Behavior was already
// running, let it continue as normal to ensure correct behavior and state.
if (!behaviorActive && d->targetValue == currentValue) {
- QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::write(d->property, value, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
return;
}
@@ -234,7 +234,7 @@ void QQuickBehavior::write(const QVariant &value)
d->blockRunningChanged = false;
}
if (!after.contains(d->property))
- QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::write(d->property, value, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
}
void QQuickBehavior::setTarget(const QQmlProperty &property)
diff --git a/src/quick/util/qquickbehavior_p.h b/src/quick/util/qquickbehavior_p.h
index c3438d8c6d..b3fd2af400 100644
--- a/src/quick/util/qquickbehavior_p.h
+++ b/src/quick/util/qquickbehavior_p.h
@@ -75,8 +75,8 @@ public:
QQuickBehavior(QObject *parent=0);
~QQuickBehavior();
- virtual void setTarget(const QQmlProperty &);
- virtual void write(const QVariant &value);
+ void setTarget(const QQmlProperty &) override;
+ void write(const QVariant &value) override;
QQuickAbstractAnimation *animation();
void setAnimation(QQuickAbstractAnimation *);
diff --git a/src/quick/util/qquickfontloader.cpp b/src/quick/util/qquickfontloader.cpp
index b7367f3934..6e23d99f7e 100644
--- a/src/quick/util/qquickfontloader.cpp
+++ b/src/quick/util/qquickfontloader.cpp
@@ -264,7 +264,7 @@ void QQuickFontLoader::setSource(const QUrl &url)
updateFontInfo(QString(), Error);
}
} else {
- updateFontInfo(QFontDatabase::applicationFontFamilies(fontLoaderFonts()->map[d->url]->id).at(0), Ready);
+ updateFontInfo(QFontDatabase::applicationFontFamilies(fontLoaderFonts()->map.value(d->url)->id).at(0), Ready);
}
} else {
if (!fontLoaderFonts()->map.contains(d->url)) {
@@ -280,7 +280,7 @@ void QQuickFontLoader::setSource(const QUrl &url)
// Silently fail if compiled with no_network
#endif
} else {
- QQuickFontObject *fo = fontLoaderFonts()->map[d->url];
+ QQuickFontObject *fo = fontLoaderFonts()->map.value(d->url);
if (fo->id == -1) {
#ifndef QT_NO_NETWORK
d->status = Loading;
diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h
index d4719a7f5b..879c4d0fcc 100644
--- a/src/quick/util/qquickimageprovider.h
+++ b/src/quick/util/qquickimageprovider.h
@@ -90,8 +90,8 @@ public:
QQuickImageProvider(ImageType type, Flags flags = Flags());
virtual ~QQuickImageProvider();
- ImageType imageType() const;
- Flags flags() const;
+ ImageType imageType() const override;
+ Flags flags() const override;
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize, bool requestedAutoTransform);
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index 6b491a433c..25a4433a9b 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -358,7 +358,7 @@ QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &en
bool usesPercent = false;
int index = 0;
- foreach (QQuickPathElement *pathElement, d->_pathElements) {
+ for (QQuickPathElement *pathElement : qAsConst(d->_pathElements)) {
if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
QQuickPathData data;
data.index = index;
@@ -382,7 +382,7 @@ QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &en
}
// Fixup end points
- const AttributePoint &last = attributePoints.last();
+ const AttributePoint &last = attributePoints.constLast();
for (int ii = 0; ii < attributes.count(); ++ii) {
if (!last.values.contains(attributes.at(ii)))
endpoint(attributePoints, attributes.at(ii));
@@ -407,11 +407,11 @@ QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &en
}
attributePoints[ii].origpercent /= length;
attributePoints[ii].percent = point.values.value(percentString);
- prevorigpercent = attributePoints[ii].origpercent;
- prevpercent = attributePoints[ii].percent;
+ prevorigpercent = attributePoints.at(ii).origpercent;
+ prevpercent = attributePoints.at(ii).percent;
} else {
attributePoints[ii].origpercent /= length;
- attributePoints[ii].percent = attributePoints[ii].origpercent;
+ attributePoints[ii].percent = attributePoints.at(ii).origpercent;
}
}
@@ -432,17 +432,17 @@ void QQuickPath::classBegin()
void QQuickPath::disconnectPathElements()
{
- Q_D(QQuickPath);
+ Q_D(const QQuickPath);
- foreach (QQuickPathElement *pathElement, d->_pathElements)
+ for (QQuickPathElement *pathElement : d->_pathElements)
disconnect(pathElement, SIGNAL(changed()), this, SLOT(processPath()));
}
void QQuickPath::connectPathElements()
{
- Q_D(QQuickPath);
+ Q_D(const QQuickPath);
- foreach (QQuickPathElement *pathElement, d->_pathElements)
+ for (QQuickPathElement *pathElement : d->_pathElements)
connect(pathElement, SIGNAL(changed()), this, SLOT(processPath()));
}
@@ -453,7 +453,7 @@ void QQuickPath::gatherAttributes()
QSet<QString> attributes;
// First gather up all the attributes
- foreach (QQuickPathElement *pathElement, d->_pathElements) {
+ for (QQuickPathElement *pathElement : qAsConst(d->_pathElements)) {
if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement))
d->_pathCurves.append(curve);
else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement))
@@ -488,7 +488,7 @@ QStringList QQuickPath::attributes() const
QSet<QString> attrs;
// First gather up all the attributes
- foreach (QQuickPathElement *pathElement, d->_pathElements) {
+ for (QQuickPathElement *pathElement : d->_pathElements) {
if (QQuickPathAttribute *attribute =
qobject_cast<QQuickPathAttribute *>(pathElement))
attrs.insert(attribute->name());
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index e2c99de44e..59f1ff3c69 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -55,6 +55,7 @@
#include <private/qqmlnullablevalue_p.h>
#include <private/qbezier_p.h>
+#include <private/qtquickglobal_p.h>
#include <QtCore/QObject>
#include <QtGui/QPainterPath>
@@ -69,7 +70,7 @@ struct QQuickPathData
QList<QQuickCurve*> curves;
};
-class Q_AUTOTEST_EXPORT QQuickPathElement : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickPathElement : public QObject
{
Q_OBJECT
public:
@@ -78,7 +79,7 @@ Q_SIGNALS:
void changed();
};
-class Q_AUTOTEST_EXPORT QQuickPathAttribute : public QQuickPathElement
+class Q_QUICK_PRIVATE_EXPORT QQuickPathAttribute : public QQuickPathElement
{
Q_OBJECT
@@ -103,7 +104,7 @@ private:
qreal _value;
};
-class Q_AUTOTEST_EXPORT QQuickCurve : public QQuickPathElement
+class Q_QUICK_PRIVATE_EXPORT QQuickCurve : public QQuickPathElement
{
Q_OBJECT
@@ -145,16 +146,16 @@ private:
QQmlNullableValue<qreal> _relativeY;
};
-class Q_AUTOTEST_EXPORT QQuickPathLine : public QQuickCurve
+class Q_QUICK_PRIVATE_EXPORT QQuickPathLine : public QQuickCurve
{
Q_OBJECT
public:
QQuickPathLine(QObject *parent=0) : QQuickCurve(parent) {}
- void addToPath(QPainterPath &path, const QQuickPathData &);
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
};
-class Q_AUTOTEST_EXPORT QQuickPathQuad : public QQuickCurve
+class Q_QUICK_PRIVATE_EXPORT QQuickPathQuad : public QQuickCurve
{
Q_OBJECT
@@ -179,7 +180,7 @@ public:
void setRelativeControlY(qreal y);
bool hasRelativeControlY();
- void addToPath(QPainterPath &path, const QQuickPathData &);
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
Q_SIGNALS:
void controlXChanged();
@@ -194,7 +195,7 @@ private:
QQmlNullableValue<qreal> _relativeControlY;
};
-class Q_AUTOTEST_EXPORT QQuickPathCubic : public QQuickCurve
+class Q_QUICK_PRIVATE_EXPORT QQuickPathCubic : public QQuickCurve
{
Q_OBJECT
@@ -237,7 +238,7 @@ public:
void setRelativeControl2Y(qreal y);
bool hasRelativeControl2Y();
- void addToPath(QPainterPath &path, const QQuickPathData &);
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
Q_SIGNALS:
void control1XChanged();
@@ -260,16 +261,16 @@ private:
QQmlNullableValue<qreal> _relativeControl2Y;
};
-class Q_AUTOTEST_EXPORT QQuickPathCatmullRomCurve : public QQuickCurve
+class Q_QUICK_PRIVATE_EXPORT QQuickPathCatmullRomCurve : public QQuickCurve
{
Q_OBJECT
public:
QQuickPathCatmullRomCurve(QObject *parent=0) : QQuickCurve(parent) {}
- void addToPath(QPainterPath &path, const QQuickPathData &);
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
};
-class Q_AUTOTEST_EXPORT QQuickPathArc : public QQuickCurve
+class Q_QUICK_PRIVATE_EXPORT QQuickPathArc : public QQuickCurve
{
Q_OBJECT
Q_PROPERTY(qreal radiusX READ radiusX WRITE setRadiusX NOTIFY radiusXChanged)
@@ -296,7 +297,7 @@ public:
ArcDirection direction() const;
void setDirection(ArcDirection direction);
- void addToPath(QPainterPath &path, const QQuickPathData &);
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
Q_SIGNALS:
void radiusXChanged();
@@ -311,7 +312,7 @@ private:
ArcDirection _direction;
};
-class Q_AUTOTEST_EXPORT QQuickPathSvg : public QQuickCurve
+class Q_QUICK_PRIVATE_EXPORT QQuickPathSvg : public QQuickCurve
{
Q_OBJECT
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
@@ -321,7 +322,7 @@ public:
QString path() const;
void setPath(const QString &path);
- void addToPath(QPainterPath &path, const QQuickPathData &);
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
Q_SIGNALS:
void pathChanged();
@@ -330,7 +331,7 @@ private:
QString _path;
};
-class Q_AUTOTEST_EXPORT QQuickPathPercent : public QQuickPathElement
+class Q_QUICK_PRIVATE_EXPORT QQuickPathPercent : public QQuickPathElement
{
Q_OBJECT
Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
@@ -359,7 +360,7 @@ struct QQuickCachedBezier
};
class QQuickPathPrivate;
-class Q_AUTOTEST_EXPORT QQuickPath : public QObject, public QQmlParserStatus
+class Q_QUICK_PRIVATE_EXPORT QQuickPath : public QObject, public QQmlParserStatus
{
Q_OBJECT
@@ -400,8 +401,8 @@ Q_SIGNALS:
void startYChanged();
protected:
- virtual void componentComplete();
- virtual void classBegin();
+ void componentComplete() override;
+ void classBegin() override;
void disconnectPathElements();
void connectPathElements();
void gatherAttributes();
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index dc4b27d738..987dd3c30f 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -177,7 +177,7 @@ class QQuickPixmapReaderThreadObject : public QObject {
public:
QQuickPixmapReaderThreadObject(QQuickPixmapReader *);
void processJobs();
- virtual bool event(QEvent *e);
+ bool event(QEvent *e) override;
private slots:
void networkRequestDone();
void asyncResponseFinished();
@@ -448,7 +448,7 @@ QQuickPixmapReader::~QQuickPixmapReader()
mutex.lock();
// manually cancel all outstanding jobs.
- foreach (QQuickPixmapReply *reply, jobs) {
+ for (QQuickPixmapReply *reply : qAsConst(jobs)) {
if (reply->data && reply->data->reply == reply)
reply->data->reply = 0;
delete reply;
@@ -629,7 +629,7 @@ void QQuickPixmapReader::processJobs()
// Find a job we can use
bool usableJob = false;
for (int i = jobs.count() - 1; !usableJob && i >= 0; i--) {
- QQuickPixmapReply *job = jobs[i];
+ QQuickPixmapReply *job = jobs.at(i);
const QUrl url = job->url;
QString localFile;
QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid;
@@ -892,7 +892,7 @@ public:
void purgeCache();
protected:
- virtual void timerEvent(QTimerEvent *);
+ void timerEvent(QTimerEvent *) override;
public:
QHash<QQuickPixmapKey, QQuickPixmapData *> m_cache;
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index f53e847e00..623c826815 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -77,10 +77,10 @@ class QQuickDefaultTextureFactory : public QQuickTextureFactory
Q_OBJECT
public:
QQuickDefaultTextureFactory(const QImage &i);
- QSGTexture *createTexture(QQuickWindow *window) const;
- QSize textureSize() const { return size; }
- int textureByteCount() const { return size.width() * size.height() * 4; }
- QImage image() const { return im; }
+ QSGTexture *createTexture(QQuickWindow *window) const override;
+ QSize textureSize() const override { return size; }
+ int textureByteCount() const override { return size.width() * size.height() * 4; }
+ QImage image() const override { return im; }
private:
QImage im;
diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp
index 659ffe1d84..841a1c9bcf 100644
--- a/src/quick/util/qquickprofiler.cpp
+++ b/src/quick/util/qquickprofiler.cpp
@@ -70,7 +70,7 @@ void QQuickProfiler::registerAnimationCallback()
class CallbackRegistrationHelper : public QObject {
Q_OBJECT
-public slots:
+public:
void registerAnimationTimerCallback()
{
QQuickProfiler::registerAnimationCallback();
@@ -86,7 +86,12 @@ QQuickProfiler::QQuickProfiler(QObject *parent) : QObject(parent)
m_timer.start();
CallbackRegistrationHelper *helper = new CallbackRegistrationHelper; // will delete itself
helper->moveToThread(QCoreApplication::instance()->thread());
- QMetaObject::invokeMethod(helper, "registerAnimationTimerCallback", Qt::QueuedConnection);
+
+ // Queue the signal to have the animation timer registration run in the right thread;
+ QObject signalSource;
+ connect(&signalSource, &QObject::destroyed,
+ helper, &CallbackRegistrationHelper::registerAnimationTimerCallback,
+ Qt::QueuedConnection);
}
QQuickProfiler::~QQuickProfiler()
diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h
index f1af87f4e6..66ed212722 100644
--- a/src/quick/util/qquickprofiler_p.h
+++ b/src/quick/util/qquickprofiler_p.h
@@ -62,52 +62,22 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_NO_QML_DEBUGGER
+
+#define Q_QUICK_PROFILE_IF_ENABLED(feature, Code)
+
+struct QQuickProfiler {
+ static void registerAnimationCallback() {}
+};
+
+#else
+
#define Q_QUICK_PROFILE_IF_ENABLED(feature, Code)\
if (QQuickProfiler::featuresEnabled & (1 << feature)) {\
Code;\
} else\
(void)0
-#define Q_QUICK_PROFILE(feature, Method)\
- Q_QUICK_PROFILE_IF_ENABLED(feature, QQuickProfiler::Method)
-
-#define Q_QUICK_SG_PROFILE_START(Type)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
- (QQuickProfiler::startSceneGraphFrame<Type>()))
-
-#define Q_QUICK_SG_PROFILE_RECORD(Type)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
- (QQuickProfiler::recordSceneGraphTimestamp<Type>()))
-
-#define Q_QUICK_SG_PROFILE_SKIP(Type, Skip)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
- (QQuickProfiler::skipSceneGraphTimestamps<Type, Skip>()))
-
-#define Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(Type1, Type2)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
- (QQuickProfiler::startSceneGraphFrame<Type1, Type2>()))
-
-#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2) \
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
- (QQuickProfiler::reportSceneGraphFrame<Type1, true, Type2>()))
-
-#define Q_QUICK_SG_PROFILE_REPORT(Type)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
- (QQuickProfiler::reportSceneGraphFrame<Type, false>()))
-
-#define Q_QUICK_SG_PROFILE_END(Type)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
- (QQuickProfiler::reportSceneGraphFrame<Type, true>()))
-
-#define Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(Type, Payload)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
- (QQuickProfiler::reportSceneGraphFrame<Type, true>(Payload)))
-
-
-#define Q_QUICK_INPUT_PROFILE(Type, DetailType, A, B)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileInputEvents,\
- (QQuickProfiler::inputEvent<Type, DetailType>(A, B)))
-
// This struct is somewhat dangerous to use:
// You can save values either with 32 or 64 bit precision. toByteArrays will
// guess the precision from messageType. If you state the wrong messageType
@@ -319,17 +289,15 @@ public:
qint64 timestamp() { return m_timer.nsecsElapsed(); }
-
static quint64 featuresEnabled;
- static bool profilingSceneGraph()
- {
- return featuresEnabled & (1 << QQuickProfiler::ProfileSceneGraph);
- }
static void initialize(QObject *parent);
virtual ~QQuickProfiler();
+signals:
+ void dataReady(const QVector<QQuickProfilerData> &data);
+
protected:
friend class QQuickProfilerAdapter;
@@ -347,16 +315,54 @@ protected:
m_data.append(message);
}
-signals:
- void dataReady(const QVector<QQuickProfilerData> &data);
-
-protected slots:
void startProfilingImpl(quint64 features);
void stopProfilingImpl();
void reportDataImpl(bool trackLocations);
void setTimer(const QElapsedTimer &t);
};
+#endif // QT_NO_QML_DEBUGGER
+
+#define Q_QUICK_PROFILE(feature, Method)\
+ Q_QUICK_PROFILE_IF_ENABLED(feature, QQuickProfiler::Method)
+
+#define Q_QUICK_SG_PROFILE_START(Type)\
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::startSceneGraphFrame<Type>()))
+
+#define Q_QUICK_SG_PROFILE_RECORD(Type)\
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::recordSceneGraphTimestamp<Type>()))
+
+#define Q_QUICK_SG_PROFILE_SKIP(Type, Skip)\
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::skipSceneGraphTimestamps<Type, Skip>()))
+
+#define Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(Type1, Type2)\
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::startSceneGraphFrame<Type1, Type2>()))
+
+#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2) \
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type1, true, Type2>()))
+
+#define Q_QUICK_SG_PROFILE_REPORT(Type)\
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, false>()))
+
+#define Q_QUICK_SG_PROFILE_END(Type)\
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, true>()))
+
+#define Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(Type, Payload)\
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, true>(Payload)))
+
+
+#define Q_QUICK_INPUT_PROFILE(Type, DetailType, A, B)\
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileInputEvents,\
+ (QQuickProfiler::inputEvent<Type, DetailType>(A, B)))
+
QT_END_NAMESPACE
#endif
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index bd556444de..4dfeb7cc4a 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -46,7 +46,6 @@
#include <private/qqmlcustomparser_p.h>
#include <qqmlexpression.h>
#include <private/qqmlbinding_p.h>
-#include <private/qqmlcompiler_p.h>
#include <qqmlcontext.h>
#include <private/qqmlproperty_p.h>
#include <private/qqmlcontext_p.h>
@@ -143,29 +142,29 @@ public:
QQuickReplaceSignalHandler() {}
~QQuickReplaceSignalHandler() {}
- virtual EventType type() const { return SignalHandler; }
+ EventType type() const override { return SignalHandler; }
QQmlProperty property;
QQmlBoundSignalExpressionPointer expression;
QQmlBoundSignalExpressionPointer reverseExpression;
QQmlBoundSignalExpressionPointer rewindExpression;
- virtual void execute() {
+ void execute() override {
QQmlPropertyPrivate::setSignalExpression(property, expression);
}
- virtual bool isReversable() { return true; }
- virtual void reverse() {
+ bool isReversable() override { return true; }
+ void reverse() override {
QQmlPropertyPrivate::setSignalExpression(property, reverseExpression);
}
- virtual void saveOriginals() {
+ void saveOriginals() override {
saveCurrentValues();
reverseExpression = rewindExpression;
}
- virtual bool needsCopy() { return true; }
- virtual void copyOriginals(QQuickStateActionEvent *other)
+ bool needsCopy() override { return true; }
+ void copyOriginals(QQuickStateActionEvent *other) override
{
QQuickReplaceSignalHandler *rsh = static_cast<QQuickReplaceSignalHandler*>(other);
saveCurrentValues();
@@ -174,14 +173,14 @@ public:
reverseExpression = rsh->reverseExpression;
}
- virtual void rewind() {
+ void rewind() override {
QQmlPropertyPrivate::setSignalExpression(property, rewindExpression);
}
- virtual void saveCurrentValues() {
+ void saveCurrentValues() override {
rewindExpression = QQmlPropertyPrivate::signalExpression(property);
}
- virtual bool override(QQuickStateActionEvent*other) {
+ bool override(QQuickStateActionEvent *other) override {
if (other == this)
return true;
if (other->type() != type())
@@ -257,7 +256,7 @@ void QQuickPropertyChangesPrivate::decode()
if (decoded)
return;
- foreach (const QV4::CompiledData::Binding *binding, bindings)
+ for (const QV4::CompiledData::Binding *binding : qAsConst(bindings))
decodeBinding(QString(), compilationUnit->data, binding);
bindings.clear();
@@ -288,7 +287,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
handler->property = prop;
handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
- QQmlContextData::get(qmlContext(q)), object, compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]));
+ QQmlContextData::get(qmlContext(q)), object, compilationUnit->runtimeFunctions.at(binding->value.compiledScriptIndex)));
signalReplacements << handler;
return;
}
@@ -456,12 +455,14 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
QQmlBinding *newBinding = 0;
if (e.id != QQmlBinding::Invalid) {
QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
- QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, object(), d->compilationUnit->runtimeFunctions[e.id]));
- newBinding = new QQmlBinding(function, object(), context);
+ QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, object(), d->compilationUnit->runtimeFunctions.at(e.id)));
+ newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core,
+ function, object(), context);
}
// QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0;
if (!newBinding)
- newBinding = new QQmlBinding(e.expression, object(), context, e.url.toString(), e.line, e.column);
+ newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core,
+ e.expression, object(), context, e.url.toString(), e.line, e.column);
if (d->isExplicit) {
// in this case, we don't want to assign a binding, per se,
@@ -596,7 +597,7 @@ void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &val
state()->addEntryToRevertList(action);
QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(action.property);
if (oldBinding)
- oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
+ oldBinding->setEnabled(false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
d->property(name).write(value);
}
}
@@ -625,9 +626,12 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString
if (entry.name == name) {
entry.expression = expression;
if (state() && state()->isStateActive()) {
- QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this));
- newBinding->setTarget(d->property(name));
- QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
+ auto prop = d->property(name);
+ QQmlBinding *newBinding = QQmlBinding::create(
+ &QQmlPropertyPrivate::get(prop)->core, expression, object(),
+ qmlContext(this));
+ newBinding->setTarget(prop);
+ QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
}
return;
}
@@ -640,13 +644,16 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString
if (hadValue) {
QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name));
if (oldBinding) {
- oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
+ oldBinding->setEnabled(false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
state()->changeBindingInRevertList(object(), name, oldBinding);
}
- QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this));
- newBinding->setTarget(d->property(name));
- QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
+ auto prop = d->property(name);
+ QQmlBinding *newBinding = QQmlBinding::create(
+ &QQmlPropertyPrivate::get(prop)->core, expression, object(),
+ qmlContext(this));
+ newBinding->setTarget(prop);
+ QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
} else {
QQuickStateAction action;
action.restore = restoreEntryValues();
@@ -655,7 +662,9 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString
action.specifiedObject = object();
action.specifiedProperty = name;
- QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this));
+ QQmlBinding *newBinding = QQmlBinding::create(
+ &QQmlPropertyPrivate::get(action.property)->core, expression,
+ object(), qmlContext(this));
if (d->isExplicit) {
// don't assign the binding, merely evaluate the expression.
// XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString)
@@ -670,9 +679,9 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString
state()->addEntryToRevertList(action);
QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(action.property);
if (oldBinding)
- oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
+ oldBinding->setEnabled(false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
- QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
+ QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
}
}
}
diff --git a/src/quick/util/qquickpropertychanges_p.h b/src/quick/util/qquickpropertychanges_p.h
index 0537750338..35b37e84cb 100644
--- a/src/quick/util/qquickpropertychanges_p.h
+++ b/src/quick/util/qquickpropertychanges_p.h
@@ -78,7 +78,7 @@ public:
bool isExplicit() const;
void setIsExplicit(bool);
- virtual ActionList actions();
+ ActionList actions() override;
bool containsProperty(const QString &name) const;
bool containsValue(const QString &name) const;
@@ -103,8 +103,8 @@ public:
void verifyList(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding);
- virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
- virtual void applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
+ void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) override;
+ void applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
};
diff --git a/src/quick/util/qquickshortcut.cpp b/src/quick/util/qquickshortcut.cpp
index 66c29474cc..9725ddd671 100644
--- a/src/quick/util/qquickshortcut.cpp
+++ b/src/quick/util/qquickshortcut.cpp
@@ -144,7 +144,7 @@ void QQuickShortcut::setSequence(const QVariant &sequence)
\since 5.6
This property provides the shortcut's key sequence as a platform specific
- string. This means that it will be shown translated, and on OS X it will
+ string. This means that it will be shown translated, and on \macos it will
resemble a key sequence from the menu bar. It is best to display this text
to the user (for example, on a tooltip).
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index 569cb37c95..e7beee8ed3 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -254,8 +254,8 @@ void QSmoothedAnimation::updateCurrentTime(int t)
qreal value = easeFollow(time_seconds);
value *= (invert? -1.0: 1.0);
QQmlPropertyPrivate::write(target, initialValue + value,
- QQmlPropertyPrivate::BypassInterceptor
- | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyData::BypassInterceptor
+ | QQmlPropertyData::DontRemoveBinding);
}
void QSmoothedAnimation::init()
@@ -287,8 +287,8 @@ void QSmoothedAnimation::init()
break;
case QQuickSmoothedAnimation::Sync:
QQmlPropertyPrivate::write(target, to,
- QQmlPropertyPrivate::BypassInterceptor
- | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyData::BypassInterceptor
+ | QQmlPropertyData::DontRemoveBinding);
trackVelocity = 0;
stop();
return;
@@ -304,8 +304,8 @@ void QSmoothedAnimation::init()
if (!recalc()) {
QQmlPropertyPrivate::write(target, to,
- QQmlPropertyPrivate::BypassInterceptor
- | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyData::BypassInterceptor
+ | QQmlPropertyData::DontRemoveBinding);
stop();
return;
}
@@ -409,7 +409,7 @@ QAbstractAnimationJob* QQuickSmoothedAnimation::transition(QQuickStateActions &a
Q_UNUSED(direction);
Q_D(QQuickSmoothedAnimation);
- QQuickStateActions dataActions = QQuickPropertyAnimation::createTransitionActions(actions, modified, defaultTarget);
+ const QQuickStateActions dataActions = QQuickPropertyAnimation::createTransitionActions(actions, modified, defaultTarget);
QContinuingAnimationGroupJob *wrapperGroup = new QContinuingAnimationGroupJob();
diff --git a/src/quick/util/qquicksmoothedanimation_p.h b/src/quick/util/qquicksmoothedanimation_p.h
index d640985b39..2f0e3bc0d8 100644
--- a/src/quick/util/qquicksmoothedanimation_p.h
+++ b/src/quick/util/qquicksmoothedanimation_p.h
@@ -79,8 +79,8 @@ public:
ReversingMode reversingMode() const;
void setReversingMode(ReversingMode);
- virtual int duration() const;
- virtual void setDuration(int);
+ int duration() const override;
+ void setDuration(int) override;
qreal velocity() const;
void setVelocity(qreal);
@@ -88,10 +88,10 @@ public:
int maximumEasingTime() const;
void setMaximumEasingTime(int);
- virtual QAbstractAnimationJob* transition(QQuickStateActions &actions,
+ QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0);
+ QObject *defaultTarget = 0) override;
Q_SIGNALS:
void velocityChanged();
void reversingModeChanged();
diff --git a/src/quick/util/qquicksmoothedanimation_p_p.h b/src/quick/util/qquicksmoothedanimation_p_p.h
index 4a61599592..a415fdb55f 100644
--- a/src/quick/util/qquicksmoothedanimation_p_p.h
+++ b/src/quick/util/qquicksmoothedanimation_p_p.h
@@ -93,7 +93,7 @@ public:
QQmlProperty target;
- int duration() const;
+ int duration() const override;
void restart();
void init();
@@ -101,9 +101,9 @@ public:
void clearTemplate() { animationTemplate = 0; }
protected:
- virtual void updateCurrentTime(int);
- virtual void updateState(QAbstractAnimationJob::State, QAbstractAnimationJob::State);
- void debugAnimation(QDebug d) const;
+ void updateCurrentTime(int) override;
+ void updateState(QAbstractAnimationJob::State, QAbstractAnimationJob::State) override;
+ void debugAnimation(QDebug d) const override;
private:
qreal easeFollow(qreal);
diff --git a/src/quick/util/qquickspringanimation.cpp b/src/quick/util/qquickspringanimation.cpp
index d2bc3b4ece..a9940959a0 100644
--- a/src/quick/util/qquickspringanimation.cpp
+++ b/src/quick/util/qquickspringanimation.cpp
@@ -61,7 +61,7 @@ public:
QSpringAnimation(QQuickSpringAnimationPrivate * = 0);
~QSpringAnimation();
- int duration() const;
+ int duration() const override;
void restart();
void init();
@@ -97,9 +97,9 @@ public:
void clearTemplate() { animationTemplate = 0; }
protected:
- virtual void updateCurrentTime(int time);
- virtual void updateState(QAbstractAnimationJob::State, QAbstractAnimationJob::State);
- void debugAnimation(QDebug d) const;
+ void updateCurrentTime(int time) override;
+ void updateState(QAbstractAnimationJob::State, QAbstractAnimationJob::State) override;
+ void debugAnimation(QDebug d) const override;
private:
QQuickSpringAnimationPrivate *animationTemplate;
@@ -301,8 +301,8 @@ void QSpringAnimation::updateCurrentTime(int time)
qreal old_to = to;
QQmlPropertyPrivate::write(target, currentValue,
- QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyData::BypassInterceptor |
+ QQmlPropertyData::DontRemoveBinding);
if (stopped && old_to == to) { // do not stop if we got restarted
if (animationTemplate)
diff --git a/src/quick/util/qquickspringanimation_p.h b/src/quick/util/qquickspringanimation_p.h
index 141a2469d7..ffb2c41e6b 100644
--- a/src/quick/util/qquickspringanimation_p.h
+++ b/src/quick/util/qquickspringanimation_p.h
@@ -94,10 +94,10 @@ public:
qreal modulus() const;
void setModulus(qreal modulus);
- virtual QAbstractAnimationJob* transition(QQuickStateActions &actions,
+ QAbstractAnimationJob* transition(QQuickStateActions &actions,
QQmlProperties &modified,
TransitionDirection direction,
- QObject *defaultTarget = 0);
+ QObject *defaultTarget = 0) override;
Q_SIGNALS:
void modulusChanged();
diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp
index 947a5b6e4e..2d3934cce8 100644
--- a/src/quick/util/qquickstate.cpp
+++ b/src/quick/util/qquickstate.cpp
@@ -334,7 +334,7 @@ QQuickStatePrivate::generateActionList() const
}
}
- foreach(QQuickStateOperation *op, operations)
+ for (QQuickStateOperation *op : operations)
applyList << op->actions();
inState = false;
@@ -676,7 +676,7 @@ void QQuickState::apply(QQuickTransition *trans, QQuickState *revert)
#ifndef QT_NO_DEBUG_STREAM
// Output for debugging
if (stateChangeDebug()) {
- foreach(const QQuickStateAction &action, applyList) {
+ for (const QQuickStateAction &action : qAsConst(applyList)) {
if (action.event)
qWarning() << " QQuickStateAction event:" << action.event->type();
else
diff --git a/src/quick/util/qquickstatechangescript_p.h b/src/quick/util/qquickstatechangescript_p.h
index 0c17b7c68c..a1315ae2ef 100644
--- a/src/quick/util/qquickstatechangescript_p.h
+++ b/src/quick/util/qquickstatechangescript_p.h
@@ -69,9 +69,9 @@ public:
QQuickStateChangeScript(QObject *parent=0);
~QQuickStateChangeScript();
- virtual ActionList actions();
+ ActionList actions() override;
- virtual EventType type() const;
+ EventType type() const override;
QQmlScriptString script() const;
void setScript(const QQmlScriptString &);
@@ -79,7 +79,7 @@ public:
QString name() const;
void setName(const QString &);
- virtual void execute();
+ void execute() override;
};
diff --git a/src/quick/util/qquickstategroup_p.h b/src/quick/util/qquickstategroup_p.h
index 78508ac166..eebe3a9e56 100644
--- a/src/quick/util/qquickstategroup_p.h
+++ b/src/quick/util/qquickstategroup_p.h
@@ -81,8 +81,8 @@ public:
QQuickState *findState(const QString &name) const;
void removeState(QQuickState *state);
- virtual void classBegin();
- virtual void componentComplete();
+ void classBegin() override;
+ void componentComplete() override;
Q_SIGNALS:
void stateChanged(const QString &);
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index 83409e8b34..ae8719341d 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -658,10 +658,13 @@ bool QQuickStyledTextPrivate::parseAnchorAttributes(const QChar *&ch, const QStr
void QQuickStyledTextPrivate::parseImageAttributes(const QChar *&ch, const QString &textIn, QString &textOut)
{
qreal imgWidth = 0.0;
+ QFontMetricsF fm(layout.font());
+ const qreal spaceWidth = fm.width(QChar::Nbsp);
+ const bool trailingSpace = textOut.endsWith(space);
if (!updateImagePositions) {
QQuickStyledTextImgTag *image = new QQuickStyledTextImgTag;
- image->position = textOut.length() + 1;
+ image->position = textOut.length() + (trailingSpace ? 0 : 1);
QPair<QStringRef,QStringRef> attr;
do {
@@ -698,14 +701,16 @@ void QQuickStyledTextPrivate::parseImageAttributes(const QChar *&ch, const QStri
}
imgWidth = image->size.width();
+ image->offset = -std::fmod(imgWidth, spaceWidth) / 2.0;
imgTags->append(image);
} else {
// if we already have a list of img tags for this text
// we only want to update the positions of these tags.
QQuickStyledTextImgTag *image = imgTags->value(nbImages);
- image->position = textOut.length() + 1;
+ image->position = textOut.length() + (trailingSpace ? 0 : 1);
imgWidth = image->size.width();
+ image->offset = -std::fmod(imgWidth, spaceWidth) / 2.0;
QPair<QStringRef,QStringRef> attr;
do {
attr = parseAttribute(ch, textIn);
@@ -713,11 +718,10 @@ void QQuickStyledTextPrivate::parseImageAttributes(const QChar *&ch, const QStri
nbImages++;
}
- QFontMetricsF fm(layout.font());
- QString padding(qFloor(imgWidth / fm.width(QChar::Nbsp)), QChar::Nbsp);
- textOut += QLatin1Char(' ');
- textOut += padding;
- textOut += QLatin1Char(' ');
+ QString padding(qFloor(imgWidth / spaceWidth), QChar::Nbsp);
+ if (!trailingSpace)
+ textOut += QLatin1Char(' ');
+ textOut += padding + QLatin1Char(' ');
}
QPair<QStringRef,QStringRef> QQuickStyledTextPrivate::parseAttribute(const QChar *&ch, const QString &textIn)
diff --git a/src/quick/util/qquickstyledtext_p.h b/src/quick/util/qquickstyledtext_p.h
index ee3f42cb48..2a2e234224 100644
--- a/src/quick/util/qquickstyledtext_p.h
+++ b/src/quick/util/qquickstyledtext_p.h
@@ -68,7 +68,7 @@ class Q_AUTOTEST_EXPORT QQuickStyledTextImgTag
{
public:
QQuickStyledTextImgTag()
- : position(0), align(QQuickStyledTextImgTag::Bottom), pix(0)
+ : position(0), offset(0.0), align(QQuickStyledTextImgTag::Bottom), pix(0)
{ }
~QQuickStyledTextImgTag() { delete pix; }
@@ -83,6 +83,7 @@ public:
QPointF pos;
QSize size;
int position;
+ qreal offset; // this offset allows us to compensate for flooring reserved space
Align align;
QQuickPixmap *pix;
};
diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp
index 74baa3bfda..b3f0caa2b3 100644
--- a/src/quick/util/qquicktimeline.cpp
+++ b/src/quick/util/qquicktimeline.cpp
@@ -154,7 +154,7 @@ void QQuickTimeLinePrivate::add(QQuickTimeLineObject &g, const Op &o)
}
if (!iter->ops.isEmpty() &&
o.type == Op::Pause &&
- iter->ops.last().type == Op::Pause) {
+ iter->ops.constLast().type == Op::Pause) {
iter->ops.last().length += o.length;
iter->length += o.length;
} else {
diff --git a/src/quick/util/qquicktimeline_p_p.h b/src/quick/util/qquicktimeline_p_p.h
index 552f194b79..ae1087487b 100644
--- a/src/quick/util/qquicktimeline_p_p.h
+++ b/src/quick/util/qquicktimeline_p_p.h
@@ -100,14 +100,14 @@ public:
int time() const;
- virtual int duration() const;
+ int duration() const override;
Q_SIGNALS:
void updated();
void completed();
protected:
- virtual void updateCurrentTime(int);
- void debugAnimation(QDebug d) const;
+ void updateCurrentTime(int) override;
+ void debugAnimation(QDebug d) const override;
private:
void remove(QQuickTimeLineObject *);
@@ -181,7 +181,7 @@ public:
Q_ASSERT(_class);
}
- virtual void setValue(qreal v)
+ void setValue(qreal v) override
{
QQuickTimeLineValue::setValue(v);
if (_setFunctionReal) (_class->*_setFunctionReal)(v);
diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp
index c8b5482c87..1d258d84bf 100644
--- a/src/quick/util/qquicktransition.cpp
+++ b/src/quick/util/qquicktransition.cpp
@@ -106,7 +106,7 @@ public:
QQuickTransitionManager *manager;
protected:
- virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) override;
};
class QQuickTransitionPrivate : public QObjectPrivate, QAnimationJobChangeListener
@@ -134,7 +134,7 @@ public:
bool reversible;
bool enabled;
protected:
- virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State, QAbstractAnimationJob::State);
+ void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State, QAbstractAnimationJob::State) override;
static void append_animation(QQmlListProperty<QQuickAbstractAnimation> *list, QQuickAbstractAnimation *a);
static int animation_count(QQmlListProperty<QQuickAbstractAnimation> *list);
diff --git a/src/quick/util/qquicktransitionmanager.cpp b/src/quick/util/qquicktransitionmanager.cpp
index 55abb0a207..714e6d62b6 100644
--- a/src/quick/util/qquicktransitionmanager.cpp
+++ b/src/quick/util/qquicktransitionmanager.cpp
@@ -106,7 +106,7 @@ void QQuickTransitionManager::complete()
void QQuickTransitionManagerPrivate::applyBindings()
{
- foreach(const QQuickStateAction &action, bindingsList) {
+ for (const QQuickStateAction &action : qAsConst(bindingsList)) {
if (action.toBinding) {
QQmlPropertyPrivate::setBinding(action.toBinding.data());
} else if (action.event) {
@@ -133,7 +133,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list,
QQuickStateOperation::ActionList applyList = list;
// Determine which actions are binding changes and disable any current bindings
- foreach(const QQuickStateAction &action, applyList) {
+ for (const QQuickStateAction &action : qAsConst(applyList)) {
if (action.toBinding)
d->bindingsList << action;
if (action.fromBinding)
@@ -159,9 +159,9 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list,
for (int ii = 0; ii < applyList.size(); ++ii) {
const QQuickStateAction &action = applyList.at(ii);
if (action.toBinding) {
- QQmlPropertyPrivate::setBinding(action.toBinding.data(), QQmlPropertyPrivate::None, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::setBinding(action.toBinding.data(), QQmlPropertyPrivate::None, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
} else if (!action.event) {
- QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
} else if (action.event->isReversable()) {
if (action.reverseEvent)
action.event->reverse();
@@ -184,7 +184,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list,
}
// Revert back to the original values
- foreach(const QQuickStateAction &action, applyList) {
+ for (const QQuickStateAction &action : qAsConst(applyList)) {
if (action.event) {
if (action.event->isReversable()) {
action.event->clearBindings();
@@ -197,7 +197,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list,
if (action.toBinding)
QQmlPropertyPrivate::removeBinding(action.property); // Make sure this is disabled during the transition
- QQmlPropertyPrivate::write(action.property, action.fromValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
+ QQmlPropertyPrivate::write(action.property, action.fromValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
}
}
@@ -239,7 +239,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list,
// be applied immediately. We skip applying bindings, as they are all
// applied at the end in applyBindings() to avoid any nastiness mid
// transition
- foreach(const QQuickStateAction &action, applyList) {
+ for (const QQuickStateAction &action : qAsConst(applyList)) {
if (action.event && !action.event->changesBindings()) {
if (action.event->isReversable() && action.reverseEvent)
action.event->reverse();
@@ -251,7 +251,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list,
}
#ifndef QT_NO_DEBUG_STREAM
if (stateChangeDebug()) {
- foreach(const QQuickStateAction &action, applyList) {
+ for (const QQuickStateAction &action : qAsConst(applyList)) {
if (action.event)
qWarning() << " No transition for event:" << action.event->type();
else
diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp
index 7b9b6068bd..e673df0451 100644
--- a/src/quick/util/qquickvaluetypes.cpp
+++ b/src/quick/util/qquickvaluetypes.cpp
@@ -80,6 +80,36 @@ qreal QQuickColorValueType::a() const
return v.alphaF();
}
+qreal QQuickColorValueType::hsvHue() const
+{
+ return v.hsvHueF();
+}
+
+qreal QQuickColorValueType::hsvSaturation() const
+{
+ return v.hsvSaturationF();
+}
+
+qreal QQuickColorValueType::hsvValue() const
+{
+ return v.valueF();
+}
+
+qreal QQuickColorValueType::hslHue() const
+{
+ return v.hslHueF();
+}
+
+qreal QQuickColorValueType::hslSaturation() const
+{
+ return v.hslSaturationF();
+}
+
+qreal QQuickColorValueType::hslLightness() const
+{
+ return v.lightnessF();
+}
+
void QQuickColorValueType::setR(qreal r)
{
v.setRedF(r);
@@ -100,6 +130,48 @@ void QQuickColorValueType::setA(qreal a)
v.setAlphaF(a);
}
+void QQuickColorValueType::setHsvHue(qreal hsvHue)
+{
+ qreal hue, saturation, value, alpha;
+ v.getHsvF(&hue, &saturation, &value, &alpha);
+ v.setHsvF(hsvHue, saturation, value, alpha);
+}
+
+void QQuickColorValueType::setHsvSaturation(qreal hsvSaturation)
+{
+ qreal hue, saturation, value, alpha;
+ v.getHsvF(&hue, &saturation, &value, &alpha);
+ v.setHsvF(hue, hsvSaturation, value, alpha);
+}
+
+void QQuickColorValueType::setHsvValue(qreal hsvValue)
+{
+ qreal hue, saturation, value, alpha;
+ v.getHsvF(&hue, &saturation, &value, &alpha);
+ v.setHsvF(hue, saturation, hsvValue, alpha);
+}
+
+void QQuickColorValueType::setHslHue(qreal hslHue)
+{
+ qreal hue, saturation, lightness, alpha;
+ v.getHslF(&hue, &saturation, &lightness, &alpha);
+ v.setHslF(hslHue, saturation, lightness, alpha);
+}
+
+void QQuickColorValueType::setHslSaturation(qreal hslSaturation)
+{
+ qreal hue, saturation, lightness, alpha;
+ v.getHslF(&hue, &saturation, &lightness, &alpha);
+ v.setHslF(hue, hslSaturation, lightness, alpha);
+}
+
+void QQuickColorValueType::setHslLightness(qreal hslLightness)
+{
+ qreal hue, saturation, lightness, alpha;
+ v.getHslF(&hue, &saturation, &lightness, &alpha);
+ v.setHslF(hue, saturation, hslLightness, alpha);
+}
+
QString QQuickVector2DValueType::toString() const
{
return QString(QLatin1String("QVector2D(%1, %2)")).arg(v.x()).arg(v.y());
diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h
index 05e954f915..4a1598ec5c 100644
--- a/src/quick/util/qquickvaluetypes_p.h
+++ b/src/quick/util/qquickvaluetypes_p.h
@@ -78,6 +78,12 @@ class QQuickColorValueType
Q_PROPERTY(qreal g READ g WRITE setG FINAL)
Q_PROPERTY(qreal b READ b WRITE setB FINAL)
Q_PROPERTY(qreal a READ a WRITE setA FINAL)
+ Q_PROPERTY(qreal hsvHue READ hsvHue WRITE setHsvHue FINAL)
+ Q_PROPERTY(qreal hsvSaturation READ hsvSaturation WRITE setHsvSaturation FINAL)
+ Q_PROPERTY(qreal hsvValue READ hsvValue WRITE setHsvValue FINAL)
+ Q_PROPERTY(qreal hslHue READ hslHue WRITE setHslHue FINAL)
+ Q_PROPERTY(qreal hslSaturation READ hslSaturation WRITE setHslSaturation FINAL)
+ Q_PROPERTY(qreal hslLightness READ hslLightness WRITE setHslLightness FINAL)
Q_GADGET
public:
Q_INVOKABLE QString toString() const;
@@ -86,10 +92,22 @@ public:
qreal g() const;
qreal b() const;
qreal a() const;
+ qreal hsvHue() const;
+ qreal hsvSaturation() const;
+ qreal hsvValue() const;
+ qreal hslHue() const;
+ qreal hslSaturation() const;
+ qreal hslLightness() const;
void setR(qreal);
void setG(qreal);
void setB(qreal);
void setA(qreal);
+ void setHsvHue(qreal);
+ void setHsvSaturation(qreal);
+ void setHsvValue(qreal);
+ void setHslHue(qreal);
+ void setHslSaturation(qreal);
+ void setHslLightness(qreal);
};
class QQuickVector2DValueType
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index ffb31ae75e..66792536d7 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -26,12 +26,13 @@ SOURCES += \
$$PWD/qquickanimator.cpp \
$$PWD/qquickanimatorjob.cpp \
$$PWD/qquickanimatorcontroller.cpp \
- $$PWD/qquickprofiler.cpp \
$$PWD/qquickfontmetrics.cpp \
$$PWD/qquicktextmetrics.cpp \
$$PWD/qquickshortcut.cpp \
$$PWD/qquickvalidator.cpp
+!contains(QT_CONFIG, no-qml-debug): SOURCES += $$PWD/qquickprofiler.cpp
+
HEADERS += \
$$PWD/qquickapplication_p.h\
$$PWD/qquickutilmodule_p.h\
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index d6de552017..de3692afb0 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -59,9 +59,11 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformintegration.h>
+#ifndef QT_NO_OPENGL
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/private/qopenglextensions_p.h>
+#endif
#include <QtGui/QPainter>
#include <QtQuick/QSGRendererInterface>
@@ -74,7 +76,9 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_OPENGL
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
+#endif
class QQuickWidgetRenderControl : public QQuickRenderControl
{
@@ -104,18 +108,17 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
useSoftwareRenderer = true;
if (!useSoftwareRenderer) {
+#ifndef QT_NO_OPENGL
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface))
setRenderToTexture();
else
+#endif
qWarning("QQuickWidget is not supported on this platform.");
}
engine = e;
- if (engine.isNull())
- engine = new QQmlEngine(q);
-
- if (!engine.data()->incubationController())
+ if (!engine.isNull() && !engine.data()->incubationController())
engine.data()->setIncubationController(offscreenWindow->incubationController());
#ifndef QT_NO_DRAGANDDROP
@@ -128,8 +131,19 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
}
+void QQuickWidgetPrivate::ensureEngine() const
+{
+ Q_Q(const QQuickWidget);
+ if (!engine.isNull())
+ return;
+
+ engine = new QQmlEngine(const_cast<QQuickWidget*>(q));
+ engine.data()->setIncubationController(offscreenWindow->incubationController());
+}
+
void QQuickWidgetPrivate::invalidateRenderControl()
{
+#ifndef QT_NO_OPENGL
if (!useSoftwareRenderer) {
if (!context) // this is not an error, could be called before creating the context, or multiple times
return;
@@ -140,13 +154,25 @@ void QQuickWidgetPrivate::invalidateRenderControl()
return;
}
}
+#endif
renderControl->invalidate();
}
void QQuickWidgetPrivate::handleWindowChange()
{
+ if (offscreenWindow->isPersistentSceneGraph() && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts))
+ return;
+
+ // In case of !isPersistentSceneGraph or when we need a new context due to
+ // the need to share resources with the new window's context, we must both
+ // invalidate the scenegraph and destroy the context. With
+ // QQuickRenderControl destroying the context must be preceded by an
+ // invalidate to prevent being left with dangling context references in the
+ // rendercontrol.
+
invalidateRenderControl();
+
if (!useSoftwareRenderer)
destroyContext();
}
@@ -157,9 +183,11 @@ QQuickWidgetPrivate::QQuickWidgetPrivate()
, offscreenWindow(0)
, offscreenSurface(0)
, renderControl(0)
+#ifndef QT_NO_OPENGL
, fbo(0)
, resolvedFbo(0)
, context(0)
+#endif
, resizeMode(QQuickWidget::SizeViewToRootObject)
, initialSize(0,0)
, eventPending(false)
@@ -178,6 +206,7 @@ QQuickWidgetPrivate::~QQuickWidgetPrivate()
delete renderControl;
delete offscreenWindow;
} else {
+#ifndef QT_NO_OPENGL
// context and offscreenSurface are current at this stage, if the context was created.
Q_ASSERT(!context || (QOpenGLContext::currentContext() == context && context->surface() == offscreenSurface));
delete renderControl; // always delete the rendercontrol first
@@ -186,16 +215,14 @@ QQuickWidgetPrivate::~QQuickWidgetPrivate()
delete fbo;
destroyContext();
+#endif
}
}
void QQuickWidgetPrivate::execute()
{
Q_Q(QQuickWidget);
- if (!engine) {
- qWarning() << "QQuickWidget: invalid qml engine.";
- return;
- }
+ ensureEngine();
if (root) {
delete root;
@@ -217,19 +244,21 @@ void QQuickWidgetPrivate::execute()
}
}
-void QQuickWidgetPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickWidgetPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change,
+ const QRectF &diff)
{
Q_Q(QQuickWidget);
if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) {
// wait for both width and height to be changed
resizetimer.start(0,q);
}
- QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+ QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, diff);
}
void QQuickWidgetPrivate::render(bool needsSync)
{
if (!useSoftwareRenderer) {
+#ifndef QT_NO_OPENGL
// createFramebufferObject() bails out when the size is empty. In this case
// we cannot render either.
if (!fbo)
@@ -259,6 +288,7 @@ void QQuickWidgetPrivate::render(bool needsSync)
static_cast<QOpenGLExtensions *>(context->functions())->flushShared();
QOpenGLContextPrivate::get(context)->defaultFboRedirect = 0;
+#endif
} else {
//Software Renderer
if (needsSync) {
@@ -268,7 +298,7 @@ void QQuickWidgetPrivate::render(bool needsSync)
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer);
- if (softwareRenderer) {
+ if (softwareRenderer && !softwareImage.isNull()) {
softwareRenderer->setCurrentPaintDevice(&softwareImage);
renderControl->render();
@@ -313,10 +343,12 @@ void QQuickWidgetPrivate::renderSceneGraph()
QImage QQuickWidgetPrivate::grabFramebuffer()
{
if (!useSoftwareRenderer) {
+#ifndef QT_NO_OPENGL
if (!context)
return QImage();
context->makeCurrent(offscreenSurface);
+#endif
}
return renderControl->grab();
}
@@ -386,6 +418,36 @@ QObject *QQuickWidgetPrivate::focusObject()
entire purpose of QQuickWidget is to render Quick scenes without a separate native
window, hence making it a native widget should always be avoided.
+ \section1 Scene graph and context persistency
+
+ QQuickWidget honors QQuickWindow::isPersistentSceneGraph(), meaning that
+ applications can decide - by calling
+ QQuickWindow::setPersistentSceneGraph() on the window returned from the
+ quickWindow() function - to let scenegraph nodes and other Qt Quick scene
+ related resources be released whenever the widget becomes hidden. By default
+ persistency is enabled, just like with QQuickWindow.
+
+ When running with the OpenGL backend of the scene graph, QQuickWindow
+ offers the possibility to disable persistent OpenGL contexts as well. This
+ setting is currently ignored by QQuickWidget and the context is always
+ persistent. The OpenGL context is thus not destroyed when hiding the
+ widget. The context is destroyed only when the widget is destroyed or when
+ the widget gets reparented into another top-level widget's child hierarchy.
+ However, some applications, in particular those that have their own
+ graphics resources due to performing custom OpenGL rendering in the Qt
+ Quick scene, may wish to disable the latter since they may not be prepared
+ to handle the loss of the context when moving a QQuickWidget into another
+ window. Such applications can set the
+ QCoreApplication::AA_ShareOpenGLContexts attribute. For a discussion on the
+ details of resource initialization and cleanup, refer to the QOpenGLWidget
+ documentation.
+
+ \note QQuickWidget offers less fine-grained control over its internal
+ OpenGL context than QOpenGLWidget, and there are subtle differences, most
+ notably that disabling the persistent scene graph will lead to destroying
+ the context on a window change regardless of the presence of
+ QCoreApplication::AA_ShareOpenGLContexts.
+
\section1 Limitations
Putting other widgets underneath and making the QQuickWidget transparent will not lead
@@ -406,6 +468,13 @@ QObject *QQuickWidgetPrivate::focusObject()
Qt::WA_TranslucentBackground on the top-level window, request an alpha channel, and
change the Qt Quick Scenegraph's clear color to Qt::transparent via setClearColor().
+ \section1 Support when not using OpenGL
+
+ In addition to OpenGL, the \c software backend of Qt Quick also supports
+ QQuickWidget. Other backends, for example the Direct 3D 12 one, are not
+ compatible however and attempting to construct a QQuickWidget will lead to
+ problems.
+
\sa {Exposing Attributes of C++ Types to QML}, {Qt Quick Widgets Example}, QQuickView
*/
@@ -452,7 +521,6 @@ QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
{
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
- Q_ASSERT(engine);
d_func()->init(engine);
}
@@ -507,8 +575,8 @@ void QQuickWidget::setContent(const QUrl& url, QQmlComponent *component, QObject
d->component = component;
if (d->component && d->component->isError()) {
- QList<QQmlError> errorList = d->component->errors();
- foreach (const QQmlError &error, errorList) {
+ const QList<QQmlError> errorList = d->component->errors();
+ for (const QQmlError &error : errorList) {
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
<< error;
}
@@ -538,7 +606,8 @@ QUrl QQuickWidget::source() const
QQmlEngine* QQuickWidget::engine() const
{
Q_D(const QQuickWidget);
- return d->engine ? const_cast<QQmlEngine *>(d->engine.data()) : 0;
+ d->ensureEngine();
+ return const_cast<QQmlEngine *>(d->engine.data());
}
/*!
@@ -551,7 +620,8 @@ QQmlEngine* QQuickWidget::engine() const
QQmlContext* QQuickWidget::rootContext() const
{
Q_D(const QQuickWidget);
- return d->engine ? d->engine.data()->rootContext() : 0;
+ d->ensureEngine();
+ return d->engine.data()->rootContext();
}
/*!
@@ -596,7 +666,7 @@ QQmlContext* QQuickWidget::rootContext() const
QQuickWidget::Status QQuickWidget::status() const
{
Q_D(const QQuickWidget);
- if (!d->engine)
+ if (!d->engine && !d->source.isEmpty())
return QQuickWidget::Error;
if (!d->component)
@@ -622,11 +692,12 @@ QList<QQmlError> QQuickWidget::errors() const
if (d->component)
errs = d->component->errors();
- if (!d->engine) {
+ if (!d->engine && !d->source.isEmpty()) {
QQmlError error;
error.setDescription(QLatin1String("QQuickWidget: invalid qml engine."));
errs << error;
- } else if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
+ }
+ if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
QQmlError error;
error.setDescription(QLatin1String("QQuickWidget: invalid root object."));
errs << error;
@@ -694,9 +765,14 @@ void QQuickWidgetPrivate::updateSize()
q->resize(newSize);
}
} else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
- if (!qFuzzyCompare(q->width(), root->width()))
+ bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
+ bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
+
+ if (needToUpdateWidth && needToUpdateHeight)
+ root->setSize(QSizeF(q->width(), q->height()));
+ else if (needToUpdateWidth)
root->setWidth(q->width());
- if (!qFuzzyCompare(q->height(), root->height()))
+ else if (needToUpdateHeight)
root->setHeight(q->height());
}
}
@@ -759,9 +835,11 @@ void QQuickWidgetPrivate::handleContextCreationFailure(const QSurfaceFormat &for
// Never called by Software Rendering backend
void QQuickWidgetPrivate::createContext()
{
+#ifndef QT_NO_OPENGL
Q_Q(QQuickWidget);
- // On hide-show we invalidate() but our context is kept.
- // We nonetheless need to initialize() again.
+
+ // On hide-show we may invalidate() (when !isPersistentSceneGraph) but our
+ // context is kept. We may need to initialize() again, though.
const bool reinit = context && !offscreenWindow->openglContext();
if (!reinit) {
@@ -795,9 +873,11 @@ void QQuickWidgetPrivate::createContext()
offscreenSurface->create();
}
- if (context->makeCurrent(offscreenSurface))
- renderControl->initialize(context);
- else
+ if (context->makeCurrent(offscreenSurface)) {
+ if (!offscreenWindow->openglContext())
+ renderControl->initialize(context);
+ } else
+#endif
qWarning("QQuickWidget: Failed to make context current");
}
@@ -806,8 +886,10 @@ void QQuickWidgetPrivate::destroyContext()
{
delete offscreenSurface;
offscreenSurface = 0;
+#ifndef QT_NO_OPENGL
delete context;
context = 0;
+#endif
}
void QQuickWidget::createFramebufferObject()
@@ -819,6 +901,12 @@ void QQuickWidget::createFramebufferObject()
if (size().isEmpty())
return;
+ // Even though this is just an offscreen window we should set the position on it, as it might be
+ // useful for an item to know the actual position of the scene.
+ // Note: The position will be update when we get a move event (see: updatePosition()).
+ const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
+ d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
+
if (d->useSoftwareRenderer) {
const QSize imageSize = size() * devicePixelRatio();
d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
@@ -826,6 +914,7 @@ void QQuickWidget::createFramebufferObject()
return;
}
+#ifndef QT_NO_OPENGL
QOpenGLContext *context = d->offscreenWindow->openglContext();
if (!context) {
@@ -833,9 +922,10 @@ void QQuickWidget::createFramebufferObject()
return;
}
- if (context->shareContext() != QWidgetPrivate::get(window())->shareContext()) {
- context->setShareContext(QWidgetPrivate::get(window())->shareContext());
- context->setScreen(context->shareContext()->screen());
+ QOpenGLContext *shareWindowContext = QWidgetPrivate::get(window())->shareContext();
+ if (shareWindowContext && context->shareContext() != shareWindowContext) {
+ context->setShareContext(shareWindowContext);
+ context->setScreen(shareWindowContext->screen());
if (!context->create())
qWarning("QQuickWidget: Failed to recreate context");
// The screen may be different so we must recreate the offscreen surface too.
@@ -884,11 +974,6 @@ void QQuickWidget::createFramebufferObject()
}
#endif
- // Even though this is just an offscreen window we should set the position on it, as it might be
- // useful for an item to know the actual position of the scene.
- // Note: The position will be update when we get a move event (see: updatePosition()).
- const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
- d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
d->offscreenWindow->setRenderTarget(d->fbo);
if (samples > 0)
@@ -898,6 +983,7 @@ 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());
+#endif
}
void QQuickWidget::destroyFramebufferObject()
@@ -909,10 +995,12 @@ void QQuickWidget::destroyFramebufferObject()
return;
}
+#ifndef QT_NO_OPENGL
delete d->fbo;
d->fbo = 0;
delete d->resolvedFbo;
d->resolvedFbo = 0;
+#endif
}
QQuickWidget::ResizeMode QQuickWidget::resizeMode() const
@@ -930,8 +1018,8 @@ void QQuickWidget::continueExecute()
disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)), this, SLOT(continueExecute()));
if (d->component->isError()) {
- QList<QQmlError> errorList = d->component->errors();
- foreach (const QQmlError &error, errorList) {
+ const QList<QQmlError> errorList = d->component->errors();
+ for (const QQmlError &error : errorList) {
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
<< error;
}
@@ -942,8 +1030,8 @@ void QQuickWidget::continueExecute()
QObject *obj = d->component->create();
if (d->component->isError()) {
- QList<QQmlError> errorList = d->component->errors();
- foreach (const QQmlError &error, errorList) {
+ const QList<QQmlError> errorList = d->component->errors();
+ for (const QQmlError &error : errorList) {
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
<< error;
}
@@ -990,6 +1078,7 @@ void QQuickWidgetPrivate::setRootObject(QObject *obj)
}
}
+#ifndef QT_NO_OPENGL
GLuint QQuickWidgetPrivate::textureId() const
{
Q_Q(const QQuickWidget);
@@ -1001,6 +1090,7 @@ GLuint QQuickWidgetPrivate::textureId() const
return resolvedFbo ? resolvedFbo->texture()
: (fbo ? fbo->texture() : 0);
}
+#endif
/*!
\internal
@@ -1090,7 +1180,7 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
createFramebufferObject();
}
} else {
-
+#ifndef QT_NO_OPENGL
if (d->context) {
// Bail out when receiving a resize after scenegraph invalidation. This can happen
// during hide - resize - show sequences and also during application exit.
@@ -1112,7 +1202,7 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
qWarning("QQuickWidget::resizeEvent() no OpenGL context");
return;
}
-
+#endif
}
d->render(needsSync);
@@ -1180,15 +1270,20 @@ void QQuickWidget::showEvent(QShowEvent *)
d->createContext();
if (d->offscreenWindow->openglContext()) {
d->render(true);
- if (d->updatePending) {
+ // render() may have led to a QQuickWindow::update() call (for
+ // example, having a scene with a QQuickFramebufferObject::Renderer
+ // calling update() in its render()) which in turn results in
+ // renderRequested in the rendercontrol, ending up in
+ // triggerUpdate. In this case just calling update() is not
+ // acceptable, we need the full renderSceneGraph issued from
+ // timerEvent().
+ if (!d->eventPending && d->updatePending) {
d->updatePending = false;
update();
}
} else {
triggerUpdate();
}
- } else {
- triggerUpdate();
}
QWindowPrivate *offscreenPrivate = QWindowPrivate::get(d->offscreenWindow);
if (!offscreenPrivate->visible) {
@@ -1204,7 +1299,8 @@ void QQuickWidget::showEvent(QShowEvent *)
void QQuickWidget::hideEvent(QHideEvent *)
{
Q_D(QQuickWidget);
- d->invalidateRenderControl();
+ if (!d->offscreenWindow->isPersistentSceneGraph())
+ d->invalidateRenderControl();
QWindowPrivate *offscreenPrivate = QWindowPrivate::get(d->offscreenWindow);
if (offscreenPrivate->visible) {
offscreenPrivate->visible = false;
@@ -1305,7 +1401,24 @@ bool QQuickWidget::event(QEvent *e)
break;
case QEvent::ScreenChangeInternal:
- if (d->fbo || d->useSoftwareRenderer) {
+ if (QWindow *window = this->window()->windowHandle()) {
+ QScreen *newScreen = window->screen();
+
+ if (d->offscreenWindow)
+ d->offscreenWindow->setScreen(newScreen);
+ if (d->offscreenSurface)
+ d->offscreenSurface->setScreen(newScreen);
+#ifndef QT_NO_OPENGL
+ if (d->context)
+ d->context->setScreen(newScreen);
+#endif
+ }
+
+ if (d->useSoftwareRenderer
+#ifndef QT_NO_OPENGL
+ || d->fbo
+#endif
+ ) {
// This will check the size taking the devicePixelRatio into account
// and recreate if needed.
createFramebufferObject();
@@ -1490,7 +1603,8 @@ void QQuickWidget::paintEvent(QPaintEvent *event)
painter.drawImage(rect(), d->softwareImage);
} else {
//Paint only the updated areas
- for (auto targetRect : d->updateRegion.rects()) {
+ const auto rects = d->updateRegion.rects();
+ for (auto targetRect : rects) {
auto sourceRect = QRect(targetRect.topLeft() * devicePixelRatio(), targetRect.size() * devicePixelRatio());
painter.drawImage(targetRect, d->softwareImage, sourceRect);
}
diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
index 5c35093c58..3d64981797 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -87,7 +87,7 @@ public:
~QQuickWidgetPrivate();
void execute();
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) Q_DECL_OVERRIDE;
void initResize();
void updateSize();
void updatePosition();
@@ -101,10 +101,15 @@ public:
QObject *focusObject() Q_DECL_OVERRIDE;
+#ifndef QT_NO_OPENGL
GLuint textureId() const Q_DECL_OVERRIDE;
QImage grabFramebuffer() Q_DECL_OVERRIDE;
+#else
+ QImage grabFramebuffer();
+#endif
void init(QQmlEngine* e = 0);
+ void ensureEngine() const;
void handleWindowChange();
void invalidateRenderControl();
@@ -114,15 +119,18 @@ public:
QUrl source;
- QPointer<QQmlEngine> engine;
+ mutable QPointer<QQmlEngine> engine;
QQmlComponent *component;
QBasicTimer resizetimer;
QQuickWindow *offscreenWindow;
QOffscreenSurface *offscreenSurface;
QQuickRenderControl *renderControl;
+
+#ifndef QT_NO_OPENGL
QOpenGLFramebufferObject *fbo;
QOpenGLFramebufferObject *resolvedFbo;
QOpenGLContext *context;
+#endif
QQuickWidget::ResizeMode resizeMode;
QSize initialSize;
diff --git a/src/quickwidgets/quickwidgets.pro b/src/quickwidgets/quickwidgets.pro
index 87409e31c5..2438e577ae 100644
--- a/src/quickwidgets/quickwidgets.pro
+++ b/src/quickwidgets/quickwidgets.pro
@@ -2,7 +2,7 @@ TARGET = QtQuickWidgets
QT = core-private gui-private qml-private quick-private widgets-private
-DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
+DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES QT_NO_FOREACH
HEADERS += \
qquickwidget.h \
diff --git a/src/src.pro b/src/src.pro
index 04fa8663bb..11bc4de8e3 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,12 +1,14 @@
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += \
- qml \
- quick \
- qmltest
+ qml
-qtHaveModule(gui):contains(QT_CONFIG, opengl(es1|es2)?) {
- SUBDIRS += particles
+qtHaveModule(gui) {
+ SUBDIRS += \
+ quick \
+ qmltest
+
+ qtConfig(opengl(es1|es2)?): SUBDIRS += particles
qtHaveModule(widgets): SUBDIRS += quickwidgets
}
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index b72a43d742..556f5ddc7a 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -8,12 +8,15 @@ SUBDIRS=\
installed_cmake \
toolsupport
-qtHaveModule(gui):contains(QT_CONFIG, opengl(es1|es2)?) {
+qtHaveModule(gui):qtConfig(opengl(es1|es2)?) {
SUBDIRS += particles
qtHaveModule(widgets): SUBDIRS += quickwidgets
}
+# console applications not supported
+uikit: SUBDIRS -= qmltest
+
qmldevtools.CONFIG = host_build
installed_cmake.depends = cmake
diff --git a/tests/auto/particles/particles.pro b/tests/auto/particles/particles.pro
index 265a1eabc7..6ee1290dbb 100644
--- a/tests/auto/particles/particles.pro
+++ b/tests/auto/particles/particles.pro
@@ -25,6 +25,5 @@ PRIVATETESTS += \
qquickturbulence \
qquickwander
-contains(QT_CONFIG, private_tests) {
+qtConfig(private_tests): \
SUBDIRS += $$PRIVATETESTS
-}
diff --git a/tests/auto/particles/qquickage/tst_qquickage.cpp b/tests/auto/particles/qquickage/tst_qquickage.cpp
index 04c6fbd9e4..a233b30043 100644
--- a/tests/auto/particles/qquickage/tst_qquickage.cpp
+++ b/tests/auto/particles/qquickage/tst_qquickage.cpp
@@ -61,7 +61,7 @@ void tst_qquickage::test_kill()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -86,7 +86,7 @@ void tst_qquickage::test_jump()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -112,7 +112,7 @@ void tst_qquickage::test_onceOff()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -138,7 +138,7 @@ void tst_qquickage::test_sustained()
//TODO: Ensure some particles have lived to 0.4s point despite unified timer
//Can't verify size, because particles never die. It will constantly grow.
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp b/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp
index 4ff72f159d..b3fc01caa6 100644
--- a/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp
+++ b/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp
@@ -58,7 +58,7 @@ void tst_qquickangleddirection::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp b/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp
index 795fcaf42e..360b222367 100644
--- a/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp
+++ b/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp
@@ -57,7 +57,7 @@ void tst_qquickcumulativedirection::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp
index fb15af4dd1..ee05fb29c9 100644
--- a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp
+++ b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp
@@ -59,7 +59,7 @@ void tst_qquickcustomaffector::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
//in CI the whole simulation often happens at once, so dead particles end up missing out
@@ -92,7 +92,7 @@ void tst_qquickcustomaffector::test_move()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
if (!d->stillAlive(system))
diff --git a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp
index a722508a3e..60c6a37899 100644
--- a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp
+++ b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp
@@ -60,7 +60,7 @@ void tst_qquickcustomparticle::test_basic()
bool oneNonZero = false;
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp b/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp
index ac8e2bac49..a1fe5b225d 100644
--- a/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp
+++ b/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp
@@ -74,7 +74,7 @@ void tst_qquickellipseextruder::test_basic()
//Filled
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -91,7 +91,7 @@ void tst_qquickellipseextruder::test_basic()
//Just border
QCOMPARE(system->groupData[1]->size(), 500);
- foreach (QQuickParticleData *d, system->groupData[1]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp b/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp
index 70e0291330..ab682c591e 100644
--- a/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp
+++ b/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp
@@ -59,7 +59,7 @@ void tst_qquickfriction::test_basic()
//Default is just slowed a little
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -76,7 +76,7 @@ void tst_qquickfriction::test_basic()
//Nondefault comes to a complete stop within the first half of its life
QCOMPARE(system->groupData[1]->size(), 500);
- foreach (QQuickParticleData *d, system->groupData[1]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -103,7 +103,7 @@ void tst_qquickfriction::test_threshold()
//Velocity capped at 50, but it might take a frame or two to get there
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1.0f)
continue; //Particle data unused
if (myFuzzyGEQ(d->t, ((qreal)system->timeInt/1000.0) - 0.1))
diff --git a/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp b/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp
index 8ef075dc9b..34566b90eb 100644
--- a/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp
+++ b/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp
@@ -58,7 +58,7 @@ void tst_qquickgravity::test_basic()
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
float mag = 707.10678f;
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1 || !d->stillAlive(system))
continue; //Particle data unused or dead
diff --git a/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp b/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp
index fc270b991f..1228b4cc68 100644
--- a/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp
+++ b/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp
@@ -58,7 +58,7 @@ void tst_qquickgroupgoal::test_instantTransition()
ensureAnimTime(600, system->m_animation);
QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450);
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp b/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp
index cd684ec59b..7e07878d39 100644
--- a/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp
+++ b/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp
@@ -72,7 +72,7 @@ void tst_qquickimageparticle::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -116,7 +116,7 @@ void tst_qquickimageparticle::test_colored()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -160,7 +160,7 @@ void tst_qquickimageparticle::test_colorVariance()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -205,7 +205,7 @@ void tst_qquickimageparticle::test_deformed()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -249,7 +249,7 @@ void tst_qquickimageparticle::test_tabled()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -294,7 +294,7 @@ void tst_qquickimageparticle::test_sprite()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
index 98aac71e93..d9791cdb33 100644
--- a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
+++ b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
@@ -60,7 +60,7 @@ void tst_qquickitemparticle::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp b/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp
index 1f36874f0f..6baf8539d3 100644
--- a/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp
+++ b/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp
@@ -57,7 +57,7 @@ void tst_qquicklineextruder::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -73,7 +73,7 @@ void tst_qquicklineextruder::test_basic()
}
QCOMPARE(system->groupData[1]->size(), 500);
- foreach (QQuickParticleData *d, system->groupData[1]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp b/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp
index a3d0988019..d8481efc47 100644
--- a/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp
+++ b/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp
@@ -57,7 +57,7 @@ void tst_qquickmaskextruder::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp b/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp
index 8b7224623a..8791d19db6 100644
--- a/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp
+++ b/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp
@@ -58,7 +58,7 @@ void tst_qquickparticlegroup::test_instantTransition()
//A frame or two worth of particles will be missed, the transition doesn't take effect on the frame it's spawned (QTBUG-21781)
QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450);
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
index 4a3c5cdc74..5c82b946e5 100644
--- a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
+++ b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
@@ -58,7 +58,7 @@ void tst_qquickparticlesystem::test_basic()
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
int stillAlive = 0;
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp b/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp
index 99a8530d3a..c0d7d38512 100644
--- a/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp
+++ b/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp
@@ -57,7 +57,7 @@ void tst_qquickpointattractor::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp b/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp
index 0d150fb86d..5cc23e0306 100644
--- a/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp
+++ b/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp
@@ -57,7 +57,7 @@ void tst_qquickpointdirection::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp b/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp
index 24b30bf9ab..414e2d36f7 100644
--- a/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp
+++ b/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp
@@ -57,7 +57,7 @@ void tst_qquickrectangleextruder::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -76,7 +76,7 @@ void tst_qquickrectangleextruder::test_basic()
}
QCOMPARE(system->groupData[1]->size(), 500);
- foreach (QQuickParticleData *d, system->groupData[1]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp b/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp
index 8249159e43..ca5d9171f9 100644
--- a/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp
+++ b/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp
@@ -57,7 +57,7 @@ void tst_qquickspritegoal::test_instantTransition()
ensureAnimTime(600, system->m_animation);
QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450);
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp b/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp
index 8d9556fdac..2f45263c37 100644
--- a/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp
+++ b/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp
@@ -57,7 +57,7 @@ void tst_qquicktargetdirection::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp
index 99ecd7a06a..27d9bf01c9 100644
--- a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp
+++ b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp
@@ -57,7 +57,7 @@ void tst_qquicktrailemitter::test_basic()
ensureAnimTime(600, system->m_animation);
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -74,7 +74,7 @@ void tst_qquicktrailemitter::test_basic()
}
QVERIFY(extremelyFuzzyCompare(system->groupData[1]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[1]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp b/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp
index c8024470e4..74fafdc1d2 100644
--- a/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp
+++ b/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp
@@ -59,7 +59,7 @@ void tst_qquickturbulence::test_basic()
//Note that the noise image built-in provides the 'randomness', so this test should be stable so long as it and the size
//of the Turbulence item remain the same
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10));
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/particles/qquickwander/tst_qquickwander.cpp b/tests/auto/particles/qquickwander/tst_qquickwander.cpp
index 6e37fc648c..51ef7a272e 100644
--- a/tests/auto/particles/qquickwander/tst_qquickwander.cpp
+++ b/tests/auto/particles/qquickwander/tst_qquickwander.cpp
@@ -61,7 +61,7 @@ void tst_qquickwander::test_basic()
//the 500 was randomly changed from 0.0 in velocity
bool vxChanged = false;
bool vyChanged = false;
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro
index ccb2d71c53..a50411e18b 100644
--- a/tests/auto/qml/debugger/debugger.pro
+++ b/tests/auto/qml/debugger/debugger.pro
@@ -20,6 +20,6 @@ PRIVATETESTS += \
SUBDIRS += $$PUBLICTESTS
-contains(QT_CONFIG, private_tests) {
+qtConfig(private_tests): \
SUBDIRS += $$PRIVATETESTS
-}
+
diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
index 4568d25dc1..40e19d375d 100644
--- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
@@ -1223,16 +1223,15 @@ void tst_QQmlEngineDebugService::queryObjectTree()
int main(int argc, char *argv[])
{
int _argc = argc + 1;
- char **_argv = new char*[_argc];
+ QScopedArrayPointer<char *>_argv(new char*[_argc]);
for (int i = 0; i < argc; ++i)
_argv[i] = argv[i];
char arg[] = "-qmljsdebugger=port:3768,services:QmlDebugger";
_argv[_argc - 1] = arg;
- QGuiApplication app(_argc, _argv);
+ QGuiApplication app(_argc, _argv.data());
tst_QQmlEngineDebugService tc;
- return QTest::qExec(&tc, _argc, _argv);
- delete _argv;
+ return QTest::qExec(&tc, _argc, _argv.data());
}
#include "tst_qqmlenginedebugservice.moc"
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index c1de5ff594..c4b17aa60a 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -64,7 +64,8 @@ class QQmlProfilerTestClient : public QQmlProfilerClient
Q_OBJECT
public:
- QQmlProfilerTestClient(QQmlDebugConnection *connection) : QQmlProfilerClient(connection) {}
+ QQmlProfilerTestClient(QQmlDebugConnection *connection) : QQmlProfilerClient(connection),
+ lastTimestamp(-1) {}
QVector<QQmlProfilerData> qmlMessages;
QVector<QQmlProfilerData> javascriptMessages;
@@ -72,6 +73,8 @@ public:
QVector<QQmlProfilerData> asynchronousMessages;
QVector<QQmlProfilerData> pixmapMessages;
+ qint64 lastTimestamp;
+
signals:
void recordingFinished();
@@ -114,6 +117,8 @@ void QQmlProfilerTestClient::traceFinished(qint64 time, int engineId)
void QQmlProfilerTestClient::rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime)
{
QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType);
+ QVERIFY(lastTimestamp <= startTime);
+ lastTimestamp = startTime;
QQmlProfilerData data(startTime, QQmlProfilerDefinitions::RangeStart, type);
if (type == QQmlProfilerDefinitions::Javascript)
javascriptMessages.append(data);
@@ -125,6 +130,8 @@ void QQmlProfilerTestClient::rangeData(QQmlProfilerDefinitions::RangeType type,
const QString &string)
{
QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType);
+ QVERIFY(lastTimestamp <= time);
+ lastTimestamp = time;
QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeData, type, string);
if (type == QQmlProfilerDefinitions::Javascript)
javascriptMessages.append(data);
@@ -137,6 +144,8 @@ void QQmlProfilerTestClient::rangeLocation(QQmlProfilerDefinitions::RangeType ty
{
QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType);
QVERIFY(location.line >= -2);
+ QVERIFY(lastTimestamp <= time);
+ lastTimestamp = time;
QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeLocation, type, location.filename);
data.line = location.line;
data.column = location.column;
@@ -149,6 +158,8 @@ void QQmlProfilerTestClient::rangeLocation(QQmlProfilerDefinitions::RangeType ty
void QQmlProfilerTestClient::rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime)
{
QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType);
+ QVERIFY(lastTimestamp <= endTime);
+ lastTimestamp = endTime;
QQmlProfilerData data(endTime, QQmlProfilerDefinitions::RangeEnd, type);
if (type == QQmlProfilerDefinitions::Javascript)
javascriptMessages.append(data);
@@ -161,6 +172,8 @@ void QQmlProfilerTestClient::animationFrame(qint64 time, int frameRate, int anim
QVERIFY(threadId >= 0);
QVERIFY(frameRate != -1);
QVERIFY(animationCount != -1);
+ QVERIFY(lastTimestamp <= time);
+ lastTimestamp = time;
QQmlProfilerData data(time, QQmlProfilerDefinitions::Event,
QQmlProfilerDefinitions::AnimationFrame);
data.framerate = frameRate;
@@ -178,6 +191,8 @@ void QQmlProfilerTestClient::sceneGraphEvent(QQmlProfilerDefinitions::SceneGraph
Q_UNUSED(numericData3);
Q_UNUSED(numericData4);
Q_UNUSED(numericData5);
+ QVERIFY(lastTimestamp <= time);
+ lastTimestamp = time;
asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::SceneGraphFrame,
type));
}
@@ -186,6 +201,8 @@ void QQmlProfilerTestClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEve
qint64 time, const QString &url, int numericData1,
int numericData2)
{
+ QVERIFY(lastTimestamp <= time);
+ lastTimestamp = time;
QQmlProfilerData data(time, QQmlProfilerDefinitions::PixmapCacheEvent, type, url);
switch (type) {
case QQmlProfilerDefinitions::PixmapSizeKnown:
@@ -205,6 +222,8 @@ void QQmlProfilerTestClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEve
void QQmlProfilerTestClient::memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time,
qint64 amount)
{
+ QVERIFY(lastTimestamp <= time);
+ lastTimestamp = time;
QQmlProfilerData data(time, QQmlProfilerDefinitions::MemoryAllocation, type);
data.amount = amount;
jsHeapMessages.append(data);
@@ -213,6 +232,8 @@ void QQmlProfilerTestClient::memoryAllocation(QQmlProfilerDefinitions::MemoryTyp
void QQmlProfilerTestClient::inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time,
int a, int b)
{
+ QVERIFY(lastTimestamp <= time);
+ lastTimestamp = time;
qmlMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event, type,
QString::number(a) + QLatin1Char('x') +
QString::number(b)));
@@ -588,12 +609,11 @@ void tst_QQmlProfilerService::scenegraphData()
checkTraceReceived();
checkJsHeap();
-
- // check that at least one frame was rendered
- // there should be a SGPolishAndSync + SGRendererFrame + SGRenderLoopFrame sequence
- // (though we can't be sure to get the SGRenderLoopFrame in the threaded renderer)
+ // Check that at least one frame was rendered.
+ // There should be a SGContextFrame + SGRendererFrame + SGRenderLoopFrame sequence,
+ // but we can't be sure to get the SGRenderLoopFrame in the threaded renderer.
//
- // since the rendering happens in a different thread, there could be other unrelated events
+ // Since the rendering happens in a different thread, there could be other unrelated events
// interleaved. Also, events could carry the same time stamps and be sorted in an unexpected way
// if the clocks are acting up.
qint64 contextFrameTime = -1;
@@ -622,8 +642,13 @@ void tst_QQmlProfilerService::scenegraphData()
foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) {
if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRenderLoopFrame) {
- QVERIFY(msg.time >= renderFrameTime);
- break;
+ if (msg.time >= contextFrameTime) {
+ // Make sure SceneGraphRenderLoopFrame is not between SceneGraphContextFrame and
+ // SceneGraphRendererFrame. A SceneGraphRenderLoopFrame before everything else is
+ // OK as the scene graph might decide to do an initial rendering.
+ QVERIFY(msg.time >= renderFrameTime);
+ break;
+ }
}
}
}
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index 3f89913f3b..a23b7e37eb 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -326,7 +326,7 @@ private slots:
private:
QV4Debugger *debugger() const
{
- return static_cast<QV4Debugger *>(m_v4->debugger);
+ return static_cast<QV4Debugger *>(m_v4->debugger());
}
void evaluateJavaScript(const QString &script, const QString &fileName, int lineNumber = 1)
{
@@ -444,7 +444,7 @@ void tst_qv4debugger::addBreakPointWhilePaused()
static QV4::ReturnedValue someCall(QV4::CallContext *ctx)
{
- static_cast<QV4Debugger *>(ctx->d()->engine->debugger)
+ static_cast<QV4Debugger *>(ctx->d()->engine->debugger())
->removeBreakPoint("removeBreakPointForNextInstruction", 2);
return QV4::Encode::undefined();
}
diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h
index 6fe5d897e0..1ec0a6513d 100644
--- a/tests/auto/qml/debugger/shared/debugutil_p.h
+++ b/tests/auto/qml/debugger/shared/debugutil_p.h
@@ -135,8 +135,6 @@ public:
int lastResponseId;
bool lastResult;
-public slots:
-
void recordResponse(int requestId, bool result)
{
lastResponseId = requestId;
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 99c18f91a1..f4eb17f1ca 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -73,6 +73,7 @@ private slots:
void newQObject();
void newQObject_ownership();
void newQObject_deletedEngine();
+ void newQMetaObject();
void exceptionInSlot();
void globalObjectProperties();
void globalObjectEquals();
@@ -188,6 +189,8 @@ private slots:
void v4FunctionWithoutQML();
+ void withNoContext();
+
signals:
void testSignal();
};
@@ -712,6 +715,104 @@ void tst_QJSEngine::newQObject_deletedEngine()
QTRY_VERIFY(spy.count());
}
+class TestQMetaObject : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(int called READ called)
+public:
+ enum Enum1 {
+ Zero = 0,
+ One,
+ Two
+ };
+ enum Enum2 {
+ A = 0,
+ B,
+ C
+ };
+ Q_ENUMS(Enum1 Enum2)
+
+ Q_INVOKABLE TestQMetaObject()
+ : m_called(1) {
+ }
+ Q_INVOKABLE TestQMetaObject(int)
+ : m_called(2) {
+ }
+ Q_INVOKABLE TestQMetaObject(QString)
+ : m_called(3) {
+ }
+ Q_INVOKABLE TestQMetaObject(QString, int)
+ : m_called(4) {
+ }
+ int called() const {
+ return m_called;
+ }
+private:
+ int m_called;
+};
+
+void tst_QJSEngine::newQMetaObject() {
+ {
+ QJSEngine engine;
+ QJSValue metaObject = engine.newQMetaObject(&TestQMetaObject::staticMetaObject);
+ QCOMPARE(metaObject.isNull(), false);
+ QCOMPARE(metaObject.isObject(), true);
+ QCOMPARE(metaObject.isQObject(), false);
+ QCOMPARE(metaObject.isCallable(), true);
+ QCOMPARE(metaObject.isQMetaObject(), true);
+
+ QCOMPARE(metaObject.toQMetaObject(), &TestQMetaObject::staticMetaObject);
+
+ QVERIFY(metaObject.strictlyEquals(engine.newQMetaObject<TestQMetaObject>()));
+
+
+ {
+ auto result = metaObject.callAsConstructor();
+ if (result.isError())
+ qDebug() << result.toString();
+ QCOMPARE(result.isError(), false);
+ QCOMPARE(result.isNull(), false);
+ QCOMPARE(result.isObject(), true);
+ QCOMPARE(result.isQObject(), true);
+ QVERIFY(result.property("constructor").strictlyEquals(metaObject));
+ QVERIFY(result.prototype().strictlyEquals(metaObject));
+
+
+ QCOMPARE(result.property("called").toInt(), 1);
+
+ }
+
+ QJSValue integer(42);
+ QJSValue string("foo");
+
+ {
+ auto result = metaObject.callAsConstructor({integer});
+ QCOMPARE(result.property("called").toInt(), 2);
+ }
+
+ {
+ auto result = metaObject.callAsConstructor({string});
+ QCOMPARE(result.property("called").toInt(), 3);
+ }
+
+ {
+ auto result = metaObject.callAsConstructor({string, integer});
+ QCOMPARE(result.property("called").toInt(), 4);
+ }
+ }
+
+ {
+ QJSEngine engine;
+ QJSValue metaObject = engine.newQMetaObject(&TestQMetaObject::staticMetaObject);
+ QCOMPARE(metaObject.property("Zero").toInt(), 0);
+ QCOMPARE(metaObject.property("One").toInt(), 1);
+ QCOMPARE(metaObject.property("Two").toInt(), 2);
+ QCOMPARE(metaObject.property("A").toInt(), 0);
+ QCOMPARE(metaObject.property("B").toInt(), 1);
+ QCOMPARE(metaObject.property("C").toInt(), 2);
+ }
+
+}
+
void tst_QJSEngine::exceptionInSlot()
{
QJSEngine engine;
@@ -1343,6 +1444,7 @@ void tst_QJSEngine::valueConversion_QVariant()
QCOMPARE(qjsvalue_cast<QVariant>(QJSValue(123)), QVariant(123));
QVERIFY(eng.toScriptValue(QVariant(QMetaType::VoidStar, 0)).isNull());
+ QVERIFY(eng.toScriptValue(QVariant::fromValue(nullptr)).isNull());
{
QVariantMap map;
@@ -2040,18 +2142,42 @@ void tst_QJSEngine::jsNumberClass()
QJSValue ret = eng.evaluate("new Number(123).toExponential()");
QVERIFY(ret.isString());
QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2"));
+ ret = eng.evaluate("new Number(123).toExponential(1)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("1.2e+2"));
+ ret = eng.evaluate("new Number(123).toExponential(2)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2"));
+ ret = eng.evaluate("new Number(123).toExponential(3)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("1.230e+2"));
}
QVERIFY(proto.property("toFixed").isCallable());
{
QJSValue ret = eng.evaluate("new Number(123).toFixed()");
QVERIFY(ret.isString());
QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ ret = eng.evaluate("new Number(123).toFixed(1)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123.0"));
+ ret = eng.evaluate("new Number(123).toFixed(2)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123.00"));
}
QVERIFY(proto.property("toPrecision").isCallable());
{
QJSValue ret = eng.evaluate("new Number(123).toPrecision()");
QVERIFY(ret.isString());
QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ ret = eng.evaluate("new Number(42).toPrecision(1)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("4e+1"));
+ ret = eng.evaluate("new Number(42).toPrecision(2)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("42"));
+ ret = eng.evaluate("new Number(42).toPrecision(3)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("42.0"));
}
}
@@ -3886,6 +4012,13 @@ void tst_QJSEngine::v4FunctionWithoutQML()
QVERIFY(obj.called);
}
+void tst_QJSEngine::withNoContext()
+{
+ // Don't crash (QTBUG-53794)
+ QJSEngine engine;
+ engine.evaluate("with (noContext) true");
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index 859caf72c7..d28bbc1ffa 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -431,6 +431,12 @@ void tst_QJSValue::toString()
QVERIFY(!o.engine());
QCOMPARE(o.toString(), QStringLiteral("1,2,3"));
}
+
+ {
+ QByteArray hello = QByteArrayLiteral("Hello World");
+ QJSValue jsValue = eng.toScriptValue(hello);
+ QCOMPARE(jsValue.toString(), QString::fromUtf8(hello));
+ }
}
void tst_QJSValue::toNumber()
@@ -978,8 +984,8 @@ void tst_QJSValue::toVariant()
QCOMPARE(qjsvalue_cast<QVariant>(undefined), QVariant());
QJSValue null = eng.evaluate("null");
- QCOMPARE(null.toVariant(), QVariant(QMetaType::VoidStar, 0));
- QCOMPARE(qjsvalue_cast<QVariant>(null), QVariant(QMetaType::VoidStar, 0));
+ QCOMPARE(null.toVariant(), QVariant::fromValue(nullptr));
+ QCOMPARE(qjsvalue_cast<QVariant>(null), QVariant::fromValue(nullptr));
{
QJSValue number = eng.toScriptValue(123.0);
@@ -1055,8 +1061,8 @@ void tst_QJSValue::toVariant()
QCOMPARE(qjsvalue_cast<QVariant>(undef), QVariant());
QJSValue nil = QJSValue(QJSValue::NullValue);
- QCOMPARE(nil.toVariant(), QVariant(QMetaType::VoidStar, 0));
- QCOMPARE(qjsvalue_cast<QVariant>(nil), QVariant(QMetaType::VoidStar, 0));
+ QCOMPARE(nil.toVariant(), QVariant::fromValue(nullptr));
+ QCOMPARE(qjsvalue_cast<QVariant>(nil), QVariant::fromValue(nullptr));
}
// array
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 28f04be5d7..68a2eace19 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -8,7 +8,6 @@ PUBLICTESTS += \
qjsvalueiterator \
qjsonbinding \
qmlmin \
- qmlplugindump \
qqmlcomponent \
qqmlconsole \
qqmlengine \
@@ -61,7 +60,9 @@ PRIVATETESTS += \
v4misc \
qqmltranslation \
qqmlimport \
- qqmlobjectmodel
+ qqmlobjectmodel \
+ qmldiskcache \
+ qv4mm
qtHaveModule(widgets) {
PUBLICTESTS += \
@@ -72,14 +73,13 @@ qtHaveModule(widgets) {
SUBDIRS += $$PUBLICTESTS \
qqmlextensionplugin
SUBDIRS += $$METATYPETESTS
-!winrt { # no QProcess on winrt
+!uikit:!winrt { # no QProcess on uikit/winrt
!contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger
- SUBDIRS += qmllint
+ SUBDIRS += qmllint qmlplugindump
}
-contains(QT_CONFIG, private_tests) {
+qtConfig(private_tests): \
SUBDIRS += $$PRIVATETESTS
-}
qtNomakeTools( \
qmlplugindump \
diff --git a/tests/auto/qml/qmldiskcache/qmldiskcache.pro b/tests/auto/qml/qmldiskcache/qmldiskcache.pro
new file mode 100644
index 0000000000..f98a157b6a
--- /dev/null
+++ b/tests/auto/qml/qmldiskcache/qmldiskcache.pro
@@ -0,0 +1,9 @@
+CONFIG += testcase
+TARGET = tst_qmldiskcache
+osx:CONFIG -= app_bundle
+
+SOURCES += tst_qmldiskcache.cpp
+
+RESOURCES += test.qml
+
+QT += core-private qml-private testlib
diff --git a/tests/auto/qml/qmldiskcache/test.qml b/tests/auto/qml/qmldiskcache/test.qml
new file mode 100644
index 0000000000..d632422616
--- /dev/null
+++ b/tests/auto/qml/qmldiskcache/test.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property int value: 20
+}
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
new file mode 100644
index 0000000000..8ccf4714ba
--- /dev/null
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -0,0 +1,562 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+
+#include <private/qv4compileddata_p.h>
+#include <private/qv4compiler_p.h>
+#include <private/qv4jsir_p.h>
+#include <private/qv4isel_p.h>
+#include <private/qv8engine_p.h>
+#include <private/qv4engine_p.h>
+#include <QQmlComponent>
+#include <QQmlEngine>
+#include <QQmlFileSelector>
+#include <QThread>
+#include <QCryptographicHash>
+#include <QStandardPaths>
+#include <QDirIterator>
+
+class tst_qmldiskcache: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void regenerateAfterChange();
+ void registerImportForImplicitComponent();
+ void basicVersionChecks();
+ void recompileAfterChange();
+ void fileSelectors();
+ void localAliases();
+ void cacheResources();
+};
+
+// A wrapper around QQmlComponent to ensure the temporary reference counts
+// on the type data as a result of the main thread <> loader thread communication
+// are dropped. Regular Synchronous loading will leave us with an event posted
+// to the gui thread and an extra refcount that will only be dropped after the
+// event delivery. A plain sendPostedEvents() however is insufficient because
+// we can't be sure that the event is posted after the constructor finished.
+class CleanlyLoadingComponent : public QQmlComponent
+{
+public:
+ CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url)
+ : QQmlComponent(engine, url, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+ CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName)
+ : QQmlComponent(engine, fileName, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+
+ void waitForLoad()
+ {
+ QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error);
+ }
+};
+
+static void waitForFileSystem()
+{
+ // On macOS with HFS+ the precision of file times is measured in seconds, so to ensure that
+ // the newly written file has a modification date newer than an existing cache file, we must
+ // wait.
+ // Similar effects of lacking precision have been observed on some Linux systems.
+ QThread::sleep(1);
+}
+
+struct TestCompiler
+{
+ TestCompiler(QQmlEngine *engine)
+ : engine(engine)
+ , tempDir()
+ , testFilePath(tempDir.path() + QStringLiteral("/test.qml"))
+ , cacheFilePath(tempDir.path() + QStringLiteral("/test.qmlc"))
+ , mappedFile(cacheFilePath)
+ , currentMapping(nullptr)
+ {
+ }
+
+ bool compile(const QByteArray &contents)
+ {
+ closeMapping();
+ engine->clearComponentCache();
+
+ waitForFileSystem();
+
+ {
+ QFile f(testFilePath);
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ lastErrorString = f.errorString();
+ return false;
+ }
+ if (f.write(contents) != contents.size()) {
+ lastErrorString = f.errorString();
+ return false;
+ }
+ }
+
+ CleanlyLoadingComponent component(engine, testFilePath);
+ if (!component.isReady()) {
+ lastErrorString = component.errorString();
+ return false;
+ }
+
+ return true;
+ }
+
+ const QV4::CompiledData::Unit *mapUnit()
+ {
+ if (!mappedFile.open(QIODevice::ReadOnly)) {
+ lastErrorString = mappedFile.errorString();
+ return nullptr;
+ }
+
+ currentMapping = mappedFile.map(/*offset*/0, mappedFile.size());
+ if (!currentMapping) {
+ lastErrorString = mappedFile.errorString();
+ return nullptr;
+ }
+ QV4::CompiledData::Unit *unitPtr;
+ memcpy(&unitPtr, &currentMapping, sizeof(unitPtr));
+ return unitPtr;
+ }
+
+ typedef void (*HeaderTweakFunction)(QV4::CompiledData::Unit *header);
+ bool tweakHeader(HeaderTweakFunction function)
+ {
+ closeMapping();
+
+ QFile f(cacheFilePath);
+ if (!f.open(QIODevice::ReadWrite))
+ return false;
+ QV4::CompiledData::Unit header;
+ if (f.read(reinterpret_cast<char *>(&header), sizeof(header)) != sizeof(header))
+ return false;
+ function(&header);
+ f.seek(0);
+ return f.write(reinterpret_cast<const char *>(&header), sizeof(header)) == sizeof(header);
+ }
+
+ bool verify()
+ {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
+ return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), v4->iselFactory.data(), &lastErrorString);
+ }
+
+ void closeMapping()
+ {
+ if (currentMapping) {
+ mappedFile.unmap(currentMapping);
+ currentMapping = nullptr;
+ }
+ mappedFile.close();
+ }
+
+ void clearCache()
+ {
+ closeMapping();
+ QFile::remove(cacheFilePath);
+ }
+
+ QQmlEngine *engine;
+ const QTemporaryDir tempDir;
+ const QString testFilePath;
+ const QString cacheFilePath;
+ QString lastErrorString;
+ QFile mappedFile;
+ uchar *currentMapping;
+};
+
+void tst_qmldiskcache::initTestCase()
+{
+ qputenv("QML_FORCE_DISK_CACHE", "1");
+}
+
+void tst_qmldiskcache::regenerateAfterChange()
+{
+ QQmlEngine engine;
+ TestCompiler testCompiler(&engine);
+
+ QVERIFY(testCompiler.tempDir.isValid());
+
+ const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n"
+ "QtObject {\n"
+ " property string blah: Qt.platform;\n"
+ "}");
+
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+
+ {
+ const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit();
+ QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString));
+
+ QCOMPARE(quint32(testUnit->nObjects), quint32(1));
+
+ const QV4::CompiledData::Object *obj = testUnit->objectAt(0);
+ QCOMPARE(quint32(obj->nBindings), quint32(1));
+ QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Script));
+ QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(1));
+
+ QCOMPARE(quint32(testUnit->functionTableSize), quint32(2));
+
+ const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1);
+ QVERIFY(bindingFunction->codeOffset > testUnit->unitSize);
+ }
+
+ {
+ const QByteArray newContents = QByteArrayLiteral("import QtQml 2.0\n"
+ "QtObject {\n"
+ " property string blah: Qt.platform;\n"
+ " property int secondProperty: 42;\n"
+ "}");
+
+ QVERIFY2(testCompiler.compile(newContents), qPrintable(testCompiler.lastErrorString));
+ const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit();
+ QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString));
+
+ QCOMPARE(quint32(testUnit->nObjects), quint32(1));
+
+ const QV4::CompiledData::Object *obj = testUnit->objectAt(0);
+ QCOMPARE(quint32(obj->nBindings), quint32(2));
+ QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number));
+ QCOMPARE(obj->bindingTable()->valueAsNumber(), double(42));
+
+ QCOMPARE(quint32(testUnit->functionTableSize), quint32(2));
+
+ const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1);
+ QVERIFY(bindingFunction->codeOffset > testUnit->unitSize);
+ }
+}
+
+void tst_qmldiskcache::registerImportForImplicitComponent()
+{
+ QQmlEngine engine;
+
+ TestCompiler testCompiler(&engine);
+ QVERIFY(testCompiler.tempDir.isValid());
+
+ const QByteArray contents = QByteArrayLiteral("import QtQuick 2.0\n"
+ "Loader {\n"
+ " sourceComponent: Item {}\n"
+ "}");
+
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+ {
+ const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit();
+ QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString));
+
+ QCOMPARE(quint32(testUnit->nImports), quint32(2));
+ QCOMPARE(testUnit->stringAt(testUnit->importAt(0)->uriIndex), QStringLiteral("QtQuick"));
+
+ QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
+
+ QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->uriIndex), QString(componentType->module()));
+ QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->qualifierIndex), QStringLiteral("QmlInternals"));
+
+ QCOMPARE(quint32(testUnit->nObjects), quint32(3));
+
+ const QV4::CompiledData::Object *obj = testUnit->objectAt(0);
+ QCOMPARE(quint32(obj->nBindings), quint32(1));
+ QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Object));
+
+ const QV4::CompiledData::Object *implicitComponent = testUnit->objectAt(obj->bindingTable()->value.objectIndex);
+ QCOMPARE(testUnit->stringAt(implicitComponent->inheritedTypeNameIndex), QStringLiteral("QmlInternals.") + componentType->elementName());
+ }
+}
+
+void tst_qmldiskcache::basicVersionChecks()
+{
+ QQmlEngine engine;
+
+ TestCompiler testCompiler(&engine);
+ QVERIFY(testCompiler.tempDir.isValid());
+
+ const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n"
+ "QtObject {\n"
+ " property string blah: Qt.platform;\n"
+ "}");
+
+ {
+ testCompiler.clearCache();
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+ QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString));
+ }
+
+ {
+ testCompiler.clearCache();
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+
+ testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) {
+ header->qtVersion = 0;
+ });
+
+ QVERIFY(!testCompiler.verify());
+ QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Qt version mismatch. Found 0 expected %1").arg(QT_VERSION, 0, 16));
+ testCompiler.clearCache();
+ }
+
+ {
+ testCompiler.clearCache();
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+
+ testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) {
+ header->version = 0;
+ });
+
+ QVERIFY(!testCompiler.verify());
+ QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("V4 data structure version mismatch. Found 0 expected %1").arg(QV4_DATA_STRUCTURE_VERSION, 0, 16));
+ }
+
+ {
+ testCompiler.clearCache();
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+
+ testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) {
+ header->architectureIndex = 0;
+ });
+
+ QVERIFY(!testCompiler.verify());
+ QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Architecture mismatch. Found expected %1").arg(QSysInfo::buildAbi()));
+ }
+
+ {
+ testCompiler.clearCache();
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+
+ testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) {
+ header->codeGeneratorIndex = 0;
+ });
+
+ QVERIFY(!testCompiler.verify());
+ QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Code generator mismatch. Found code generated by but expected %1").arg(QV8Engine::getV4(&engine)->iselFactory->codeGeneratorName));
+ }
+}
+
+class TypeVersion1 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged);
+public:
+
+
+ int m_value = 0;
+ int value() const { return m_value; }
+ void setValue(int v) { m_value = v; emit valueChanged(); }
+
+signals:
+ void valueChanged();
+};
+
+// Same as TypeVersion1 except the property type changed!
+class TypeVersion2 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged);
+public:
+
+
+ QString m_value;
+ QString value() const { return m_value; }
+ void setValue(QString v) { m_value = v; emit valueChanged(); }
+
+signals:
+ void valueChanged();
+};
+
+void tst_qmldiskcache::recompileAfterChange()
+{
+ QQmlEngine engine;
+
+ TestCompiler testCompiler(&engine);
+ QVERIFY(testCompiler.tempDir.isValid());
+
+ const QByteArray contents = QByteArrayLiteral("import TypeTest 1.0\n"
+ "TypeThatWillChange {\n"
+ "}");
+
+ qmlRegisterType<TypeVersion1>("TypeTest", 1, 0, "TypeThatWillChange");
+
+ {
+ testCompiler.clearCache();
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+ QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString));
+ }
+
+ QDateTime initialCacheTimeStamp = QFileInfo(testCompiler.cacheFilePath).lastModified();
+
+ {
+ CleanlyLoadingComponent component(&engine, testCompiler.testFilePath);
+ QScopedPointer<TypeVersion1> obj(qobject_cast<TypeVersion1*>(component.create()));
+ QVERIFY(!obj.isNull());
+ QCOMPARE(QFileInfo(testCompiler.cacheFilePath).lastModified(), initialCacheTimeStamp);
+ }
+
+ engine.clearComponentCache();
+
+ {
+ CleanlyLoadingComponent component(&engine, testCompiler.testFilePath);
+ QScopedPointer<TypeVersion1> obj(qobject_cast<TypeVersion1*>(component.create()));
+ QVERIFY(!obj.isNull());
+ QCOMPARE(QFileInfo(testCompiler.cacheFilePath).lastModified(), initialCacheTimeStamp);
+ }
+
+ engine.clearComponentCache();
+ qmlClearTypeRegistrations();
+ qmlRegisterType<TypeVersion2>("TypeTest", 1, 0, "TypeThatWillChange");
+
+ waitForFileSystem();
+
+ {
+ CleanlyLoadingComponent component(&engine, testCompiler.testFilePath);
+ QScopedPointer<TypeVersion2> obj(qobject_cast<TypeVersion2*>(component.create()));
+ QVERIFY(!obj.isNull());
+ QVERIFY(QFileInfo(testCompiler.cacheFilePath).lastModified() > initialCacheTimeStamp);
+ }
+}
+
+void tst_qmldiskcache::fileSelectors()
+{
+ QQmlEngine engine;
+
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const QString testFilePath = tempDir.path() + "/test.qml";
+ {
+ QFile f(testFilePath);
+ QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString()));
+ f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 42 }"));
+ }
+
+ const QString selector = QStringLiteral("testSelector");
+ const QString selectorPath = tempDir.path() + "/+" + selector;
+ const QString selectedTestFilePath = selectorPath + "/test.qml";
+ {
+ QVERIFY(QDir::root().mkpath(selectorPath));
+ QFile f(selectorPath + "/test.qml");
+ QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString()));
+ f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 100 }"));
+ }
+
+ {
+ QQmlComponent component(&engine, testFilePath);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 42);
+
+ QFile cacheFile(testFilePath + "c");
+ QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName()));
+ }
+
+ QQmlFileSelector qmlSelector(&engine);
+ qmlSelector.setExtraSelectors(QStringList() << selector);
+
+ engine.clearComponentCache();
+
+ {
+ QQmlComponent component(&engine, testFilePath);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 100);
+
+ QFile cacheFile(selectedTestFilePath + "c");
+ QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName()));
+ }
+}
+
+void tst_qmldiskcache::localAliases()
+{
+ QQmlEngine engine;
+
+ TestCompiler testCompiler(&engine);
+ QVERIFY(testCompiler.tempDir.isValid());
+
+ const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n"
+ "QtObject {\n"
+ " id: root\n"
+ " property int prop: 100\n"
+ " property alias dummy1: root.prop\n"
+ " property alias dummy2: root.prop\n"
+ " property alias dummy3: root.prop\n"
+ " property alias dummy4: root.prop\n"
+ " property alias dummy5: root.prop\n"
+ " property alias foo: root.prop\n"
+ " property alias bar: root.foo\n"
+ "}");
+
+ {
+ testCompiler.clearCache();
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+ QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString));
+ }
+
+ {
+ CleanlyLoadingComponent component(&engine, testCompiler.testFilePath);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("bar").toInt(), 100);
+ }
+
+ engine.clearComponentCache();
+
+ {
+ CleanlyLoadingComponent component(&engine, testCompiler.testFilePath);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("bar").toInt(), 100);
+ }
+}
+
+void tst_qmldiskcache::cacheResources()
+{
+ const QString cacheDirectory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+ QVERIFY(QDir::root().mkpath(cacheDirectory));
+
+ const QString qmlCacheDirectory = cacheDirectory + QLatin1String("/qmlcache/");
+ QVERIFY(QDir(qmlCacheDirectory).removeRecursively());
+ QVERIFY(QDir::root().mkpath(qmlCacheDirectory));
+ QVERIFY(QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot).isEmpty());
+
+
+ QQmlEngine engine;
+
+ {
+ CleanlyLoadingComponent component(&engine, QUrl("qrc:/test.qml"));
+ qDebug() << component.errorString();
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 20);
+ }
+
+ QCOMPARE(QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot | QDir::Files).count(), 1);
+}
+
+QTEST_MAIN(tst_qmldiskcache)
+
+#include "tst_qmldiskcache.moc"
diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml
new file mode 100644
index 0000000000..d19b6ecc41
--- /dev/null
+++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Pelagicore AG
+** 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$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+
+Item {
+ id:root
+
+ LoggingCategory {
+ id: testCategory
+ name: "qt.test"
+ }
+
+ LoggingCategory {
+ id: emptyCategory
+ }
+
+ Component.onCompleted: {
+ console.debug(testCategory, "console.debug");
+ console.log(testCategory, "console.log");
+ console.info(testCategory, "console.info");
+ console.warn(testCategory, "console.warn");
+ console.error(testCategory, "console.error");
+
+ testCategory.name = "qt.test2";
+
+ console.error(emptyCategory, "console.error");
+ }
+}
diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
index f12656c5fe..f832143935 100644
--- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
+++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
@@ -40,6 +40,7 @@ public:
private slots:
void logging();
+ void categorized_logging();
void tracing();
void profiling();
void testAssert();
@@ -87,6 +88,41 @@ void tst_qqmlconsole::logging()
delete object;
}
+void tst_qqmlconsole::categorized_logging()
+{
+ QUrl testUrl = testFileUrl("categorized_logging.qml");
+ QQmlTestMessageHandler messageHandler;
+ messageHandler.setIncludeCategoriesEnabled(true);
+
+ QLoggingCategory testCategory("qt.test");
+ testCategory.setEnabled(QtDebugMsg, true);
+ QVERIFY(testCategory.isDebugEnabled());
+ QVERIFY(testCategory.isWarningEnabled());
+ QVERIFY(testCategory.isCriticalEnabled());
+
+ QQmlComponent component(&engine, testUrl);
+ QObject *object = component.create();
+ QVERIFY2(object != 0, component.errorString().toUtf8());
+
+ QVERIFY(messageHandler.messages().contains("qt.test: console.info"));
+ QVERIFY(messageHandler.messages().contains("qt.test: console.warn"));
+ QVERIFY(messageHandler.messages().contains("qt.test: console.error"));
+
+ QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) +
+ "QML LoggingCategory: Declaring the name of the 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";
+ QVERIFY(messageHandler.messages().contains(changedCategory));
+
+ QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(63) +
+ "Error: A QmlLoggingCatgory was provided without a valid name";
+ QVERIFY(messageHandler.messages().contains(useEmptyCategory));
+
+ delete object;
+}
+
void tst_qqmlconsole::tracing()
{
QUrl testUrl = testFileUrl("tracing.qml");
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index e0cde6c86f..f49fd391ac 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -61,6 +61,7 @@ private slots:
void qtbug_22535();
void evalAfterInvalidate();
void qobjectDerived();
+ void qtbug_49232();
private:
QQmlEngine engine;
@@ -200,6 +201,8 @@ class TestObject : public QObject
Q_PROPERTY(int a READ a NOTIFY aChanged)
Q_PROPERTY(int b READ b NOTIFY bChanged)
Q_PROPERTY(int c READ c NOTIFY cChanged)
+ Q_PROPERTY(char d READ d NOTIFY dChanged)
+ Q_PROPERTY(uchar e READ e NOTIFY eChanged)
public:
TestObject() : _a(10), _b(10), _c(10) {}
@@ -213,15 +216,25 @@ public:
int c() const { return _c; }
void setC(int c) { _c = c; emit cChanged(); }
+ char d() const { return _d; }
+ void setD(char d) { _d = d; emit dChanged(); }
+
+ uchar e() const { return _e; }
+ void setE(uchar e) { _e = e; emit eChanged(); }
+
signals:
void aChanged();
void bChanged();
void cChanged();
+ void dChanged();
+ void eChanged();
private:
int _a;
int _b;
int _c;
+ char _d;
+ uchar _e;
};
#define TEST_CONTEXT_PROPERTY(ctxt, name, value) \
@@ -694,6 +707,22 @@ void tst_qqmlcontext::qobjectDerived()
QCOMPARE(command.count, 2);
}
+void tst_qqmlcontext::qtbug_49232()
+{
+ TestObject testObject;
+ testObject.setD('a');
+ testObject.setE(97);
+
+ QQmlEngine engine;
+ engine.rootContext()->setContextProperty("TestObject", &testObject);
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0; QtObject { property int valueOne: TestObject.d; property int valueTwo: TestObject.e }", QUrl());
+ QScopedPointer<QObject> obj(component.create());
+
+ QCOMPARE(obj->property("valueOne"), QVariant('a'));
+ QCOMPARE(obj->property("valueTwo"), QVariant(97));
+}
+
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"
diff --git a/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml b/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml
new file mode 100644
index 0000000000..8bb0a3554e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml
@@ -0,0 +1,3 @@
+import Test 1.0
+WeakReferenceMutator {
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml b/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml
new file mode 100644
index 0000000000..4006a2a782
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+QtObject {
+ property Component factory: Component { QtObject {} }
+ property QtObject testProperty: factory.createObject()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml b/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml
new file mode 100644
index 0000000000..57d3ae2f14
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml
@@ -0,0 +1,12 @@
+import QtQml 2.0
+QtObject {
+ property int value: 100
+ property bool success: {
+ unrelatedFunction();
+ return value == 42;
+ }
+ property int unrelatedValue: 100
+ function unrelatedFunction() {
+ return unrelatedValue;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml
new file mode 100644
index 0000000000..d59f8f99f9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+NullObjectInitializerBase {
+ testProperty: null
+ property bool success: false
+ Component.onCompleted: {
+ success = testProperty === null;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml
new file mode 100644
index 0000000000..32bc62c9f2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property QtObject testProperty: null
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml
new file mode 100644
index 0000000000..8f7d5f2a70
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+
+QtObject {
+ function checkPropertyDeletion() {
+ var o = {
+ x: 1,
+ y: 2
+ };
+ o.z = 3
+ delete o.y;
+
+ return (o.x === 1 && o.y === undefined && o.z === 3)
+ }
+
+ property bool result: checkPropertyDeletion()
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 2f78df1f11..c734a0a011 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -44,6 +44,8 @@
#include <private/qv4scopedvalue_p.h>
#include <private/qv4alloca_p.h>
#include <private/qv4runtime_p.h>
+#include <private/qv4object_p.h>
+#include <private/qqmlcomponentattached_p.h>
#ifdef Q_CC_MSVC
#define NO_INLINE __declspec(noinline)
@@ -82,6 +84,7 @@ private slots:
void arrayExpressions();
void contextPropertiesTriggerReeval();
void objectPropertiesTriggerReeval();
+ void dependenciesWithFunctions();
void deferredProperties();
void deferredPropertiesErrors();
void deferredPropertiesInComponents();
@@ -208,6 +211,7 @@ private slots:
void dynamicCreationOwnership();
void regExpBug();
void nullObjectBinding();
+ void nullObjectInitializer();
void deletedEngine();
void libraryScriptAssert();
void variantsAssignedUndefined();
@@ -282,6 +286,7 @@ private slots:
void replaceBinding();
void deleteRootObjectInCreation();
void onDestruction();
+ void onDestructionViaGC();
void bindingSuppression();
void signalEmitted();
void threadSignal();
@@ -323,6 +328,8 @@ private slots:
void switchExpression();
void qtbug_46022();
void qtbug_52340();
+ void qtbug_54589();
+ void qtbug_54687();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -875,6 +882,18 @@ void tst_qqmlecmascript::objectPropertiesTriggerReeval()
}
}
+void tst_qqmlecmascript::dependenciesWithFunctions()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("dependenciesWithFunctions.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(object, qPrintable(component.errorString()));
+ QVERIFY(!object->property("success").toBool());
+ object->setProperty("value", 42);
+ QVERIFY(object->property("success").toBool());
+}
+
void tst_qqmlecmascript::deferredProperties()
{
QQmlComponent component(&engine, testFileUrl("deferredProperties.qml"));
@@ -2312,7 +2331,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const
QV4::ScopedCallData d(scope, 1);
d->args[0] = o;
d->thisObject = engine->global();
- function->call(d);
+ function->call(scope, d);
if (scope.engine->hasException) {
scope.engine->catchException();
return true;
@@ -2338,16 +2357,15 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o,
if (!function)
return false;
- QV4::ScopedValue value(scope);
QV4::ScopedCallData d(scope, 1);
d->args[0] = o;
d->thisObject = engine->global();
- value = function->call(d);
+ function->call(scope, d);
if (scope.engine->hasException) {
scope.engine->catchException();
return false;
}
- return QV4::Runtime::method_strictEqual(value, result);
+ return QV4::Runtime::method_strictEqual(scope.result, result);
}
static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o,
@@ -2371,12 +2389,12 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o
QV4::ScopedCallData d(scope, 1);
d->args[0] = o;
d->thisObject = engine->global();
- QV4::ScopedValue result(scope, function->call(d));
+ function->call(scope, d);
if (scope.engine->hasException) {
scope.engine->catchException();
return QV4::Encode::undefined();
}
- return result->asReturnedValue();
+ return scope.result.asReturnedValue();
}
#define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
@@ -5708,6 +5726,49 @@ void tst_qqmlecmascript::nullObjectBinding()
delete object;
}
+void tst_qqmlecmascript::nullObjectInitializer()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("nullObjectInitializer.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ QQmlData *ddata = QQmlData::get(obj.data(), /*create*/false);
+ QVERIFY(ddata);
+
+ {
+ const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty");
+ QVERIFY(propertyIndex > 0);
+ QVERIFY(!ddata->hasBindingBit(propertyIndex));
+ }
+
+ QVariant value = obj->property("testProperty");
+ QVERIFY(value.userType() == qMetaTypeId<QObject*>());
+ QVERIFY(!value.value<QObject*>());
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("nullObjectInitializer.2.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ QQmlData *ddata = QQmlData::get(obj.data(), /*create*/false);
+ QVERIFY(ddata);
+
+ {
+ const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty");
+ QVERIFY(propertyIndex > 0);
+ QVERIFY(ddata->hasBindingBit(propertyIndex));
+ }
+
+ QVERIFY(obj->property("success").toBool());
+
+ QVariant value = obj->property("testProperty");
+ QVERIFY(value.userType() == qMetaTypeId<QObject*>());
+ QVERIFY(!value.value<QObject*>());
+ }
+}
+
// Test that bindings don't evaluate once the engine has been destroyed
void tst_qqmlecmascript::deletedEngine()
{
@@ -5769,7 +5830,7 @@ void tst_qqmlecmascript::variants()
QVERIFY(object != 0);
QCOMPARE(object->property("undefinedVariant").type(), QVariant::Invalid);
- QCOMPARE(int(object->property("nullVariant").type()), int(QMetaType::VoidStar));
+ QCOMPARE(int(object->property("nullVariant").type()), int(QMetaType::Nullptr));
QCOMPARE(object->property("intVariant").type(), QVariant::Int);
QCOMPARE(object->property("doubleVariant").type(), QVariant::Double);
@@ -7155,6 +7216,105 @@ void tst_qqmlecmascript::onDestruction()
}
}
+class WeakReferenceMutator : public QObject
+{
+ Q_OBJECT
+public:
+ WeakReferenceMutator()
+ : resultPtr(Q_NULLPTR)
+ , weakRef(Q_NULLPTR)
+ {}
+
+ void init(QV4::ExecutionEngine *v4, QV4::WeakValue *weakRef, bool *resultPtr)
+ {
+ QV4::QObjectWrapper::wrap(v4, this);
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
+
+ this->resultPtr = resultPtr;
+ this->weakRef = weakRef;
+
+ QObject::connect(QQmlComponent::qmlAttachedProperties(this), &QQmlComponentAttached::destruction, this, &WeakReferenceMutator::reviveFirstWeakReference);
+ }
+
+private slots:
+ void reviveFirstWeakReference() {
+ *resultPtr = weakRef->valueRef() && weakRef->isNullOrUndefined();
+ if (!*resultPtr)
+ return;
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(this));
+ weakRef->set(v4, v4->newObject());
+ *resultPtr = weakRef->valueRef() && !weakRef->isNullOrUndefined();
+ }
+
+public:
+ bool *resultPtr;
+
+ QV4::WeakValue *weakRef;
+};
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace Heap {
+struct WeakReferenceSentinel : public Object {
+ WeakReferenceSentinel(WeakValue *weakRef, bool *resultPtr)
+ : weakRef(weakRef)
+ , resultPtr(resultPtr) {
+
+ }
+
+ ~WeakReferenceSentinel() {
+ *resultPtr = weakRef->isNullOrUndefined();
+ }
+
+ WeakValue *weakRef;
+ bool *resultPtr;
+};
+} // namespace Heap
+
+struct WeakReferenceSentinel : public Object {
+ V4_OBJECT2(WeakReferenceSentinel, Object)
+ V4_NEEDS_DESTROY
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+DEFINE_OBJECT_VTABLE(QV4::WeakReferenceSentinel);
+
+void tst_qqmlecmascript::onDestructionViaGC()
+{
+ qmlRegisterType<WeakReferenceMutator>("Test", 1, 0, "WeakReferenceMutator");
+
+ QQmlEngine engine;
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
+
+ QQmlComponent component(&engine, testFileUrl("DestructionHelper.qml"));
+
+ QScopedPointer<QV4::WeakValue> weakRef;
+
+ bool mutatorResult = false;
+ bool sentinelResult = false;
+
+ {
+ weakRef.reset(new QV4::WeakValue);
+ weakRef->set(v4, v4->newObject());
+ QVERIFY(!weakRef->isNullOrUndefined());
+
+ QPointer<WeakReferenceMutator> weakReferenceMutator = qobject_cast<WeakReferenceMutator *>(component.create());
+ QVERIFY2(!weakReferenceMutator.isNull(), qPrintable(component.errorString()));
+ weakReferenceMutator->init(v4, weakRef.data(), &mutatorResult);
+
+ v4->memoryManager->allocObject<QV4::WeakReferenceSentinel>(weakRef.data(), &sentinelResult);
+ }
+ gc(engine);
+
+ QVERIFY2(mutatorResult, "We failed to re-assign the weak reference a new value during GC");
+ QVERIFY2(sentinelResult, "The weak reference was not cleared properly");
+}
+
struct EventProcessor : public QObject
{
Q_OBJECT
@@ -7425,8 +7585,11 @@ void tst_qqmlecmascript::negativeYear()
QVariant q;
QMetaObject::invokeMethod(object, "check_negative_tostring", Q_RETURN_ARG(QVariant, q));
- // Strip the timezone. It should be irrelevant as the date was created with the same one.
- QCOMPARE(q.toString().left(32), QStringLiteral("result: Sat Jan 1 00:00:00 -2001"));
+
+ // Only check for the year. We hope that every language writes the year in arabic numerals and
+ // in relation to a specific dude's date of birth. We also hope that no language adds a "-2001"
+ // junk string somewhere in the middle.
+ QVERIFY(q.toString().indexOf(QStringLiteral("-2001")) != -1);
QMetaObject::invokeMethod(object, "check_negative_toisostring", Q_RETURN_ARG(QVariant, q));
QCOMPARE(q.toString().left(16), QStringLiteral("result: -002000-"));
@@ -7922,6 +8085,22 @@ void tst_qqmlecmascript::qtbug_52340()
QVERIFY(returnValue.toBool());
}
+void tst_qqmlecmascript::qtbug_54589()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_54589.qml"));
+
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->property("result").toBool(), true);
+}
+
+void tst_qqmlecmascript::qtbug_54687()
+{
+ QJSEngine e;
+ // it's simple: this shouldn't crash.
+ engine.evaluate("12\n----12");
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 3af1cf46b3..9c155eda5b 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -275,6 +275,12 @@ void tst_qqmlengine::clearComponentCache()
// Modify qml file
{
+ // On macOS with HFS+ the precision of file times is measured in seconds, so to ensure that
+ // the newly written file has a modification date newer than an existing cache file, we must
+ // wait.
+ // Similar effects of lacking precision have been observed on some Linux systems.
+ QThread::sleep(1);
+
QFile file("temp.qml");
QVERIFY(file.open(QIODevice::WriteOnly));
file.write("import QtQuick 2.0\nQtObject {\nproperty int test: 11\n}\n");
@@ -317,6 +323,11 @@ public:
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
QCoreApplication::processEvents();
+ // There might be JS function objects around that hold a last ref to the compilation unit that's
+ // keeping the type compilation data (CompilationUnit) around. Let's collect them as well so that
+ // trim works well.
+ engine->collectGarbage();
+
engine->trimComponentCache();
}
diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
index ab5e958323..124a107a37 100644
--- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
+++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
@@ -80,6 +80,10 @@ void tst_qqmlextensionplugin::iidCheck_data()
QList<QString> files;
for (QDirIterator it(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath), QDirIterator::Subdirectories); it.hasNext(); ) {
QString file = it.next();
+#if defined(Q_OS_DARWIN)
+ if (file.contains(QLatin1String(".dSYM/")))
+ continue;
+#endif
if (file.endsWith(SUFFIX)) {
files << file;
}
@@ -105,7 +109,7 @@ void tst_qqmlextensionplugin::iidCheck()
QFETCH(QString, filePath);
QPluginLoader loader(filePath);
- QVERIFY(loader.load());
+ QVERIFY2(loader.load(), qPrintable(loader.errorString()));
QVERIFY(loader.instance() != Q_NULLPTR);
if (qobject_cast<QQmlExtensionPlugin *>(loader.instance())) {
diff --git a/tests/auto/qml/qqmllanguage/data/alias.12.qml b/tests/auto/qml/qqmllanguage/data/alias.12.qml
new file mode 100644
index 0000000000..cc17318092
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.12.qml
@@ -0,0 +1,15 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+ property alias topLevelAlias: subObject.targetProperty
+
+ property QtObject referencingSubObject: QtObject {
+ property alias success: root.topLevelAlias
+ }
+
+ property QtObject foo: QtObject {
+ id: subObject
+ property bool targetProperty: true
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.13.qml b/tests/auto/qml/qqmllanguage/data/alias.13.qml
new file mode 100644
index 0000000000..cff8a72d9a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.13.qml
@@ -0,0 +1,16 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+ property bool targetProperty: true
+
+ property QtObject foo: QtObject {
+ id: otherSubObject
+ property alias theAlias: root.targetProperty
+ }
+
+ property QtObject referencingSubObject: QtObject {
+ property alias success: otherSubObject.theAlias
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt b/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt
new file mode 100644
index 0000000000..90a3ea4317
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt
@@ -0,0 +1 @@
+10:34:References to other aliases within the same object are not supported at the moment
diff --git a/tests/auto/qml/qqmllanguage/data/alias.14.qml b/tests/auto/qml/qqmllanguage/data/alias.14.qml
new file mode 100644
index 0000000000..ff3c36d990
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.14.qml
@@ -0,0 +1,17 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+ property bool targetProperty: true
+
+ property QtObject foo: QtObject {
+ id: otherSubObject
+ property alias theAliasOrigin: root.targetProperty
+ property alias theAlias: otherSubObject.theAliasOrigin
+ }
+
+ property QtObject referencingSubObject: QtObject {
+ property alias success: otherSubObject.theAlias
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml b/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml
index c91cf581b3..52027232db 100644
--- a/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml
+++ b/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml
@@ -26,7 +26,9 @@ MyTypeObject {
boolProperty: true
variantProperty: "Hello World!"
vectorProperty: "10,1,2.2"
+ vector2Property: "2, 3"
vector4Property: "10,1,2.2,2.3"
+ quaternionProperty: "4,5,6,7"
urlProperty: "main.qml?with%3cencoded%3edata"
objectProperty: MyTypeObject { intProperty: 8 }
diff --git a/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt b/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt
index 7a75447a62..acf0d1da84 100644
--- a/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt
@@ -1,2 +1,2 @@
3:1:Type RegisteredCompositeType2 unavailable
--1:-1:File not found
+-1:-1:No such file or directory
diff --git a/tests/auto/qml/qqmllanguage/data/cppnamespace.qml b/tests/auto/qml/qqmllanguage/data/cppnamespace.qml
index e1daf3b78f..efedf2b14a 100644
--- a/tests/auto/qml/qqmllanguage/data/cppnamespace.qml
+++ b/tests/auto/qml/qqmllanguage/data/cppnamespace.qml
@@ -1,4 +1,5 @@
import Test 1.0
MyNamespacedType {
+ myEnum: MyNamespace.Key5
}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt
new file mode 100644
index 0000000000..b79b660c46
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt
@@ -0,0 +1 @@
+5:5:Circular alias reference detected
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml
new file mode 100644
index 0000000000..9b50b48df8
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+ property alias a: subObject.b
+ property QtObject foo: QtObject {
+ id: subObject
+ property alias b: root.a
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt
index 716cf5709a..b3082d80e6 100644
--- a/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt
+++ b/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt
@@ -1,2 +1,2 @@
5:5:Type RegisteredCompositeType unavailable
-2:1:pragma Singleton used with a non composite singleton type CompositeSingletonTest/RegisteredCompositeType
+-1:-1:pragma Singleton used with a non composite singleton type CompositeSingletonTest/RegisteredCompositeType
diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt
index 77c26df310..ebeab6987b 100644
--- a/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt
+++ b/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt
@@ -1 +1 @@
-2:1:No matching type found, pragma Singleton files cannot be used by QQmlComponent.
+-1:-1:No matching type found, pragma Singleton files cannot be used by QQmlComponent.
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index ccfcfc098e..3af7645ff7 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -27,8 +27,6 @@
****************************************************************************/
#include "testtypes.h"
-#include <private/qqmlcompiler_p.h>
-
static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
@@ -47,6 +45,7 @@ void registerTypes()
qmlRegisterType<MyDotPropertyObject>("Test",1,0,"MyDotPropertyObject");
qmlRegisterType<MyNamespace::MyNamespacedType>("Test",1,0,"MyNamespacedType");
qmlRegisterType<MyNamespace::MySecondNamespacedType>("Test",1,0,"MySecondNamespacedType");
+ qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "Test", 1, 0, "MyNamespace", "Access to enums & flags only");
qmlRegisterType<MyParserStatus>("Test",1,0,"MyParserStatus");
qmlRegisterType<MyGroupedObject>();
qmlRegisterType<MyRevisionedClass>("Test",1,0,"MyRevisionedClass");
@@ -131,9 +130,10 @@ void CustomBinding::componentComplete()
QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, compilationUnit->runtimeFunctions[bindingId]));
- QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context);
QQmlProperty property(m_target, name, qmlContext(this));
+ QQmlBinding *qmlBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core,
+ function, m_target, context);
qmlBinding->setTarget(property);
QQmlPropertyPrivate::setBinding(property, qmlBinding);
}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index 788ae42726..6c62bcf7b9 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -33,15 +33,16 @@
#include <QtCore/qdatetime.h>
#include <QtGui/qmatrix.h>
#include <QtGui/qcolor.h>
+#include <QtGui/qvector2d.h>
#include <QtGui/qvector3d.h>
#include <QtGui/qvector4d.h>
+#include <QtGui/qquaternion.h>
#include <QtQml/qqml.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qqmlpropertyvaluesource.h>
#include <QtQml/qqmlscriptstring.h>
#include <QtQml/qqmlproperty.h>
-#include <private/qqmlcompiler_p.h>
#include <private/qqmlcustomparser_p.h>
QVariant myCustomVariantTypeConverter(const QString &data);
@@ -242,8 +243,10 @@ class MyTypeObject : public QObject
Q_PROPERTY(QRectF rectFProperty READ rectFProperty WRITE setRectFProperty NOTIFY rectFPropertyChanged)
Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty NOTIFY boolPropertyChanged)
Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty NOTIFY variantPropertyChanged)
+ Q_PROPERTY(QVector2D vector2Property READ vector2Property WRITE setVector2Property NOTIFY vector2PropertyChanged)
Q_PROPERTY(QVector3D vectorProperty READ vectorProperty WRITE setVectorProperty NOTIFY vectorPropertyChanged)
Q_PROPERTY(QVector4D vector4Property READ vector4Property WRITE setVector4Property NOTIFY vector4PropertyChanged)
+ Q_PROPERTY(QQuaternion quaternionProperty READ quaternionProperty WRITE setQuaternionProperty NOTIFY quaternionPropertyChanged)
Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty NOTIFY urlPropertyChanged)
Q_PROPERTY(QQmlScriptString scriptProperty READ scriptProperty WRITE setScriptProperty)
@@ -524,6 +527,15 @@ public:
emit vectorPropertyChanged();
}
+ QVector2D vector2PropertyValue;
+ QVector2D vector2Property() const {
+ return vector2PropertyValue;
+ }
+ void setVector2Property(const QVector2D &v) {
+ vector2PropertyValue = v;
+ emit vector2PropertyChanged();
+ }
+
QVector4D vector4PropertyValue;
QVector4D vector4Property() const {
return vector4PropertyValue;
@@ -533,6 +545,15 @@ public:
emit vector4PropertyChanged();
}
+ QQuaternion quaternionPropertyValue;
+ QQuaternion quaternionProperty() const {
+ return quaternionPropertyValue;
+ }
+ void setQuaternionProperty(const QQuaternion &v) {
+ quaternionPropertyValue = v;
+ emit quaternionPropertyChanged();
+ }
+
QUrl urlPropertyValue;
QUrl urlProperty() const {
return urlPropertyValue;
@@ -586,7 +607,9 @@ signals:
void boolPropertyChanged();
void variantPropertyChanged();
void vectorPropertyChanged();
+ void vector2PropertyChanged();
void vector4PropertyChanged();
+ void quaternionPropertyChanged();
void urlPropertyChanged();
};
@@ -707,9 +730,19 @@ private:
namespace MyNamespace {
+ Q_NAMESPACE
+ enum MyNSEnum {
+ Key1 = 1,
+ Key2,
+ Key5 = 5
+ };
+ Q_ENUM_NS(MyNSEnum);
+
class MyNamespacedType : public QObject
{
Q_OBJECT
+ Q_PROPERTY(MyNamespace::MyNSEnum myEnum MEMBER m_myEnum)
+ MyNamespace::MyNSEnum m_myEnum = MyNSEnum::Key1;
};
class MySecondNamespacedType : public QObject
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 58a7c39760..ad06946b0b 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -494,6 +494,7 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("invalidAlias.8") << "invalidAlias.8.qml" << "invalidAlias.8.errors.txt" << false;
QTest::newRow("invalidAlias.9") << "invalidAlias.9.qml" << "invalidAlias.9.errors.txt" << false;
QTest::newRow("invalidAlias.10") << "invalidAlias.10.qml" << "invalidAlias.10.errors.txt" << false;
+ QTest::newRow("invalidAlias.11") << "invalidAlias.11.qml" << "invalidAlias.11.errors.txt" << false;
QTest::newRow("invalidAttachedProperty.1") << "invalidAttachedProperty.1.qml" << "invalidAttachedProperty.1.errors.txt" << false;
QTest::newRow("invalidAttachedProperty.2") << "invalidAttachedProperty.2.qml" << "invalidAttachedProperty.2.errors.txt" << false;
@@ -681,6 +682,7 @@ void tst_qqmllanguage::assignBasicTypes()
QCOMPARE(object->boolProperty(), true);
QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2f));
+ QCOMPARE(object->vector2Property(), QVector2D(2, 3));
QCOMPARE(object->vector4Property(), QVector4D(10, 1, 2.2f, 2.3f));
const QUrl encoded = QUrl::fromEncoded("main.qml?with%3cencoded%3edata", QUrl::TolerantMode);
QCOMPARE(object->urlProperty(), component.url().resolved(encoded));
@@ -1803,6 +1805,48 @@ void tst_qqmllanguage::aliasProperties()
delete object;
}
+
+ // Nested aliases with a qml file
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.12.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject"));
+ QVERIFY(!subObject.isNull());
+
+ QVERIFY(subObject->property("success").toBool());
+ }
+
+ // Nested aliases with a qml file with reverse ordering
+ {
+ // This is known to fail at the moment.
+ QQmlComponent component(&engine, testFileUrl("alias.13.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject"));
+ QVERIFY(!subObject.isNull());
+
+ QVERIFY(subObject->property("success").toBool());
+ }
+
+ // "Nested" aliases within an object that require iterative resolution
+ {
+ // This is known to fail at the moment.
+ QQmlComponent component(&engine, testFileUrl("alias.14.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject"));
+ QVERIFY(!subObject.isNull());
+
+ QVERIFY(subObject->property("success").toBool());
+ }
}
// QTBUG-13374 Test that alias properties and signals can coexist
@@ -2074,8 +2118,13 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
QQmlTypeData *td = eng->typeLoader.getType(url);
Q_ASSERT(td);
- QV4::CompiledData::Unit *qmlUnit = td->compiledData()->compilationUnit->data;
- Q_ASSERT(qmlUnit);
+ const QV4::CompiledData::Unit *readOnlyQmlUnit = td->compilationUnit()->data;
+ Q_ASSERT(readOnlyQmlUnit);
+ QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(malloc(readOnlyQmlUnit->unitSize));
+ memcpy(qmlUnit, readOnlyQmlUnit, readOnlyQmlUnit->unitSize);
+ qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
+ td->compilationUnit()->data = qmlUnit;
+
const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
QCOMPARE(qmlUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject"));
quint32 i;
@@ -2552,7 +2601,7 @@ void tst_qqmllanguage::basicRemote_data()
QTest::newRow("no need for qmldir") << QUrl(serverdir+"Test.qml") << "" << "";
QTest::newRow("absent qmldir") << QUrl(serverdir+"/noqmldir/Test.qml") << "" << "";
- QTest::newRow("need qmldir") << QUrl(serverdir+"TestLocal.qml") << "" << "";
+ QTest::newRow("need qmldir") << QUrl(serverdir+"TestNamed.qml") << "" << "";
}
void tst_qqmllanguage::basicRemote()
@@ -2592,6 +2641,8 @@ void tst_qqmllanguage::importsRemote_data()
<< "";
QTest::newRow("remote import with local") << "import \""+serverdir+"\"\nTestLocal {}" << "QQuickImage"
<< "";
+ QTest::newRow("remote import with qualifier") << "import \""+serverdir+"\" as NS\nNS.NamedLocal {}" << "QQuickImage"
+ << "";
QTest::newRow("wrong remote import with undeclared local") << "import \""+serverdir+"\"\nWrongTestLocal {}" << ""
<< "WrongTestLocal is not a type";
QTest::newRow("wrong remote import of internal local") << "import \""+serverdir+"\"\nLocalInternal {}" << ""
@@ -2898,7 +2949,7 @@ void tst_qqmllanguage::importIncorrectCase()
QCOMPARE(errors.count(), 1);
const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ?
- QStringLiteral("File not found") :
+ QStringLiteral("No such file or directory") :
QStringLiteral("File name case mismatch");
QCOMPARE(errors.at(0).description(), expectedError);
@@ -4077,7 +4128,7 @@ void tst_qqmllanguage::preservePropertyCacheOnGroupObjects()
QVERIFY(subCache);
QQmlPropertyData *pd = subCache->property(QStringLiteral("newProperty"), /*object*/0, /*context*/0);
QVERIFY(pd);
- QCOMPARE(pd->propType, qMetaTypeId<int>());
+ QCOMPARE(pd->propType(), qMetaTypeId<int>());
}
void tst_qqmllanguage::propertyCacheInSync()
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index b3d199f80f..cd497cbd79 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -105,6 +105,7 @@ private slots:
void get_nested();
void get_nested_data();
void crash_model_with_multiple_roles();
+ void crash_model_with_unknown_roles();
void set_model_cache();
void property_changes();
void property_changes_data();
@@ -963,6 +964,21 @@ void tst_qqmllistmodel::crash_model_with_multiple_roles()
delete rootItem;
}
+void tst_qqmllistmodel::crash_model_with_unknown_roles()
+{
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("multipleroles.qml"));
+ QScopedPointer<QObject> rootItem(component.create());
+ QVERIFY(component.errorString().isEmpty());
+ QVERIFY(rootItem != 0);
+ QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
+ QVERIFY(model != 0);
+
+ // used to cause a crash in debug builds
+ model->index(0, 0, QModelIndex()).data(Qt::DisplayRole);
+ model->index(0, 0, QModelIndex()).data(Qt::UserRole);
+}
+
//QTBUG-15190
void tst_qqmllistmodel::set_model_cache()
{
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 5a8f2747a9..fe73610bcc 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -157,7 +157,7 @@ void tst_qqmlproperty::qmlmetaproperty()
QObject *obj = new QObject;
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(nullptr, QLatin1String("null"), 0, engine.rootContext()));
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(obj, QObjectPrivate::get(obj)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
@@ -194,7 +194,8 @@ void tst_qqmlproperty::qmlmetaproperty()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), -1);
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -326,11 +327,8 @@ class PropertyObject : public QObject
Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject)
Q_PROPERTY(MyQObject *qObject READ qObject WRITE setQObject NOTIFY qObjectChanged)
Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
- Q_PROPERTY(char charProperty READ charProperty WRITE setCharProperty)
Q_PROPERTY(QChar qcharProperty READ qcharProperty WRITE setQcharProperty)
Q_PROPERTY(QChar constQChar READ constQChar STORED false CONSTANT FINAL)
- Q_PROPERTY(char constChar READ constChar STORED false CONSTANT FINAL)
- Q_PROPERTY(int constInt READ constInt STORED false CONSTANT FINAL)
Q_CLASSINFO("DefaultProperty", "defaultProperty")
public:
@@ -367,15 +365,11 @@ public:
}
QString stringProperty() const { return m_stringProperty;}
- char charProperty() const { return m_charProperty; }
QChar qcharProperty() const { return m_qcharProperty; }
QChar constQChar() const { return 0x25cf; /* Unicode: black circle */ }
- char constChar() const { return 'A'; }
- int constInt() const { return 123456; }
void setStringProperty(QString arg) { m_stringProperty = arg; }
- void setCharProperty(char arg) { m_charProperty = arg; }
void setQcharProperty(QChar arg) { m_qcharProperty = arg; }
signals:
@@ -392,7 +386,6 @@ private:
MyQmlObject m_qmlObject;
MyQObject *m_qObject;
QString m_stringProperty;
- char m_charProperty;
QChar m_qcharProperty;
};
@@ -406,7 +399,7 @@ void tst_qqmlproperty::qmlmetaproperty_object()
{
QQmlProperty prop(&object);
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
@@ -445,7 +438,8 @@ void tst_qqmlproperty::qmlmetaproperty_object()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), -1);
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -453,7 +447,7 @@ void tst_qqmlproperty::qmlmetaproperty_object()
{
QQmlProperty prop(&dobject);
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
@@ -495,7 +489,8 @@ void tst_qqmlproperty::qmlmetaproperty_object()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -509,7 +504,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
{
QQmlProperty prop(&object, QString("defaultProperty"));
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
@@ -548,7 +543,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), -1);
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -556,7 +552,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
{
QQmlProperty prop(&dobject, QString("defaultProperty"));
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
@@ -598,7 +594,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -606,7 +603,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
{
QQmlProperty prop(&dobject, QString("onClicked"));
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
@@ -647,7 +644,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QVERIFY(!sigExprWatcher.wasDeleted());
QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr);
QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()"));
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -655,7 +653,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
{
QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"));
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
@@ -696,7 +694,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QVERIFY(!sigExprWatcher.wasDeleted());
QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr);
QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()"));
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -710,7 +709,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
{
QQmlProperty prop(&object, engine.rootContext());
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
@@ -749,7 +748,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), -1);
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -757,7 +757,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
{
QQmlProperty prop(&dobject, engine.rootContext());
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
@@ -799,7 +799,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -813,7 +814,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
{
QQmlProperty prop(&object, QString("defaultProperty"), engine.rootContext());
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
@@ -852,7 +853,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), -1);
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -860,7 +862,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
{
QQmlProperty prop(&dobject, QString("defaultProperty"), engine.rootContext());
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
@@ -902,7 +904,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr);
QVERIFY(sigExprWatcher.wasDeleted());
QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -910,7 +913,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
{
QQmlProperty prop(&dobject, QString("onClicked"), engine.rootContext());
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
@@ -951,7 +954,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QVERIFY(!sigExprWatcher.wasDeleted());
QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr);
QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()"));
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -959,7 +963,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
{
QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext());
- QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext()));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
@@ -1000,7 +1004,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QVERIFY(!sigExprWatcher.wasDeleted());
QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr);
QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()"));
- QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
+ QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1);
+ QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex());
delete obj;
}
@@ -1405,23 +1410,14 @@ void tst_qqmlproperty::write()
// Char/string-property
{
PropertyObject o;
- QQmlProperty charProperty(&o, "charProperty");
QQmlProperty qcharProperty(&o, "qcharProperty");
QQmlProperty stringProperty(&o, "stringProperty");
const int black_circle = 0x25cf;
- QCOMPARE(charProperty.write(QString("foo")), false);
- QCOMPARE(charProperty.write('Q'), true);
- QCOMPARE(charProperty.read(), QVariant('Q'));
- QCOMPARE(charProperty.write(QString("t")), true);
- QCOMPARE(charProperty.read(), QVariant('t'));
-
QCOMPARE(qcharProperty.write(QString("foo")), false);
QCOMPARE(qcharProperty.write('Q'), true);
QCOMPARE(qcharProperty.read(), QVariant('Q'));
- QCOMPARE(qcharProperty.write(QString("t")), true);
- QCOMPARE(qcharProperty.read(), QVariant('t'));
QCOMPARE(qcharProperty.write(QChar(black_circle)), true);
QCOMPARE(qcharProperty.read(), QVariant(QChar(black_circle)));
@@ -1430,19 +1426,10 @@ void tst_qqmlproperty::write()
QCOMPARE(o.stringProperty(), QString("bar"));
QCOMPARE(stringProperty.write(QVariant(1234)), true);
QCOMPARE(stringProperty.read().toString(), QString::number(1234));
+ QCOMPARE(stringProperty.write('A'), true);
+ QCOMPARE(stringProperty.read().toString(), QString::number('A'));
QCOMPARE(stringProperty.write(QChar(black_circle)), true);
- QCOMPARE(stringProperty.read(), QVariant(QString(QChar(black_circle))));
-
- { // char -> QString
- QQmlComponent component(&engine);
- component.setData("import Test 1.0\nPropertyObject { stringProperty: constChar }", QUrl());
- PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
- QVERIFY(obj != 0);
- if (obj) {
- QQmlProperty stringProperty(obj, "stringProperty");
- QCOMPARE(stringProperty.read(), QVariant(QString(obj->constChar())));
- }
- }
+ QCOMPARE(stringProperty.read(), QVariant(QChar(black_circle)));
{ // QChar -> QString
QQmlComponent component(&engine);
@@ -1455,16 +1442,6 @@ void tst_qqmlproperty::write()
}
}
- { // int -> QString
- QQmlComponent component(&engine);
- component.setData("import Test 1.0\nPropertyObject { stringProperty: constInt }", QUrl());
- PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
- QVERIFY(obj != 0);
- if (obj) {
- QQmlProperty stringProperty(obj, "stringProperty");
- QCOMPARE(stringProperty.read(), QVariant(QString::number(obj->constInt())));
- }
- }
}
// VariantMap-property
@@ -2078,15 +2055,15 @@ void tst_qqmlproperty::floatToStringPrecision()
QFETCH(QString, qtString);
QFETCH(QString, jsString);
- const char *name = propertyName.toLatin1().constData();
+ QByteArray name = propertyName.toLatin1();
QCOMPARE(obj->property(name).toDouble(), number);
QCOMPARE(obj->property(name).toString(), qtString);
- const char *name1 = (propertyName + QLatin1Char('1')).toLatin1().constData();
+ QByteArray name1 = (propertyName + QLatin1Char('1')).toLatin1();
QCOMPARE(obj->property(name1).toDouble(), number);
QCOMPARE(obj->property(name1).toString(), qtString);
- const char *name2 = (propertyName + QLatin1Char('2')).toLatin1().constData();
+ QByteArray name2 = (propertyName + QLatin1Char('2')).toLatin1();
QCOMPARE(obj->property(name2).toDouble(), number);
QCOMPARE(obj->property(name2).toString(), jsString);
diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
index 5f15afff85..824fe445c0 100644
--- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
+++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
@@ -30,6 +30,8 @@
#include <private/qqmlpropertycache_p.h>
#include <QtQml/qqmlengine.h>
#include <private/qv8engine_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <QCryptographicHash>
#include "../../shared/util.h"
class tst_qqmlpropertycache : public QObject
@@ -45,6 +47,9 @@ private slots:
void methodsDerived();
void signalHandlers();
void signalHandlersDerived();
+ void metaObjectSize_data();
+ void metaObjectSize();
+ void metaObjectChecksum();
private:
QQmlEngine engine;
@@ -105,17 +110,17 @@ void tst_qqmlpropertycache::properties()
QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
QQmlPropertyData *data;
- QVERIFY(data = cacheProperty(cache, "propertyA"));
- QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA"));
+ QVERIFY((data = cacheProperty(cache, "propertyA")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA"));
- QVERIFY(data = cacheProperty(cache, "propertyB"));
- QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB"));
+ QVERIFY((data = cacheProperty(cache, "propertyB")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyB"));
- QVERIFY(data = cacheProperty(cache, "propertyC"));
- QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC"));
+ QVERIFY((data = cacheProperty(cache, "propertyC")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyC"));
- QVERIFY(data = cacheProperty(cache, "propertyD"));
- QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD"));
+ QVERIFY((data = cacheProperty(cache, "propertyD")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD"));
}
void tst_qqmlpropertycache::propertiesDerived()
@@ -129,17 +134,17 @@ void tst_qqmlpropertycache::propertiesDerived()
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
QQmlPropertyData *data;
- QVERIFY(data = cacheProperty(cache, "propertyA"));
- QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA"));
+ QVERIFY((data = cacheProperty(cache, "propertyA")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA"));
- QVERIFY(data = cacheProperty(cache, "propertyB"));
- QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB"));
+ QVERIFY((data = cacheProperty(cache, "propertyB")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyB"));
- QVERIFY(data = cacheProperty(cache, "propertyC"));
- QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC"));
+ QVERIFY((data = cacheProperty(cache, "propertyC")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyC"));
- QVERIFY(data = cacheProperty(cache, "propertyD"));
- QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD"));
+ QVERIFY((data = cacheProperty(cache, "propertyD")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD"));
}
void tst_qqmlpropertycache::methods()
@@ -152,29 +157,29 @@ void tst_qqmlpropertycache::methods()
QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
QQmlPropertyData *data;
- QVERIFY(data = cacheProperty(cache, "slotA"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()"));
+ QVERIFY((data = cacheProperty(cache, "slotA")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()"));
- QVERIFY(data = cacheProperty(cache, "slotB"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()"));
+ QVERIFY((data = cacheProperty(cache, "slotB")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotB()"));
- QVERIFY(data = cacheProperty(cache, "signalA"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()"));
+ QVERIFY((data = cacheProperty(cache, "signalA")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()"));
- QVERIFY(data = cacheProperty(cache, "signalB"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()"));
+ QVERIFY((data = cacheProperty(cache, "signalB")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()"));
- QVERIFY(data = cacheProperty(cache, "propertyAChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()"));
+ QVERIFY((data = cacheProperty(cache, "propertyAChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()"));
- QVERIFY(data = cacheProperty(cache, "propertyBChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()"));
+ QVERIFY((data = cacheProperty(cache, "propertyBChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()"));
- QVERIFY(data = cacheProperty(cache, "propertyCChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()"));
+ QVERIFY((data = cacheProperty(cache, "propertyCChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()"));
- QVERIFY(data = cacheProperty(cache, "propertyDChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()"));
+ QVERIFY((data = cacheProperty(cache, "propertyDChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
}
void tst_qqmlpropertycache::methodsDerived()
@@ -188,29 +193,29 @@ void tst_qqmlpropertycache::methodsDerived()
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
QQmlPropertyData *data;
- QVERIFY(data = cacheProperty(cache, "slotA"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()"));
+ QVERIFY((data = cacheProperty(cache, "slotA")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()"));
- QVERIFY(data = cacheProperty(cache, "slotB"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()"));
+ QVERIFY((data = cacheProperty(cache, "slotB")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotB()"));
- QVERIFY(data = cacheProperty(cache, "signalA"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()"));
+ QVERIFY((data = cacheProperty(cache, "signalA")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()"));
- QVERIFY(data = cacheProperty(cache, "signalB"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()"));
+ QVERIFY((data = cacheProperty(cache, "signalB")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()"));
- QVERIFY(data = cacheProperty(cache, "propertyAChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()"));
+ QVERIFY((data = cacheProperty(cache, "propertyAChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()"));
- QVERIFY(data = cacheProperty(cache, "propertyBChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()"));
+ QVERIFY((data = cacheProperty(cache, "propertyBChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()"));
- QVERIFY(data = cacheProperty(cache, "propertyCChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()"));
+ QVERIFY((data = cacheProperty(cache, "propertyCChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()"));
- QVERIFY(data = cacheProperty(cache, "propertyDChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()"));
+ QVERIFY((data = cacheProperty(cache, "propertyDChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
}
void tst_qqmlpropertycache::signalHandlers()
@@ -223,23 +228,23 @@ void tst_qqmlpropertycache::signalHandlers()
QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
QQmlPropertyData *data;
- QVERIFY(data = cacheProperty(cache, "onSignalA"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()"));
+ QVERIFY((data = cacheProperty(cache, "onSignalA")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()"));
- QVERIFY(data = cacheProperty(cache, "onSignalB"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()"));
+ QVERIFY((data = cacheProperty(cache, "onSignalB")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()"));
- QVERIFY(data = cacheProperty(cache, "onPropertyAChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()"));
+ QVERIFY((data = cacheProperty(cache, "onPropertyAChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()"));
- QVERIFY(data = cacheProperty(cache, "onPropertyBChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()"));
+ QVERIFY((data = cacheProperty(cache, "onPropertyBChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()"));
- QVERIFY(data = cacheProperty(cache, "onPropertyCChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()"));
+ QVERIFY((data = cacheProperty(cache, "onPropertyCChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()"));
- QVERIFY(data = cacheProperty(cache, "onPropertyDChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()"));
+ QVERIFY((data = cacheProperty(cache, "onPropertyDChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
}
void tst_qqmlpropertycache::signalHandlersDerived()
@@ -253,25 +258,145 @@ void tst_qqmlpropertycache::signalHandlersDerived()
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
QQmlPropertyData *data;
- QVERIFY(data = cacheProperty(cache, "onSignalA"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()"));
+ QVERIFY((data = cacheProperty(cache, "onSignalA")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()"));
- QVERIFY(data = cacheProperty(cache, "onSignalB"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()"));
+ QVERIFY((data = cacheProperty(cache, "onSignalB")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()"));
- QVERIFY(data = cacheProperty(cache, "onPropertyAChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()"));
+ QVERIFY((data = cacheProperty(cache, "onPropertyAChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()"));
- QVERIFY(data = cacheProperty(cache, "onPropertyBChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()"));
+ QVERIFY((data = cacheProperty(cache, "onPropertyBChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()"));
- QVERIFY(data = cacheProperty(cache, "onPropertyCChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()"));
+ QVERIFY((data = cacheProperty(cache, "onPropertyCChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()"));
- QVERIFY(data = cacheProperty(cache, "onPropertyDChanged"));
- QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()"));
+ QVERIFY((data = cacheProperty(cache, "onPropertyDChanged")));
+ QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
}
-QTEST_MAIN(tst_qqmlpropertycache)
+class TestClass : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged)
+ int m_prop;
+
+public:
+ enum MyEnum {
+ First, Second
+ };
+ Q_ENUM(MyEnum)
+
+ Q_CLASSINFO("Foo", "Bar")
+
+ TestClass() {}
+
+ int prop() const
+ {
+ return m_prop;
+ }
+
+public slots:
+ void setProp(int prop)
+ {
+ if (m_prop == prop)
+ return;
+
+ m_prop = prop;
+ emit propChanged(prop);
+ }
+signals:
+ void propChanged(int prop);
+};
+
+class TestClassWithParameters : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_INVOKABLE void slotWithArguments(int firstArg) {
+ Q_UNUSED(firstArg);
+ }
+};
+
+class TestClassWithClassInfo : public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("Key", "Value")
+};
#include "tst_qqmlpropertycache.moc"
+
+#define ARRAY_SIZE(arr) \
+ int(sizeof(arr) / sizeof(arr[0]))
+
+#define TEST_CLASS(Class) \
+ QTest::newRow(#Class) << &Class::staticMetaObject << ARRAY_SIZE(qt_meta_data_##Class) << ARRAY_SIZE(qt_meta_stringdata_##Class.data)
+
+Q_DECLARE_METATYPE(const QMetaObject*);
+
+void tst_qqmlpropertycache::metaObjectSize_data()
+{
+ QTest::addColumn<const QMetaObject*>("metaObject");
+ QTest::addColumn<int>("expectedFieldCount");
+ QTest::addColumn<int>("expectedStringCount");
+
+ TEST_CLASS(TestClass);
+ TEST_CLASS(TestClassWithParameters);
+ TEST_CLASS(TestClassWithClassInfo);
+}
+
+void tst_qqmlpropertycache::metaObjectSize()
+{
+ QFETCH(const QMetaObject *, metaObject);
+ QFETCH(int, expectedFieldCount);
+ QFETCH(int, expectedStringCount);
+
+ int size = 0;
+ int stringDataSize = 0;
+ bool valid = QQmlPropertyCache::determineMetaObjectSizes(*metaObject, &size, &stringDataSize);
+ QVERIFY(valid);
+
+ QCOMPARE(size, expectedFieldCount - 1); // Remove trailing zero field until fixed in moc.
+ QCOMPARE(stringDataSize, expectedStringCount);
+}
+
+void tst_qqmlpropertycache::metaObjectChecksum()
+{
+ QMetaObjectBuilder builder;
+ builder.setClassName("Test");
+ builder.addClassInfo("foo", "bar");
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ QScopedPointer<QMetaObject, QScopedPointerPodDeleter> mo(builder.toMetaObject());
+ QVERIFY(!mo.isNull());
+
+ QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
+ QByteArray initialHash = hash.result();
+ QVERIFY(!initialHash.isEmpty());
+ hash.reset();
+
+ {
+ QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
+ QByteArray nextHash = hash.result();
+ QVERIFY(!nextHash.isEmpty());
+ hash.reset();
+ QCOMPARE(initialHash, nextHash);
+ }
+
+ builder.addProperty("testProperty", "int", -1);
+
+ mo.reset(builder.toMetaObject());
+ {
+ QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
+ QByteArray nextHash = hash.result();
+ QVERIFY(!nextHash.isEmpty());
+ hash.reset();
+ QVERIFY(initialHash != nextHash);
+ }
+}
+
+QTEST_MAIN(tst_qqmlpropertycache)
diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
index e0c2324dc6..b8ea98df2b 100644
--- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
+++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
@@ -60,6 +60,7 @@ private slots:
void QTBUG_35233();
void disallowExtending();
void QTBUG_35906();
+ void QTBUG_48136();
};
class LazyPropertyMap : public QQmlPropertyMap, public QQmlParserStatus
@@ -462,6 +463,40 @@ void tst_QQmlPropertyMap::QTBUG_35906()
QCOMPARE(value.toInt(), 42);
}
+void tst_QQmlPropertyMap::QTBUG_48136()
+{
+ static const char key[] = "mykey";
+ QQmlPropertyMap map;
+
+ //
+ // Test that the notify signal is emitted correctly
+ //
+
+ const int propIndex = map.metaObject()->indexOfProperty(key);
+ const QMetaProperty prop = map.metaObject()->property(propIndex);
+ QSignalSpy notifySpy(&map, QByteArray::number(QSIGNAL_CODE) + prop.notifySignal().methodSignature());
+
+ map.insert(key, 42);
+ QCOMPARE(notifySpy.count(), 1);
+ map.insert(key, 43);
+ QCOMPARE(notifySpy.count(), 2);
+ map.insert(key, 43);
+ QCOMPARE(notifySpy.count(), 2);
+ map.insert(key, 44);
+ QCOMPARE(notifySpy.count(), 3);
+
+ //
+ // Test that the valueChanged signal is emitted correctly
+ //
+ QSignalSpy valueChangedSpy(&map, &QQmlPropertyMap::valueChanged);
+ map.setProperty(key, 44);
+ QCOMPARE(valueChangedSpy.count(), 0);
+ map.setProperty(key, 45);
+ QCOMPARE(valueChangedSpy.count(), 1);
+ map.setProperty(key, 45);
+ QCOMPARE(valueChangedSpy.count(), 1);
+}
+
QTEST_MAIN(tst_QQmlPropertyMap)
#include "tst_qqmlpropertymap.moc"
diff --git a/tests/auto/qml/qqmlqt/data/exit.qml b/tests/auto/qml/qqmlqt/data/exit.qml
new file mode 100644
index 0000000000..12727d9f04
--- /dev/null
+++ b/tests/auto/qml/qqmlqt/data/exit.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+QtObject {
+ property int returnCode: -1
+ Component.onCompleted: Qt.exit(returnCode)
+}
+
diff --git a/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml
new file mode 100644
index 0000000000..9d73640c87
--- /dev/null
+++ b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+QtObject {
+ Component.onCompleted: {
+ var t = tp.time;
+ tp.time = t;
+ }
+}
diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
index 8150241e4a..0576650d01 100644
--- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
+++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
@@ -46,6 +46,15 @@
#include <QFont>
#include "../../shared/util.h"
+// Copied from tst_qdatetime.cpp
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+# include <time.h>
+# if defined(Q_OS_WINRT)
+# define tzset()
+# endif
+#endif
+
class tst_qqmlqt : public QQmlDataTest
{
Q_OBJECT
@@ -87,11 +96,15 @@ private slots:
void atob();
void fontFamilies();
void quit();
+ void exit();
void resolvedUrl();
void later_data();
void later();
void qtObjectContents();
+ void timeRoundtrip_data();
+ void timeRoundtrip();
+
private:
QQmlEngine engine;
};
@@ -872,8 +885,6 @@ void tst_qqmlqt::dateTimeFormattingVariants_data()
QTime time(11, 16, 39, 755);
temporary = QDateTime(QDate(1970,1,1), time);
- QTest::newRow("formatDate, qtime") << "formatDate" << QVariant::fromValue(time) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy"));
- QTest::newRow("formatDateTime, qtime") << "formatDateTime" << QVariant::fromValue(time) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a"));
QTest::newRow("formatTime, qtime") << "formatTime" << QVariant::fromValue(time) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
QDate date(2011,5,31);
@@ -980,6 +991,20 @@ void tst_qqmlqt::quit()
delete object;
}
+void tst_qqmlqt::exit()
+{
+ QQmlComponent component(&engine, testFileUrl("exit.qml"));
+
+ QSignalSpy spy(&engine, &QQmlEngine::exit);
+ QObject *object = component.create();
+ QVERIFY(object != Q_NULLPTR);
+ QCOMPARE(spy.count(), 1);
+ QList<QVariant> arguments = spy.takeFirst();
+ QVERIFY(arguments.at(0).toInt() == object->property("returnCode").toInt());
+
+ delete object;
+}
+
void tst_qqmlqt::resolvedUrl()
{
QQmlComponent component(&engine, testFileUrl("resolvedUrl.qml"));
@@ -1139,6 +1164,104 @@ void tst_qqmlqt::qtObjectContents()
delete object;
}
+class TimeProvider: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged)
+
+public:
+ TimeProvider(const QTime &t)
+ : m_getTime(t)
+ {}
+
+ QTime time() const { return m_getTime; }
+ void setTime(const QTime &t) { m_putTime = t; emit timeChanged(); }
+
+signals:
+ void timeChanged();
+
+public:
+ QTime m_getTime, m_putTime;
+};
+
+class TimeZoneSwitch
+{
+public:
+ TimeZoneSwitch(const char *newZone)
+ : doChangeZone(qstrcmp(newZone, "localtime") == 0)
+ {
+ if (!doChangeZone)
+ return;
+
+ hadOldZone = qEnvironmentVariableIsSet("TZ");
+ if (hadOldZone) {
+ oldZone = qgetenv("TZ");
+ }
+ qputenv("TZ", newZone);
+ tzset();
+ }
+
+ ~TimeZoneSwitch()
+ {
+ if (!doChangeZone)
+ return;
+
+ if (hadOldZone)
+ qputenv("TZ", oldZone);
+ else
+ qunsetenv("TZ");
+ tzset();
+ }
+
+private:
+ bool doChangeZone;
+ bool hadOldZone;
+ QByteArray oldZone;
+};
+
+void tst_qqmlqt::timeRoundtrip_data()
+{
+ QTest::addColumn<QTime>("time");
+
+ // Local timezone:
+ QTest::newRow("localtime") << QTime(0, 0, 0);
+
+ // No DST:
+ QTest::newRow("UTC") << QTime(0, 0, 0);
+ QTest::newRow("Europe/Amsterdam") << QTime(1, 0, 0);
+ QTest::newRow("Asia/Jakarta") << QTime(7, 0, 0);
+
+ // DST:
+ QTest::newRow("Namibia/Windhoek") << QTime(1, 0, 0);
+ QTest::newRow("Australia/Adelaide") << QTime(10, 0, 0);
+ QTest::newRow("Australia/Hobart") << QTime(10, 0, 0);
+ QTest::newRow("Pacific/Auckland") << QTime(12, 0, 0);
+ QTest::newRow("Pacific/Samoa") << QTime(13, 0, 0);
+}
+
+void tst_qqmlqt::timeRoundtrip()
+{
+#ifdef Q_OS_WIN
+ QSKIP("On Windows, the DateObject doesn't handle DST transitions correctly when the timezone is not localtime."); // I.e.: for this test.
+#endif
+
+ TimeZoneSwitch tzs(QTest::currentDataTag());
+ QFETCH(QTime, time);
+
+ TimeProvider tp(time);
+
+ QQmlEngine eng;
+ eng.rootContext()->setContextProperty(QLatin1String("tp"), &tp);
+ QQmlComponent component(&eng, testFileUrl("timeRoundtrip.qml"));
+ QObject *obj = component.create();
+ QVERIFY(obj != 0);
+
+ // QML reads m_getTime and saves the result as m_putTime; this should come out the same, without
+ // any perturbation (e.g. by DST effects) from converting from QTime to V4's Date and back
+ // again.
+ QCOMPARE(tp.m_getTime, tp.m_putTime);
+}
+
QTEST_MAIN(tst_qqmlqt)
#include "tst_qqmlqt.moc"
diff --git a/tests/auto/qml/qqmlsqldatabase/data/nullvalues.js b/tests/auto/qml/qqmlsqldatabase/data/nullvalues.js
new file mode 100644
index 0000000000..322a7aea03
--- /dev/null
+++ b/tests/auto/qml/qqmlsqldatabase/data/nullvalues.js
@@ -0,0 +1,24 @@
+.import QtQuick.LocalStorage 2.0 as Sql
+
+function test() {
+ var db = Sql.LocalStorage.openDatabaseSync("QmlTestDB-nullvalues", "", "Test database from Qt autotests", 1000000);
+ var r="transaction_not_finished";
+
+ db.transaction(
+ function(tx) {
+ tx.executeSql('CREATE TABLE IF NOT EXISTS NullValues(salutation TEXT, salutee TEXT)');
+ tx.executeSql('INSERT INTO NullValues VALUES(?, ?)', [ 'hello', null ]);
+ var firstRow = tx.executeSql("SELECT * FROM NullValues").rows.item(0);
+ if (firstRow.salutation !== "hello")
+ return
+ if (firstRow.salutee === "") {
+ r = "wrong_data_type"
+ return
+ }
+ if (firstRow.salutee === null)
+ r = "passed";
+ }
+ );
+
+ return r;
+}
diff --git a/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp b/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp
index b1e5cc4e7a..e16bfb08a2 100644
--- a/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp
+++ b/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp
@@ -122,7 +122,7 @@ void tst_qqmlsqldatabase::checkDatabasePath()
QVERIFY(engine->offlineStoragePath().contains("OfflineStorage"));
}
-static const int total_databases_created_by_tests = 12;
+static const int total_databases_created_by_tests = 13;
void tst_qqmlsqldatabase::testQml_data()
{
QTest::addColumn<QString>("jsfile"); // The input file
@@ -144,6 +144,7 @@ void tst_qqmlsqldatabase::testQml_data()
QTest::newRow("error-outsidetransaction") << "error-outsidetransaction.js"; // reuse above
QTest::newRow("reopen1") << "reopen1.js";
QTest::newRow("reopen2") << "reopen2.js"; // re-uses above DB
+ QTest::newRow("null-values") << "nullvalues.js";
// If you add a test, you should usually use a new database in the
// test - in which case increment total_databases_created_by_tests above.
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index bf255ba6a0..1fc803a395 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -31,7 +31,6 @@
#include <QQmlComponent>
#include <QTranslator>
#include <QQmlContext>
-#include <private/qqmlcompiler_p.h>
#include <private/qqmlengine_p.h>
#include "../../shared/util.h"
@@ -77,15 +76,15 @@ void tst_qqmltranslation::translation()
QQmlContext *context = qmlContext(object);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine());
QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl());
- QQmlCompiledData *cdata = typeData->compiledData();
- QVERIFY(cdata);
+ QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit();
+ QVERIFY(compilationUnit);
QSet<QString> compiledTranslations;
compiledTranslations << QStringLiteral("basic")
<< QStringLiteral("disambiguation")
<< QStringLiteral("singular") << QStringLiteral("plural");
- const QV4::CompiledData::Unit *unit = cdata->compilationUnit->data;
+ const QV4::CompiledData::Unit *unit = compilationUnit->data;
const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
@@ -96,7 +95,7 @@ void tst_qqmltranslation::translation()
if (expectCompiledTranslation) {
if (binding->type != QV4::CompiledData::Binding::Type_Translation)
qDebug() << "binding for property" << propertyName << "is not a compiled translation";
- QCOMPARE(binding->type, quint32(QV4::CompiledData::Binding::Type_Translation));
+ QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_Translation));
} else {
if (binding->type == QV4::CompiledData::Binding::Type_Translation)
qDebug() << "binding for property" << propertyName << "is not supposed to be a compiled translation";
@@ -137,10 +136,10 @@ void tst_qqmltranslation::idTranslation()
QQmlContext *context = qmlContext(object);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine());
QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl());
- QQmlCompiledData *cdata = typeData->compiledData();
- QVERIFY(cdata);
+ QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit();
+ QVERIFY(compilationUnit);
- const QV4::CompiledData::Unit *unit = cdata->compilationUnit->data;
+ const QV4::CompiledData::Unit *unit = compilationUnit->data;
const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
@@ -148,7 +147,7 @@ void tst_qqmltranslation::idTranslation()
if (propertyName == "idTranslation") {
if (binding->type != QV4::CompiledData::Binding::Type_TranslationById)
qDebug() << "binding for property" << propertyName << "is not a compiled translation";
- QCOMPARE(binding->type, quint32(QV4::CompiledData::Binding::Type_TranslationById));
+ QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_TranslationById));
} else {
QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation);
}
diff --git a/tests/auto/qml/qqmltypeloader/data/MyComponent.qml b/tests/auto/qml/qqmltypeloader/data/MyComponent.qml
new file mode 100644
index 0000000000..a642518199
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/MyComponent.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 100
+ height: 62
+
+ MyComponent3 {}
+
+ MyComponent2 {}
+}
+
diff --git a/tests/auto/qml/qqmltypeloader/data/MyComponent2.qml b/tests/auto/qml/qqmltypeloader/data/MyComponent2.qml
new file mode 100644
index 0000000000..02cf5cb5dd
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/MyComponent2.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 100
+ height: 62
+}
+
diff --git a/tests/auto/qml/qqmltypeloader/data/MyComponent3.qml b/tests/auto/qml/qqmltypeloader/data/MyComponent3.qml
new file mode 100644
index 0000000000..ad5d569197
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/MyComponent3.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 100
+ height: 62
+
+ MyComponent4 {}
+}
+
diff --git a/tests/auto/qml/qqmltypeloader/data/trim_cache2.qml b/tests/auto/qml/qqmltypeloader/data/trim_cache2.qml
new file mode 100644
index 0000000000..326a720a87
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/trim_cache2.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Item {
+ width: 400
+ height: 400
+
+ Component.onCompleted: {
+ var component = Qt.createComponent("MyComponent.qml")
+ if (component.status == Component.Error)
+ console.log(component.errorString())
+ }
+}
+
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index ef1ea3a897..3d3a7ff725 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -32,7 +32,6 @@
#include <QtQuick/qquickitem.h>
#include <QtQml/private/qqmlengine_p.h>
#include <QtQml/private/qqmltypeloader_p.h>
-#include <QtQml/private/qqmlcompiler_p.h>
#include "../../shared/util.h"
class tst_QQMLTypeLoader : public QQmlDataTest
@@ -43,6 +42,7 @@ private slots:
void testLoadComplete();
void loadComponentSynchronously();
void trimCache();
+ void trimCache2();
};
void tst_QQMLTypeLoader::testLoadComplete()
@@ -81,10 +81,19 @@ void tst_QQMLTypeLoader::trimCache()
url.setQuery(QString::number(i));
QQmlTypeData *data = loader.getType(url);
- if (i % 5 == 0) // keep references to some of them so that they aren't trimmed
- data->compiledData()->addref();
+ // Run an event loop to receive the callback that release()es.
+ QTRY_COMPARE(data->count(), 2);
- data->release();
+ // keep references to some of them so that they aren't trimmed. References to either the
+ // QQmlTypeData or its compiledData() should prevent the trimming.
+ if (i % 10 == 0) {
+ // keep ref on data, don't add ref on data->compiledData()
+ } else if (i % 5 == 0) {
+ data->compilationUnit()->addref();
+ data->release();
+ } else {
+ data->release();
+ }
}
for (int i = 0; i < 256; ++i) {
@@ -98,6 +107,19 @@ void tst_QQMLTypeLoader::trimCache()
}
}
+void tst_QQMLTypeLoader::trimCache2()
+{
+ QQuickView *window = new QQuickView();
+ window->setSource(testFileUrl("trim_cache2.qml"));
+ QQmlTypeLoader &loader = QQmlEnginePrivate::get(window->engine())->typeLoader;
+ // in theory if gc has already run this could be false
+ // QCOMPARE(loader.isTypeLoaded(testFileUrl("MyComponent2.qml")), true);
+ window->engine()->collectGarbage();
+ QTest::qWait(1); // force event loop
+ window->engine()->trimComponentCache();
+ QCOMPARE(loader.isTypeLoaded(testFileUrl("MyComponent2.qml")), false);
+}
+
QTEST_MAIN(tst_QQMLTypeLoader)
#include "tst_qqmltypeloader.moc"
diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_read.qml b/tests/auto/qml/qqmlvaluetypes/data/color_read.qml
index bc92b1e5f9..73d2b921a7 100644
--- a/tests/auto/qml/qqmlvaluetypes/data/color_read.qml
+++ b/tests/auto/qml/qqmlvaluetypes/data/color_read.qml
@@ -5,5 +5,11 @@ MyTypeObject {
property real v_g: color.g
property real v_b: color.b
property real v_a: color.a
+ property real hsv_h: color.hsvHue
+ property real hsv_s: color.hsvSaturation
+ property real hsv_v: color.hsvValue
+ property real hsl_h: color.hslHue
+ property real hsl_s: color.hslSaturation
+ property real hsl_l: color.hslLightness
property variant copy: color
}
diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml
new file mode 100644
index 0000000000..0034163bbe
--- /dev/null
+++ b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml
@@ -0,0 +1,8 @@
+import Test 1.0
+
+MyTypeObject {
+ color.hslHue: if (true) 0.43
+ color.hslSaturation: if (true) 0.74
+ color.hslLightness: if (true) 0.54
+ color.a: if (true) 0.7
+}
diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml
new file mode 100644
index 0000000000..1fc47d460e
--- /dev/null
+++ b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml
@@ -0,0 +1,8 @@
+import Test 1.0
+
+MyTypeObject {
+ color.hsvHue: if (true) 0.43
+ color.hsvSaturation: if (true) 0.77
+ color.hsvValue: if (true) 0.88
+ color.a: if (true) 0.7
+}
diff --git a/tests/auto/qml/qqmlvaluetypes/testtypes.h b/tests/auto/qml/qqmlvaluetypes/testtypes.h
index 77d723fbd4..bcfe4028c6 100644
--- a/tests/auto/qml/qqmlvaluetypes/testtypes.h
+++ b/tests/auto/qml/qqmlvaluetypes/testtypes.h
@@ -194,7 +194,7 @@ class MyOffsetValueInterceptor : public QObject, public QQmlPropertyValueInterce
Q_INTERFACES(QQmlPropertyValueInterceptor)
public:
virtual void setTarget(const QQmlProperty &p) { prop = p; }
- virtual void write(const QVariant &value) { QQmlPropertyPrivate::write(prop, value.toInt() + 13, QQmlPropertyPrivate::BypassInterceptor); }
+ virtual void write(const QVariant &value) { QQmlPropertyPrivate::write(prop, value.toInt() + 13, QQmlPropertyData::BypassInterceptor); }
private:
QQmlProperty prop;
@@ -215,7 +215,7 @@ public:
c.getRgb(&r, &g, &b, &a);
c.setRgb(a, b, g, r);
- QQmlPropertyPrivate::write(prop, c, QQmlPropertyPrivate::BypassInterceptor);
+ QQmlPropertyPrivate::write(prop, c, QQmlPropertyData::BypassInterceptor);
}
private:
@@ -230,7 +230,7 @@ public:
virtual void setTarget(const QQmlProperty &p) { prop = p; }
virtual void write(const QVariant &)
{
- QQmlPropertyPrivate::write(prop, 0.0f, QQmlPropertyPrivate::BypassInterceptor);
+ QQmlPropertyPrivate::write(prop, 0.0f, QQmlPropertyData::BypassInterceptor);
}
private:
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index f506d0f53a..803bad197a 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -907,6 +907,15 @@ void tst_qqmlvaluetypes::color()
QCOMPARE((float)object->property("v_g").toDouble(), (float)0.88);
QCOMPARE((float)object->property("v_b").toDouble(), (float)0.6);
QCOMPARE((float)object->property("v_a").toDouble(), (float)0.34);
+
+ QCOMPARE(qRound(object->property("hsv_h").toDouble() * 100), 43);
+ QCOMPARE(qRound(object->property("hsv_s").toDouble() * 100), 77);
+ QCOMPARE(qRound(object->property("hsv_v").toDouble() * 100), 88);
+
+ QCOMPARE(qRound(object->property("hsl_h").toDouble() * 100), 43);
+ QCOMPARE(qRound(object->property("hsl_s").toDouble() * 100), 74);
+ QCOMPARE(qRound(object->property("hsl_l").toDouble() * 100), 54);
+
QColor comparison;
comparison.setRedF(0.2);
comparison.setGreenF(0.88);
@@ -933,6 +942,30 @@ void tst_qqmlvaluetypes::color()
}
{
+ QQmlComponent component(&engine, testFileUrl("color_write_HSV.qml"));
+ MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QColor newColor;
+ newColor.setHsvF(0.43, 0.77, 0.88, 0.7);
+ QCOMPARE(object->color(), newColor);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("color_write_HSL.qml"));
+ MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QColor newColor;
+ newColor.setHslF(0.43, 0.74, 0.54, 0.7);
+ QCOMPARE(object->color(), newColor);
+
+ delete object;
+ }
+
+ {
QQmlComponent component(&engine, testFileUrl("color_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
QVERIFY(object != 0);
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect
new file mode 100644
index 0000000000..8c13977462
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect
@@ -0,0 +1,17 @@
+PATCH /qqmlxmlhttprequest.cpp HTTP/1.1
+Accept-Language: en-US
+If-Match: "ETagNumber"
+Content-Type: application/example
+Content-Length: 247
+Connection: Keep-Alive
+Accept-Encoding: gzip, deflate
+User-Agent: Mozilla/5.0
+Host: {{ServerHostUrl}}
+
+--- a/qqmlxmlhttprequest.cpp
++++ b/qqmlxmlhttprequest.cpp
+@@ -1238,11 +1238,13 @@
+- } else if (m_method == QLatin1String("OPTIONS")) {
++ } else if (m_method == QLatin1String("OPTIONS") ||
++ (m_method == QLatin1String("PATCH"))) {
+
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml
new file mode 100644
index 0000000000..2abf1c60a8
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Canonical Limited and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+QtObject {
+ property string url
+
+ property bool dataOK: false
+ property bool headerOK: false
+
+ Component.onCompleted: {
+ var x = new XMLHttpRequest;
+ x.open("PATCH", url);
+ x.setRequestHeader("Accept-Language","en-US");
+ x.setRequestHeader("If-Match","\"ETagNumber\"");
+
+ // Test to the end
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.HEADERS_RECEIVED) {
+ headerOK = (x.getResponseHeader("Content-Location") == "/qqmlxmlhttprequest.cpp") &&
+ (x.getResponseHeader("ETag") == "\"ETagNumber\"") &&
+ (x.status == "204");
+ } else if (x.readyState == XMLHttpRequest.DONE) {
+ dataOK = (x.responseText === "");
+ }
+ }
+
+ var body = "--- a/qqmlxmlhttprequest.cpp\n" +
+ "+++ b/qqmlxmlhttprequest.cpp\n" +
+ "@@ -1238,11 +1238,13 @@\n" +
+ "- } else if (m_method == QLatin1String(\"OPTIONS\")) {\n" +
+ "+ } else if (m_method == QLatin1String(\"OPTIONS\") ||\n" +
+ "+ (m_method == QLatin1String(\"PATCH\"))) {\n"
+
+ x.send(body);
+ }
+}
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply
new file mode 100644
index 0000000000..cece41ced1
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply
@@ -0,0 +1,3 @@
+HTTP/1.1 204 No Content
+Content-Location: /qqmlxmlhttprequest.cpp
+ETag: "ETagNumber"
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 425e12677f..1ce07ecdab 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -71,6 +71,7 @@ private slots:
void send_withdata_data();
void send_options();
void send_options_data();
+ void send_patch();
void abort();
void abort_unsent();
void abort_opened();
@@ -639,6 +640,26 @@ void tst_qqmlxmlhttprequest::send_options_data()
QTest::newRow("OPTIONS (with data)") << "testdocument.html" << "send_data.10.expect" << "send_data.9.qml" << "send_data.2.reply";
}
+void tst_qqmlxmlhttprequest::send_patch()
+{
+ TestHTTPServer server;
+ QVERIFY2(server.listen(), qPrintable(server.errorString()));
+ QVERIFY(server.wait(testFileUrl("send_patch.expect"),
+ testFileUrl("send_patch.reply"),
+ // the content of response file will be ignored due to 204 status code
+ testFileUrl("testdocument.html")));
+
+ QQmlComponent component(&engine, testFileUrl("send_patch.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
+ object->setProperty("url", server.urlString("/qqmlxmlhttprequest.cpp"));
+ component.completeCreate();
+
+ QTRY_VERIFY(object->property("dataOK").toBool());
+ QTRY_VERIFY(object->property("headerOK").toBool());
+}
+
+
// Test abort() has no effect in unsent state
void tst_qqmlxmlhttprequest::abort_unsent()
{
diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
index f3ba3e8971..f19e82032a 100644
--- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
+++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
@@ -56,6 +56,7 @@ public slots:
}
private slots:
+ void initTestCase();
void basicProperties();
void showFiles();
void resetFiltering();
@@ -97,6 +98,15 @@ void tst_qquickfolderlistmodel::checkNoErrors(const QQmlComponent& component)
QVERIFY(!component.isError());
}
+void tst_qquickfolderlistmodel::initTestCase()
+{
+ // The tests rely on a fixed number of files in the directory with the qml files
+ // (the data dir), so disable the disk cache to avoid creating .qmlc files and
+ // confusing the test.
+ qputenv("QML_DISABLE_DISK_CACHE", "1");
+ QQmlDataTest::initTestCase();
+}
+
void tst_qquickfolderlistmodel::basicProperties()
{
QQmlComponent component(&engine, testFileUrl("basic.qml"));
diff --git a/tests/auto/qml/qv4mm/qv4mm.pro b/tests/auto/qml/qv4mm/qv4mm.pro
new file mode 100644
index 0000000000..d9b749af4a
--- /dev/null
+++ b/tests/auto/qml/qv4mm/qv4mm.pro
@@ -0,0 +1,8 @@
+CONFIG += testcase
+TARGET = tst_qv4mm
+osx:CONFIG -= app_bundle
+
+SOURCES += tst_qv4mm.cpp
+
+QT += qml qml-private testlib
+
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
new file mode 100644
index 0000000000..d4ba363d00
--- /dev/null
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 basysKom GmbH.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QQmlEngine>
+#include <private/qv4mm_p.h>
+
+class tst_qv4mm : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void gcStats();
+ void tweaks();
+};
+
+void tst_qv4mm::gcStats()
+{
+ qputenv(QV4_MM_STATS, "1");
+ QQmlEngine engine;
+ engine.collectGarbage();
+}
+
+void tst_qv4mm::tweaks()
+{
+ qputenv(QV4_MM_MAXBLOCK_SHIFT, "5");
+ qputenv(QV4_MM_MAX_CHUNK_SIZE, "65536");
+ QQmlEngine engine;
+}
+
+QTEST_MAIN(tst_qv4mm)
+
+#include "tst_qv4mm.moc"
diff --git a/tests/auto/qmldevtools/compile/compile.pro b/tests/auto/qmldevtools/compile/compile.pro
index 54430eb668..832700698f 100644
--- a/tests/auto/qmldevtools/compile/compile.pro
+++ b/tests/auto/qmldevtools/compile/compile.pro
@@ -5,7 +5,7 @@ force_bootstrap {
!build_pass: CONFIG += release
} else {
QT = core
- !build_pass:contains(QT_CONFIG, debug_and_release): CONFIG += release
+ !build_pass:qtConfig(debug_and_release): CONFIG += release
}
QT += qmldevtools-private
macx:CONFIG -= app_bundle
diff --git a/tests/auto/qmldevtools/qmldevtools.pro b/tests/auto/qmldevtools/qmldevtools.pro
index a0ca1bff87..a9352d4df3 100644
--- a/tests/auto/qmldevtools/qmldevtools.pro
+++ b/tests/auto/qmldevtools/qmldevtools.pro
@@ -1,6 +1,4 @@
TEMPLATE = subdirs
-contains(QT_CONFIG, private_tests) {
- SUBDIRS += \
- compile
-}
+qtConfig(private_tests): \
+ SUBDIRS += compile
diff --git a/tests/auto/qmltest/animators/Box.qml b/tests/auto/qmltest-blacklist/animators/Box.qml
index 88a74e8a54..88a74e8a54 100644
--- a/tests/auto/qmltest/animators/Box.qml
+++ b/tests/auto/qmltest-blacklist/animators/Box.qml
diff --git a/tests/auto/qmltest/animators/tst_behavior.qml b/tests/auto/qmltest-blacklist/animators/tst_behavior.qml
index 1a17c0528e..1a17c0528e 100644
--- a/tests/auto/qmltest/animators/tst_behavior.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_behavior.qml
diff --git a/tests/auto/qmltest/animators/tst_mixed.qml b/tests/auto/qmltest-blacklist/animators/tst_mixed.qml
index 5ad698254f..5ad698254f 100644
--- a/tests/auto/qmltest/animators/tst_mixed.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_mixed.qml
diff --git a/tests/auto/qmltest/animators/tst_mixedparallel.qml b/tests/auto/qmltest-blacklist/animators/tst_mixedparallel.qml
index 236f250306..236f250306 100644
--- a/tests/auto/qmltest/animators/tst_mixedparallel.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_mixedparallel.qml
diff --git a/tests/auto/qmltest/animators/tst_mixedsequential.qml b/tests/auto/qmltest-blacklist/animators/tst_mixedsequential.qml
index 771c5f33ce..771c5f33ce 100644
--- a/tests/auto/qmltest/animators/tst_mixedsequential.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_mixedsequential.qml
diff --git a/tests/auto/qmltest/animators/tst_multiwindow.qml b/tests/auto/qmltest-blacklist/animators/tst_multiwindow.qml
index 8ea6aab9a7..8ea6aab9a7 100644
--- a/tests/auto/qmltest/animators/tst_multiwindow.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_multiwindow.qml
diff --git a/tests/auto/qmltest/animators/tst_nested.qml b/tests/auto/qmltest-blacklist/animators/tst_nested.qml
index 7f35118dda..7f35118dda 100644
--- a/tests/auto/qmltest/animators/tst_nested.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_nested.qml
diff --git a/tests/auto/qmltest/animators/tst_on.qml b/tests/auto/qmltest-blacklist/animators/tst_on.qml
index 5bcbfa2a2e..5bcbfa2a2e 100644
--- a/tests/auto/qmltest/animators/tst_on.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_on.qml
diff --git a/tests/auto/qmltest/animators/tst_opacity.qml b/tests/auto/qmltest-blacklist/animators/tst_opacity.qml
index 41d09b18c6..41d09b18c6 100644
--- a/tests/auto/qmltest/animators/tst_opacity.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_opacity.qml
diff --git a/tests/auto/qmltest/animators/tst_parallel.qml b/tests/auto/qmltest-blacklist/animators/tst_parallel.qml
index ac7acf2536..ac7acf2536 100644
--- a/tests/auto/qmltest/animators/tst_parallel.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_parallel.qml
diff --git a/tests/auto/qmltest/animators/tst_restart.qml b/tests/auto/qmltest-blacklist/animators/tst_restart.qml
index 66f395c938..66f395c938 100644
--- a/tests/auto/qmltest/animators/tst_restart.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_restart.qml
diff --git a/tests/auto/qmltest/animators/tst_rotation.qml b/tests/auto/qmltest-blacklist/animators/tst_rotation.qml
index b181912299..b181912299 100644
--- a/tests/auto/qmltest/animators/tst_rotation.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_rotation.qml
diff --git a/tests/auto/qmltest/animators/tst_scale.qml b/tests/auto/qmltest-blacklist/animators/tst_scale.qml
index 0e1abcf729..0e1abcf729 100644
--- a/tests/auto/qmltest/animators/tst_scale.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_scale.qml
diff --git a/tests/auto/qmltest/animators/tst_sequential.qml b/tests/auto/qmltest-blacklist/animators/tst_sequential.qml
index e8b4e98917..e8b4e98917 100644
--- a/tests/auto/qmltest/animators/tst_sequential.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_sequential.qml
diff --git a/tests/auto/qmltest/animators/tst_targetdestroyed.qml b/tests/auto/qmltest-blacklist/animators/tst_targetdestroyed.qml
index 588777ce1c..588777ce1c 100644
--- a/tests/auto/qmltest/animators/tst_targetdestroyed.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_targetdestroyed.qml
diff --git a/tests/auto/qmltest/animators/tst_transformorigin.qml b/tests/auto/qmltest-blacklist/animators/tst_transformorigin.qml
index e9c8a16598..e9c8a16598 100644
--- a/tests/auto/qmltest/animators/tst_transformorigin.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_transformorigin.qml
diff --git a/tests/auto/qmltest/animators/tst_transition.qml b/tests/auto/qmltest-blacklist/animators/tst_transition.qml
index 1e95ed56c0..1e95ed56c0 100644
--- a/tests/auto/qmltest/animators/tst_transition.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_transition.qml
diff --git a/tests/auto/qmltest/animators/tst_x.qml b/tests/auto/qmltest-blacklist/animators/tst_x.qml
index 7a89bf564c..7a89bf564c 100644
--- a/tests/auto/qmltest/animators/tst_x.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_x.qml
diff --git a/tests/auto/qmltest/animators/tst_y.qml b/tests/auto/qmltest-blacklist/animators/tst_y.qml
index abb73db7c1..abb73db7c1 100644
--- a/tests/auto/qmltest/animators/tst_y.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_y.qml
diff --git a/tests/auto/qmltest/animators/tst_zeroduration.qml b/tests/auto/qmltest-blacklist/animators/tst_zeroduration.qml
index 83ce235f42..83ce235f42 100644
--- a/tests/auto/qmltest/animators/tst_zeroduration.qml
+++ b/tests/auto/qmltest-blacklist/animators/tst_zeroduration.qml
diff --git a/tests/auto/qmltest/item/tst_layerInPositioner.qml b/tests/auto/qmltest-blacklist/item/tst_layerInPositioner.qml
index da081fb5fe..da081fb5fe 100644
--- a/tests/auto/qmltest/item/tst_layerInPositioner.qml
+++ b/tests/auto/qmltest-blacklist/item/tst_layerInPositioner.qml
diff --git a/tests/auto/qmltest/BLACKLIST b/tests/auto/qmltest/BLACKLIST
index cd8b1181e0..c38347b42a 100644
--- a/tests/auto/qmltest/BLACKLIST
+++ b/tests/auto/qmltest/BLACKLIST
@@ -3,3 +3,9 @@
*
[SelfTests::test_blacklistWithData:test2]
*
+[shadersource-dynamic-sourceobject::test_endresult]
+linux
+[tst_grabImage::test_equals]
+linux
+[ListView::test_listInteractiveCurrentIndexEnforce]
+linux
diff --git a/tests/auto/qmltest/events/tst_events.qml b/tests/auto/qmltest/events/tst_events.qml
index e655c26c7d..d9868a316c 100644
--- a/tests/auto/qmltest/events/tst_events.qml
+++ b/tests/auto/qmltest/events/tst_events.qml
@@ -27,6 +27,7 @@
****************************************************************************/
import QtQuick 2.0
+import QtQuick.Window 2.0
import QtTest 1.1
Rectangle {
@@ -56,6 +57,16 @@ Rectangle {
signalName: "doubleClickSignalHelper"
}
+ Window {
+ id: sub
+ visible: true
+ property bool clicked: false
+ MouseArea {
+ anchors.fill: parent
+ onClicked: sub.clicked = true
+ }
+ }
+
MouseArea {
anchors.fill: parent
onClicked: {
@@ -89,6 +100,11 @@ Rectangle {
tryCompare(top, "mouseHasBeenClicked", true, 10000)
}
+ function test_mouse_click_subwindow() {
+ mouseClick(sub)
+ tryCompare(sub, "clicked", true, 10000)
+ }
+
function test_mouse_doubleclick() {
doubleClickSpy.clear()
mouseDoubleClickSequence(top, 25, 30)
diff --git a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
index 743dad70eb..022e98a202 100644
--- a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
+++ b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
@@ -102,7 +102,7 @@ Item {
property int callCount: 0;
property bool ready: false;
function handleGrab(result) {
- if (!result.saveToFile("image.png"))
+ if (!result.saveToFile("itemgrabber/image.png"))
print("Error: Failed to save image to disk...");
source = "image.png";
ready = true;
@@ -116,7 +116,7 @@ Item {
y: 0
property bool ready: false;
function handleGrab(result) {
- if (!result.saveToFile("image_small.png"))
+ if (!result.saveToFile("itemgrabber/image_small.png"))
print("Error: Failed to save image to disk...");
source = "image_small.png";
ready = true;
diff --git a/tests/auto/qmltest/listview/tst_listview.qml b/tests/auto/qmltest/listview/tst_listview.qml
index 75429c43e1..65f736f305 100644
--- a/tests/auto/qmltest/listview/tst_listview.qml
+++ b/tests/auto/qmltest/listview/tst_listview.qml
@@ -288,6 +288,7 @@ Item {
}
function test_asyncLoaderCurrentIndexChange() {
+ skip("more details in QTBUG-53780")
for (var i = 0; i < 500; i++) {
asyncLoaderCurrentIndexListView.currentIndex = 0;
asyncLoaderCurrentIndexListView.currentIndex = 1;
@@ -300,6 +301,7 @@ Item {
}
function test_asyncListViewLoader() {
+ skip("more details in QTBUG-53780")
for (var i = 0; i < 50; i++) {
wait(10);
asyncListViewLoaderView.currentIndex = 0;
@@ -318,9 +320,13 @@ Item {
function test_listInteractiveCurrentIndexEnforce() {
mousePress(listInteractiveCurrentIndexEnforce, 10, 50);
+ wait(1); // because Flickable pays attention to velocity, we need some time between movements
mouseMove(listInteractiveCurrentIndexEnforce, 10, 40);
+ wait(1);
mouseMove(listInteractiveCurrentIndexEnforce, 10, 30);
+ wait(1);
mouseMove(listInteractiveCurrentIndexEnforce, 10, 20);
+ wait(1);
mouseMove(listInteractiveCurrentIndexEnforce, 10, 10);
compare(listInteractiveCurrentIndexEnforce.interactive, false);
mouseRelease(listInteractiveCurrentIndexEnforce, 10, 10);
diff --git a/tests/auto/qmltest/qmltest.pro b/tests/auto/qmltest/qmltest.pro
index 54db7a78ab..52fd6bf9de 100644
--- a/tests/auto/qmltest/qmltest.pro
+++ b/tests/auto/qmltest/qmltest.pro
@@ -10,5 +10,5 @@ importFiles.files = borderimage buttonclick createbenchmark events qqmlbindi
importFiles.path = .
DEPLOYMENT += importFiles
-CONFIG+=insignificant_test # QTBUG-33723
-
+# Please do not make this test insignificant again, thanks.
+# Just skip those unstable ones. See also QTBUG-33723.
diff --git a/tests/auto/qmltest/selftests/tst_tryVerify.qml b/tests/auto/qmltest/selftests/tst_tryVerify.qml
new file mode 100644
index 0000000000..6f29d8643d
--- /dev/null
+++ b/tests/auto/qmltest/selftests/tst_tryVerify.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtTest 1.1
+
+TestCase {
+ name: "tst_tryVerify"
+
+ Item {
+ id: item
+ }
+
+ QtObject {
+ id: itemContainer
+ property Item i
+ }
+
+ Timer {
+ id: timer
+ interval: 100
+ onTriggered: itemContainer.i = item
+ }
+
+ function resetTimer() {
+ itemContainer.i = null;
+ timer.restart();
+ }
+
+ function test_tryVerify() {
+ timer.start();
+ tryVerify(function(){ return itemContainer.i; }, 200, "string");
+ compare(itemContainer.i, item);
+
+ resetTimer();
+ tryVerify(function(){ return itemContainer.i; }, 200);
+ compare(itemContainer.i, item);
+
+ resetTimer();
+ tryVerify(function(){ return itemContainer.i; });
+ compare(itemContainer.i, item);
+
+ resetTimer();
+ tryVerify(function(){ return !itemContainer.i; }, 0, "string");
+ verify(!itemContainer.i);
+ }
+}
diff --git a/tests/auto/qmltest/statemachine/tst_signaltransition.qml b/tests/auto/qmltest/statemachine/tst_signaltransition.qml
new file mode 100644
index 0000000000..0e35207670
--- /dev/null
+++ b/tests/auto/qmltest/statemachine/tst_signaltransition.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Copyright (C) 2016 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtTest 1.1
+import QtQml.StateMachine 1.0
+
+TestCase {
+ id: testCase
+ StateMachine {
+ id: machine
+ initialState: startState
+ State {
+ id: startState
+ SignalTransition {
+ id: signalTrans
+ signal: testCase.onMysignal
+ targetState: finalState
+ }
+ }
+ FinalState {
+ id: finalState
+ }
+ }
+
+ SignalSpy {
+ id: finalStateActive
+ target: finalState
+ signalName: "activeChanged"
+ }
+
+ signal mysignal()
+
+ name: "testSignalTransition"
+ function test_signalTransition()
+ {
+ // Start statemachine, should not have reached finalState yet.
+ machine.start()
+ tryCompare(finalStateActive, "count", 0)
+ tryCompare(machine, "running", true)
+
+ testCase.mysignal()
+ tryCompare(finalStateActive, "count", 1)
+ tryCompare(machine, "running", false)
+ }
+}
diff --git a/tests/auto/qmltest/text/tst_text.qml b/tests/auto/qmltest/text/tst_text.qml
index 691a4838cd..d2899cfb74 100644
--- a/tests/auto/qmltest/text/tst_text.qml
+++ b/tests/auto/qmltest/text/tst_text.qml
@@ -118,9 +118,10 @@ Item {
compare(txtlinecount.lineCount, 2)
txtlinecount.text = txtlinecount.third;
compare(txtlinecount.lineCount, 3)
+ console.log(txtlinecount.width)
txtlinecount.text = txtlinecount.first;
compare(txtlinecount.lineCount, 1)
- txtlinecount.width = 50;
+ txtlinecount.width = 44;
compare(txtlinecount.lineCount, 3)
}
function test_linecounts() {
diff --git a/tests/auto/qmltest/textinput/tst_textinput.qml b/tests/auto/qmltest/textinput/tst_textinput.qml
index 62659a2188..51868ec8aa 100644
--- a/tests/auto/qmltest/textinput/tst_textinput.qml
+++ b/tests/auto/qmltest/textinput/tst_textinput.qml
@@ -277,6 +277,7 @@ Item {
}
function test_doublevalidators(row) {
+ txtdoublevalidator.validator.locale = "C"
compare(txtdoublevalidator.validator.top, 2.0)
compare(txtdoublevalidator.validator.bottom, 1.0)
txtdoublevalidator.text = row.testnumber;
diff --git a/tests/auto/qmltest/window/tst_clickwindow.qml b/tests/auto/qmltest/window/tst_clickwindow.qml
index bbe091990c..c3577be4dc 100644
--- a/tests/auto/qmltest/window/tst_clickwindow.qml
+++ b/tests/auto/qmltest/window/tst_clickwindow.qml
@@ -75,6 +75,8 @@ Item {
when: windowShown
function test_clickBothWindows() {
+ if (Qt.platform.os === "linux" || Qt.platform.os === "windows")
+ skip("more details in QTBUG-53785")
mouseClick(ma, 20, 20);
verify(ma.everClicked);
mouseClick(ma2, 20, 20);
diff --git a/tests/auto/quick/drawingmodes/data/DrawingModes.qml b/tests/auto/quick/drawingmodes/data/DrawingModes.qml
new file mode 100644
index 0000000000..4211f247f8
--- /dev/null
+++ b/tests/auto/quick/drawingmodes/data/DrawingModes.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Test 1.0
+
+Rectangle {
+ id: root
+
+ width: 200
+ height: 200
+ color: "black"
+
+ DrawingModeItem {
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/quick/drawingmodes/drawingmodes.pro b/tests/auto/quick/drawingmodes/drawingmodes.pro
new file mode 100644
index 0000000000..ff5383b501
--- /dev/null
+++ b/tests/auto/quick/drawingmodes/drawingmodes.pro
@@ -0,0 +1,17 @@
+CONFIG += testcase
+TARGET = tst_drawingmodes
+SOURCES += tst_drawingmodes.cpp
+
+macos:CONFIG -= app_bundle
+
+TESTDATA = data/*
+
+include(../../shared/util.pri)
+
+CONFIG += parallel_test
+QT += gui qml quick testlib
+
+OTHER_FILES += \
+ data/DrawingModes.qml
+
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp
new file mode 100644
index 0000000000..d4065e3d38
--- /dev/null
+++ b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickview.h>
+#include <QtQuick/qsgnode.h>
+#include <QtQuick/qsggeometry.h>
+#include <QtQuick/qsgflatcolormaterial.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qopenglcontext.h>
+
+#include "../../shared/util.h"
+
+class tst_drawingmodes : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_drawingmodes();
+
+ bool hasPixelAround(const QImage &fb, int centerX, int centerY);
+ QImage runTest(const QString &fileName)
+ {
+ QQuickView view(&outerWindow);
+ view.setResizeMode(QQuickView::SizeViewToRootObject);
+ view.setSource(testFileUrl(fileName));
+ view.setVisible(true);
+ QTest::qWaitForWindowExposed(&view);
+ return view.grabWindow();
+ }
+
+ //It is important for platforms that only are able to show fullscreen windows
+ //to have a container for the window that is painted on.
+ QQuickWindow outerWindow;
+ const QRgb black;
+ const QRgb red;
+
+private slots:
+ void points();
+ void lines();
+ void lineStrip();
+ void lineLoop();
+ void triangles();
+ void triangleStrip();
+ void triangleFan();
+};
+
+class DrawingModeItem : public QQuickItem
+{
+ Q_OBJECT
+public:
+ static GLenum drawingMode;
+
+ DrawingModeItem() : first(QSGGeometry::defaultAttributes_Point2D(), 5),
+ second(QSGGeometry::defaultAttributes_Point2D(), 5)
+ {
+ setFlag(ItemHasContents, true);
+ material.setColor(Qt::red);
+ }
+
+protected:
+ QSGGeometry first;
+ QSGGeometry second;
+ QSGFlatColorMaterial material;
+
+ virtual QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
+ {
+ if (!node) {
+ QRect bounds(0, 0, 200, 200);
+ first.setDrawingMode(drawingMode);
+ second.setDrawingMode(drawingMode);
+
+ QSGGeometry::Point2D *v = first.vertexDataAsPoint2D();
+ v[0].set(bounds.width() * 2 / 8, bounds.height() / 2);
+ v[1].set(bounds.width() / 8, bounds.height() / 4);
+ v[2].set(bounds.width() * 3 / 8, bounds.height() / 4);
+ v[3].set(bounds.width() * 3 / 8, bounds.height() * 3 / 4);
+ v[4].set(bounds.width() / 8, bounds.height() * 3 / 4);
+
+ v = second.vertexDataAsPoint2D();
+ v[0].set(bounds.width() * 6 / 8, bounds.height() / 2);
+ v[1].set(bounds.width() * 5 / 8, bounds.height() / 4);
+ v[2].set(bounds.width() * 7 / 8, bounds.height() / 4);
+ v[3].set(bounds.width() * 7 / 8, bounds.height() * 3 / 4);
+ v[4].set(bounds.width() * 5 / 8, bounds.height() * 3 / 4);
+
+ node = new QSGNode;
+ QSGGeometryNode *child = new QSGGeometryNode;
+ child->setGeometry(&first);
+ child->setMaterial(&material);
+ node->appendChildNode(child);
+ child = new QSGGeometryNode;
+ child->setGeometry(&second);
+ child->setMaterial(&material);
+ node->appendChildNode(child);
+ }
+ return node;
+ }
+};
+
+GLenum DrawingModeItem::drawingMode;
+
+bool tst_drawingmodes::hasPixelAround(const QImage &fb, int centerX, int centerY) {
+ for (int x = centerX - 2; x <= centerX + 2; ++x) {
+ for (int y = centerY - 2; y <= centerY + 2; ++y) {
+ if (fb.pixel(x, y) == red)
+ return true;
+ }
+ }
+ return false;
+}
+
+tst_drawingmodes::tst_drawingmodes() : black(qRgb(0, 0, 0)), red(qRgb(0xff, 0, 0))
+{
+ qmlRegisterType<DrawingModeItem>("Test", 1, 0, "DrawingModeItem");
+ outerWindow.showNormal();
+ outerWindow.setGeometry(0,0,400,400);
+}
+
+void tst_drawingmodes::points()
+{
+ DrawingModeItem::drawingMode = GL_POINTS;
+ if (QGuiApplication::primaryScreen()->depth() < 24)
+ QSKIP("This test does not work at display depths < 24");
+
+#ifdef Q_OS_WIN
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES)
+ QSKIP("ANGLE cannot draw GL_POINTS.");
+#endif
+
+ QImage fb = runTest("DrawingModes.qml");
+
+ QVERIFY(hasPixelAround(fb, 50, 100));
+ QVERIFY(hasPixelAround(fb, 25, 50));
+ QVERIFY(hasPixelAround(fb, 75, 50));
+ QVERIFY(hasPixelAround(fb, 75, 150));
+ QVERIFY(hasPixelAround(fb, 25, 150));
+
+ QVERIFY(hasPixelAround(fb, 150, 100));
+ QVERIFY(hasPixelAround(fb, 125, 50));
+ QVERIFY(hasPixelAround(fb, 175, 50));
+ QVERIFY(hasPixelAround(fb, 175, 150));
+ QVERIFY(hasPixelAround(fb, 125, 150));
+
+ QVERIFY(!hasPixelAround(fb, 135, 70));
+ QVERIFY(!hasPixelAround(fb, 175, 100));
+ QVERIFY(!hasPixelAround(fb, 110, 140));
+ QVERIFY(!hasPixelAround(fb, 50, 50));
+ QVERIFY(!hasPixelAround(fb, 50, 150));
+ QVERIFY(!hasPixelAround(fb, 25, 100));
+ QVERIFY(!hasPixelAround(fb, 75, 100));
+ QVERIFY(!hasPixelAround(fb, 125, 100));
+ QVERIFY(!hasPixelAround(fb, 150, 50));
+ QVERIFY(!hasPixelAround(fb, 150, 150));
+ QVERIFY(!hasPixelAround(fb, 135, 130));
+ QVERIFY(!hasPixelAround(fb, 35, 130));
+}
+
+void tst_drawingmodes::lines()
+{
+ DrawingModeItem::drawingMode = GL_LINES;
+ if (QGuiApplication::primaryScreen()->depth() < 24)
+ QSKIP("This test does not work at display depths < 24");
+ QImage fb = runTest("DrawingModes.qml");
+
+ QCOMPARE(fb.width(), 200);
+ QCOMPARE(fb.height(), 200);
+
+ QVERIFY(hasPixelAround(fb, 135, 70));
+ QVERIFY(hasPixelAround(fb, 175, 100));
+ QVERIFY(!hasPixelAround(fb, 110, 140));
+ QVERIFY(!hasPixelAround(fb, 50, 50));
+ QVERIFY(!hasPixelAround(fb, 50, 150));
+
+ QVERIFY(hasPixelAround(fb, 35, 70));
+ QVERIFY(hasPixelAround(fb, 75, 100));
+ QVERIFY(!hasPixelAround(fb, 25, 100));
+ QVERIFY(!hasPixelAround(fb, 125, 100));
+ QVERIFY(!hasPixelAround(fb, 150, 50));
+ QVERIFY(!hasPixelAround(fb, 150, 150));
+ QVERIFY(!hasPixelAround(fb, 135, 130));
+ QVERIFY(!hasPixelAround(fb, 35, 130));
+}
+
+void tst_drawingmodes::lineStrip()
+{
+ DrawingModeItem::drawingMode = GL_LINE_STRIP;
+ if (QGuiApplication::primaryScreen()->depth() < 24)
+ QSKIP("This test does not work at display depths < 24");
+ QImage fb = runTest("DrawingModes.qml");
+
+ QCOMPARE(fb.width(), 200);
+ QCOMPARE(fb.height(), 200);
+
+ QVERIFY(hasPixelAround(fb, 135, 70));
+ QVERIFY(hasPixelAround(fb, 150, 50));
+ QVERIFY(hasPixelAround(fb, 175, 100));
+ QVERIFY(hasPixelAround(fb, 150, 150));
+
+ QVERIFY(hasPixelAround(fb, 35, 70));
+ QVERIFY(hasPixelAround(fb, 50, 50));
+ QVERIFY(hasPixelAround(fb, 75, 100));
+ QVERIFY(hasPixelAround(fb, 50, 150));
+
+ QVERIFY(!hasPixelAround(fb, 110, 140)); // bad line not there => line strip unbatched
+
+ QVERIFY(!hasPixelAround(fb, 25, 100));
+ QVERIFY(!hasPixelAround(fb, 125, 100));
+ QVERIFY(!hasPixelAround(fb, 135, 130));
+ QVERIFY(!hasPixelAround(fb, 35, 130));
+}
+
+void tst_drawingmodes::lineLoop()
+{
+ DrawingModeItem::drawingMode = GL_LINE_LOOP;
+ if (QGuiApplication::primaryScreen()->depth() < 24)
+ QSKIP("This test does not work at display depths < 24");
+ QImage fb = runTest("DrawingModes.qml");
+
+ QCOMPARE(fb.width(), 200);
+ QCOMPARE(fb.height(), 200);
+
+ QVERIFY(hasPixelAround(fb, 135, 70));
+ QVERIFY(hasPixelAround(fb, 135, 130));
+ QVERIFY(hasPixelAround(fb, 150, 50));
+ QVERIFY(hasPixelAround(fb, 175, 100));
+ QVERIFY(hasPixelAround(fb, 150, 150));
+
+ QVERIFY(hasPixelAround(fb, 35, 70));
+ QVERIFY(hasPixelAround(fb, 35, 130));
+ QVERIFY(hasPixelAround(fb, 50, 50));
+ QVERIFY(hasPixelAround(fb, 75, 100));
+ QVERIFY(hasPixelAround(fb, 50, 150));
+
+ QVERIFY(!hasPixelAround(fb, 110, 140)); // bad line not there => line loop unbatched
+
+ QVERIFY(!hasPixelAround(fb, 25, 100));
+ QVERIFY(!hasPixelAround(fb, 125, 100));
+}
+
+void tst_drawingmodes::triangles()
+{
+ DrawingModeItem::drawingMode = GL_TRIANGLES;
+ if (QGuiApplication::primaryScreen()->depth() < 24)
+ QSKIP("This test does not work at display depths < 24");
+ QImage fb = runTest("DrawingModes.qml");
+
+ QCOMPARE(fb.width(), 200);
+ QCOMPARE(fb.height(), 200);
+
+ QVERIFY(hasPixelAround(fb, 150, 75));
+ QVERIFY(!hasPixelAround(fb, 162, 100));
+ QVERIFY(!hasPixelAround(fb, 150, 125));
+ QVERIFY(!hasPixelAround(fb, 137, 100));
+
+ QVERIFY(!hasPixelAround(fb, 100, 125));
+
+ QVERIFY(hasPixelAround(fb, 50, 75));
+ QVERIFY(!hasPixelAround(fb, 62, 100));
+ QVERIFY(!hasPixelAround(fb, 50, 125));
+ QVERIFY(!hasPixelAround(fb, 37, 100));
+}
+
+
+void tst_drawingmodes::triangleStrip()
+{
+ DrawingModeItem::drawingMode = GL_TRIANGLE_STRIP;
+ if (QGuiApplication::primaryScreen()->depth() < 24)
+ QSKIP("This test does not work at display depths < 24");
+ QImage fb = runTest("DrawingModes.qml");
+
+ QCOMPARE(fb.width(), 200);
+ QCOMPARE(fb.height(), 200);
+
+ QVERIFY(hasPixelAround(fb, 150, 75));
+ QVERIFY(hasPixelAround(fb, 162, 100));
+ QVERIFY(hasPixelAround(fb, 150, 125));
+ QVERIFY(!hasPixelAround(fb, 137, 100));
+
+ QVERIFY(!hasPixelAround(fb, 100, 125)); // batching avoids extra triangle by duplicating vertices.
+
+ QVERIFY(hasPixelAround(fb, 50, 75));
+ QVERIFY(hasPixelAround(fb, 62, 100));
+ QVERIFY(hasPixelAround(fb, 50, 125));
+ QVERIFY(!hasPixelAround(fb, 37, 100));
+}
+
+void tst_drawingmodes::triangleFan()
+{
+ DrawingModeItem::drawingMode = GL_TRIANGLE_FAN;
+ if (QGuiApplication::primaryScreen()->depth() < 24)
+ QSKIP("This test does not work at display depths < 24");
+ QImage fb = runTest("DrawingModes.qml");
+
+ QCOMPARE(fb.width(), 200);
+ QCOMPARE(fb.height(), 200);
+
+ QVERIFY(hasPixelAround(fb, 150, 75));
+ QVERIFY(hasPixelAround(fb, 162, 100));
+ QVERIFY(hasPixelAround(fb, 150, 125));
+ QVERIFY(!hasPixelAround(fb, 137, 100));
+
+ QVERIFY(!hasPixelAround(fb, 100, 125)); // no extra triangle; triangle fan is not batched
+
+ QVERIFY(hasPixelAround(fb, 50, 75));
+ QVERIFY(hasPixelAround(fb, 62, 100));
+ QVERIFY(hasPixelAround(fb, 50, 125));
+ QVERIFY(!hasPixelAround(fb, 37, 100));
+}
+
+
+QTEST_MAIN(tst_drawingmodes)
+
+#include "tst_drawingmodes.moc"
diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp
index e25cd9535b..6c94b484ae 100644
--- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp
+++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp
@@ -51,8 +51,8 @@
#ifndef QT_NO_OPENGL
#include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h>
#include <QtQuick/private/qsgdefaultglyphnode_p.h>
-#include <QtQuick/private/qsgdefaultimagenode_p.h>
-#include <QtQuick/private/qsgdefaultrectanglenode_p.h>
+#include <QtQuick/private/qsgdefaultinternalimagenode_p.h>
+#include <QtQuick/private/qsgdefaultinternalrectanglenode_p.h>
#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
#include <QtQuick/private/qsgdistancefieldutil_p.h>
diff --git a/tests/auto/quick/qquickanimatedsprite/data/img100x100.png b/tests/auto/quick/qquickanimatedsprite/data/img100x100.png
new file mode 100644
index 0000000000..9dd1990780
--- /dev/null
+++ b/tests/auto/quick/qquickanimatedsprite/data/img100x100.png
Binary files differ
diff --git a/tests/auto/quick/qquickanimatedsprite/data/img50x50.png b/tests/auto/quick/qquickanimatedsprite/data/img50x50.png
new file mode 100644
index 0000000000..5cbb47981a
--- /dev/null
+++ b/tests/auto/quick/qquickanimatedsprite/data/img50x50.png
Binary files differ
diff --git a/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml b/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml
new file mode 100644
index 0000000000..18a8f52661
--- /dev/null
+++ b/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.4
+
+AnimatedSprite {
+ id: animatedSprite
+ source: big ? "img100x100.png" : "img50x50.png"
+ frameWidth: 100
+ frameHeight: 100
+ property bool big: true
+ MouseArea {
+ anchors.fill: parent
+ onClicked: animatedSprite.big = !animatedSprite.big
+ }
+}
diff --git a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
index 27ce46d163..820c804065 100644
--- a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
+++ b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
@@ -35,6 +35,7 @@
#include <QtGui/qopenglcontext.h>
#include <QtGui/qopenglfunctions.h>
#include <QtGui/qoffscreensurface.h>
+#include <QtQml/qqmlproperty.h>
class tst_qquickanimatedsprite : public QQmlDataTest
{
@@ -50,6 +51,7 @@ private slots:
void test_largeAnimation_data();
void test_largeAnimation();
void test_reparenting();
+ void test_changeSourceToSmallerImgKeepingBigFrameSize();
};
void tst_qquickanimatedsprite::initTestCase()
@@ -286,6 +288,43 @@ void tst_qquickanimatedsprite::test_reparenting()
QTRY_COMPARE(QQuickItemPrivate::get(sprite)->polishScheduled, false);
}
+class KillerThread : public QThread
+{
+ Q_OBJECT
+protected:
+ void run() Q_DECL_OVERRIDE {
+ sleep(3);
+ qFatal("Either the GUI or the render thread is stuck in an infinite loop.");
+ }
+};
+
+// Regression test for QTBUG-53937
+void tst_qquickanimatedsprite::test_changeSourceToSmallerImgKeepingBigFrameSize()
+{
+ QQuickView window;
+ window.setSource(testFileUrl("sourceSwitch.qml"));
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QVERIFY(window.rootObject());
+ QQuickAnimatedSprite* sprite = qobject_cast<QQuickAnimatedSprite*>(window.rootObject());
+ QVERIFY(sprite);
+
+ QQmlProperty big(sprite, "big");
+ big.write(QVariant::fromValue(false));
+
+ KillerThread *killer = new KillerThread;
+ killer->start(); // will kill us in case the GUI or render thread enters an infinite loop
+
+ QTest::qWait(50); // let it draw with the new source.
+
+ // If we reach this point it's because we didn't hit QTBUG-53937
+
+ killer->terminate();
+ killer->wait();
+ delete killer;
+}
+
QTEST_MAIN(tst_qquickanimatedsprite)
#include "tst_qquickanimatedsprite.moc"
diff --git a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
index e49f0ac462..b0fb7fcf8c 100644
--- a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
@@ -31,7 +31,9 @@ TestCase {
}
function createCanvasObject(data) {
- return component.createObject(testCase, data.properties);
+ var canvas = component.createObject(testCase, data.properties);
+ waitForRendering(canvas);
+ return canvas;
}
function comparePixel(ctx,x,y,r,g,b,a, d)
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
index 93f85107a7..565f906fb1 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
@@ -590,6 +590,7 @@ CanvasTestCase {
verify(canvas);
canvas.width = 100;
canvas.height = 100;
+ waitForRendering(canvas);
var ctx = canvas.getContext("2d");
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_image.qml b/tests/auto/quick/qquickcanvasitem/data/tst_image.qml
index 46a038a13c..1f695d7080 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_image.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_image.qml
@@ -667,6 +667,7 @@ CanvasTestCase {
var canvas2 = Qt.createQmlObject("import QtQuick 2.0; Canvas{renderTarget:Canvas.Image; renderStrategy:Canvas.Immediate}", canvas);
canvas2.width = 100;
canvas2.height = 50;
+ waitForRendering(canvas2);
var ctx2 = canvas2.getContext('2d');
ctx2.fillStyle = '#0f0';
ctx2.fillRect(0, 0, 100, 50);
diff --git a/tests/auto/quick/qquickflickable/data/contentXY.qml b/tests/auto/quick/qquickflickable/data/contentXY.qml
new file mode 100644
index 0000000000..8215976949
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/contentXY.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Flickable {
+ width: 400; height: 400
+ contentWidth: 1e11; contentHeight: 1e11
+}
diff --git a/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml b/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml
new file mode 100644
index 0000000000..07bad683ee
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Flickable {
+ property double heightRatioIs: visibleArea.heightRatio
+ property double widthRatioIs: visibleArea.widthRatio
+
+ width: 200
+ height: 200
+ contentWidth: item.width
+ contentHeight: item.height
+ topMargin: 20
+ leftMargin: 40
+
+ Item {
+ id: item
+ width: 100
+ height: 100
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index 2742f5c1e2..a03e3b8170 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -90,6 +90,8 @@ private slots:
void movementFromProgrammaticFlick();
void cleanup();
void contentSize();
+ void ratios_smallContent();
+ void contentXYNotTruncatedToInt();
private:
void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to);
@@ -1814,6 +1816,53 @@ void tst_qquickflickable::contentSize()
QCOMPARE(chspy.count(), 1);
}
+// QTBUG-53726
+void tst_qquickflickable::ratios_smallContent()
+{
+ QScopedPointer<QQuickView> window(new QQuickView);
+ window->setSource(testFileUrl("ratios_smallContent.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickViewTestUtil::centerOnScreen(window.data());
+ QQuickViewTestUtil::moveMouseAway(window.data());
+ window->setTitle(QTest::currentTestFunction());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ QQuickItem *root = window->rootObject();
+ QVERIFY(root);
+ QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root);
+ QVERIFY(obj != 0);
+
+ //doublecheck the item, as specified by contentWidth/Height, fits in the view
+ //use tryCompare to allow a bit of stabilization in component's properties
+ QTRY_COMPARE(obj->leftMargin() + obj->contentWidth() + obj->rightMargin() <= obj->width(), true);
+ QTRY_COMPARE(obj->topMargin() + obj->contentHeight() + obj->bottomMargin() <= obj->height(), true);
+
+ //the whole item fits in the flickable, heightRatio should be 1
+ QCOMPARE(obj->property("heightRatioIs").toDouble(), 1.);
+ QCOMPARE(obj->property("widthRatioIs").toDouble(), 1.);
+}
+
+// QTBUG-48018
+void tst_qquickflickable::contentXYNotTruncatedToInt()
+{
+ QScopedPointer<QQuickView> window(new QQuickView);
+ window->setSource(testFileUrl("contentXY.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickViewTestUtil::centerOnScreen(window.data());
+ QQuickViewTestUtil::moveMouseAway(window.data());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable);
+
+ flickable->setContentX(1e10);
+ flick(window.data(), QPoint(200, 100), QPoint(100, 100), 50);
+
+ // make sure we are not clipped at 2^31
+ QVERIFY(flickable->contentX() > qreal(1e10));
+}
+
QTEST_MAIN(tst_qquickflickable)
#include "tst_qquickflickable.moc"
diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
index ea988bb50d..d4922599be 100644
--- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
+++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
@@ -180,7 +180,7 @@ void tst_QQuickFramebufferObject::testThatStuffWorks()
qmlRegisterType<FBOItem>("FBOItem", 1, 0, "FBOItem");
QQuickView view;
- view.setSource(QUrl::fromLocalFile("data/testStuff.qml"));
+ view.setSource(testFileUrl("testStuff.qml"));
FBOItem *item = view.rootObject()->findChild<FBOItem *>("fbo");
@@ -224,7 +224,7 @@ void tst_QQuickFramebufferObject::testInvalidate()
qmlRegisterType<FBOItem>("FBOItem", 1, 0, "FBOItem");
QQuickView view;
- view.setSource(QUrl::fromLocalFile("data/testStuff.qml"));
+ view.setSource(testFileUrl("testStuff.qml"));
FBOItem *item = view.rootObject()->findChild<FBOItem *>("fbo");
item->setTextureFollowsItemSize(false);
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index 4b2c86697e..9fedfb21ab 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -169,6 +169,8 @@ private slots:
void childAt();
+ void ignoreButtonPressNotInAcceptedMouseButtons();
+
private:
enum PaintOrderOp {
@@ -2009,6 +2011,28 @@ void tst_qquickitem::childAt()
QVERIFY(!root->childAt(19,19));
}
+void tst_qquickitem::ignoreButtonPressNotInAcceptedMouseButtons()
+{
+ // Verify the fix for QTBUG-31861
+ TestItem item;
+ QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::NoButton));
+
+ QQuickWindow window;
+ item.setSize(QSizeF(200,100));
+ item.setParentItem(window.contentItem());
+
+ item.setAcceptedMouseButtons(Qt::LeftButton);
+ QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::LeftButton));
+
+ QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50, 50));
+ QTest::mousePress(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it's not LeftButton
+ QTest::mouseRelease(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it didn't grab the RightButton press
+ QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50));
+
+ QCOMPARE(item.pressCount, 1);
+ QCOMPARE(item.releaseCount, 1);
+}
+
QTEST_MAIN(tst_qquickitem)
#include "tst_qquickitem.moc"
diff --git a/tests/auto/quick/qquickitem2/data/layoutmirroring_window.qml b/tests/auto/quick/qquickitem2/data/layoutmirroring_window.qml
new file mode 100644
index 0000000000..3bac0716e8
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/layoutmirroring_window.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import QtQuick.Window 2.0
+
+Window {
+ LayoutMirroring.enabled: true
+ LayoutMirroring.childrenInherit: true
+}
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index de61d7aea9..7130dc4cf2 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -35,6 +35,7 @@
#include <QtGui/private/qinputmethod_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquicktextinput_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
#include <QtGui/qstylehints.h>
#include <private/qquickitem_p.h>
#include "../../shared/util.h"
@@ -87,6 +88,7 @@ private slots:
void keyNavigation_focusReason();
void keyNavigation_loop();
void layoutMirroring();
+ void layoutMirroringWindow();
void layoutMirroringIllegalParent();
void smooth();
void antialiasing();
@@ -107,6 +109,7 @@ private slots:
void childrenProperty();
void resourcesProperty();
+ void changeListener();
void transformCrash();
void implicitSize();
void qtbug_16871();
@@ -1774,11 +1777,28 @@ void tst_QQuickItem::layoutMirroring()
delete parentItem2;
}
+void tst_QQuickItem::layoutMirroringWindow()
+{
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("layoutmirroring_window.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(object.data());
+ QVERIFY(window);
+ window->show();
+
+ QQuickItemPrivate *content = QQuickItemPrivate::get(window->contentItem());
+ QCOMPARE(content->effectiveLayoutMirror, true);
+ QCOMPARE(content->inheritedLayoutMirror, true);
+ QCOMPARE(content->isMirrorImplicit, false);
+ QCOMPARE(content->inheritMirrorFromParent, true);
+ QCOMPARE(content->inheritMirrorFromItem, true);
+}
+
void tst_QQuickItem::layoutMirroringIllegalParent()
{
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }", QUrl::fromLocalFile(""));
- QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items");
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items and Windows");
QObject *object = component.create();
QVERIFY(object != 0);
}
@@ -2694,6 +2714,265 @@ void tst_QQuickItem::childrenRectBottomRightCorner()
delete window;
}
+struct TestListener : public QQuickItemChangeListener
+{
+ TestListener(bool remove = false) : remove(remove) { }
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &diff) override
+ {
+ record(item, QQuickItemPrivate::Geometry, diff);
+ }
+ void itemSiblingOrderChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::SiblingOrder);
+ }
+ void itemVisibilityChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::Visibility);
+ }
+ void itemOpacityChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::Opacity);
+ }
+ void itemRotationChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::Rotation);
+ }
+ void itemImplicitWidthChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::ImplicitWidth);
+ }
+ void itemImplicitHeightChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::ImplicitHeight);
+ }
+ void itemDestroyed(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::Destroyed);
+ }
+ void itemChildAdded(QQuickItem *item, QQuickItem *child) override
+ {
+ record(item, QQuickItemPrivate::Children, QVariant::fromValue(child));
+ }
+ void itemChildRemoved(QQuickItem *item, QQuickItem *child) override
+ {
+ record(item, QQuickItemPrivate::Children, QVariant::fromValue(child));
+ }
+ void itemParentChanged(QQuickItem *item, QQuickItem *parent) override
+ {
+ record(item, QQuickItemPrivate::Parent, QVariant::fromValue(parent));
+ }
+
+ QQuickAnchorsPrivate *anchorPrivate() override { return nullptr; }
+
+ void record(QQuickItem *item, QQuickItemPrivate::ChangeType change, const QVariant &value = QVariant())
+ {
+ changes += change;
+ values[change] = value;
+ // QTBUG-54732
+ if (remove)
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, change);
+ }
+
+ int count(QQuickItemPrivate::ChangeType change) const
+ {
+ return changes.count(change);
+ }
+
+ QVariant value(QQuickItemPrivate::ChangeType change) const
+ {
+ return values.value(change);
+ }
+
+ bool remove;
+ QList<QQuickItemPrivate::ChangeType> changes;
+ QHash<QQuickItemPrivate::ChangeType, QVariant> values;
+};
+
+void tst_QQuickItem::changeListener()
+{
+ QQuickWindow window;
+ window.show();
+ QTest::qWaitForWindowExposed(&window);
+
+ QQuickItem *item = new QQuickItem;
+ TestListener itemListener;
+ QQuickItemPrivate::get(item)->addItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff));
+
+ item->setImplicitWidth(10);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitWidth), 1);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 1);
+ QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,0)));
+
+ item->setImplicitHeight(20);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitHeight), 1);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 2);
+ QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,20)));
+
+ item->setWidth(item->width() + 30);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 3);
+ QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,30,0)));
+
+ item->setHeight(item->height() + 40);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 4);
+ QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,40)));
+
+ item->setOpacity(0.5);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Opacity), 1);
+
+ item->setRotation(90);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Rotation), 1);
+
+ item->setParentItem(window.contentItem());
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Parent), 1);
+
+ item->setVisible(false);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Visibility), 1);
+
+ QQuickItemPrivate::get(item)->removeItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff));
+
+ QQuickItem *parent = new QQuickItem(window.contentItem());
+ TestListener parentListener;
+ QQuickItemPrivate::get(parent)->addItemChangeListener(&parentListener, QQuickItemPrivate::Children);
+
+ QQuickItem *child1 = new QQuickItem;
+ QQuickItem *child2 = new QQuickItem;
+ TestListener child1Listener;
+ TestListener child2Listener;
+ QQuickItemPrivate::get(child1)->addItemChangeListener(&child1Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed);
+ QQuickItemPrivate::get(child2)->addItemChangeListener(&child2Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed);
+
+ child1->setParentItem(parent);
+ QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 1);
+ QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1));
+ QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 1);
+ QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent));
+
+ child2->setParentItem(parent);
+ QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 2);
+ QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2));
+ QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 1);
+ QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent));
+
+ child2->stackBefore(child1);
+ QCOMPARE(child1Listener.count(QQuickItemPrivate::SiblingOrder), 1);
+ QCOMPARE(child2Listener.count(QQuickItemPrivate::SiblingOrder), 1);
+
+ child1->setParentItem(nullptr);
+ QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 3);
+ QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1));
+ QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 2);
+ QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr));
+
+ delete child1;
+ QCOMPARE(child1Listener.count(QQuickItemPrivate::Destroyed), 1);
+
+ delete child2;
+ QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 4);
+ QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2));
+ QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 2);
+ QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr));
+ QCOMPARE(child2Listener.count(QQuickItemPrivate::Destroyed), 1);
+
+ QQuickItemPrivate::get(parent)->removeItemChangeListener(&parentListener, QQuickItemPrivate::Children);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // QTBUG-54732: all listeners should get invoked even if they remove themselves while iterating the listeners
+ QList<TestListener *> listeners;
+ for (int i = 0; i < 5; ++i)
+ listeners << new TestListener(true);
+
+ // itemVisibilityChanged x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Visibility);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setVisible(false);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Visibility), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemRotationChanged x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Rotation);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setRotation(90);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Rotation), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemOpacityChanged x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Opacity);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setOpacity(0.5);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Opacity), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemChildAdded() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ child1 = new QQuickItem(parent);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Children), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemParentChanged() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(child1)->addItemChangeListener(listener, QQuickItemPrivate::Parent);
+ QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count());
+ child1->setParentItem(nullptr);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Parent), 1);
+ QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), 0);
+
+ // itemImplicitWidthChanged() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitWidth);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setImplicitWidth(parent->implicitWidth() + 1);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::ImplicitWidth), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemImplicitHeightChanged() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitHeight);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setImplicitHeight(parent->implicitHeight() + 1);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::ImplicitHeight), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemGeometryChanged() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Geometry);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setWidth(parent->width() + 1);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Geometry), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemChildRemoved() x 5
+ child1->setParentItem(parent);
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ delete child1;
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Children), 2);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemDestroyed() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Destroyed);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ delete parent;
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1);
+}
+
// QTBUG-13893
void tst_QQuickItem::transformCrash()
{
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml
new file mode 100644
index 0000000000..22205c18f0
--- /dev/null
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.7
+import QtQuick.Layouts 1.3
+
+Item {
+ objectName: "qtbug51927-window"
+ visible: true
+
+ default property alias _contents: customContent.data
+
+ RowLayout {
+ id: customContent
+ objectName: "qtbug51927-columnLayout"
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml
new file mode 100644
index 0000000000..ff7ce6221b
--- /dev/null
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.6
+import QtQuick.Window 2.2
+
+Container {
+ visible: true
+
+ Text {
+ objectName: "qtbug51927-text"
+ text: qsTr("Hello World")
+ anchors.centerIn: parent
+ renderType: Text.QtRendering
+ }
+}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 33b8fd0e4e..2d4e227a9e 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -926,5 +926,17 @@ Item {
waitForRendering(layout)
layout.destroy()
}
+
+
+ function test_defaultPropertyAliasCrash() {
+ var containerUserComponent = Qt.createComponent("rowlayout/ContainerUser.qml");
+ compare(containerUserComponent.status, Component.Ready);
+
+ var containerUser = containerUserComponent.createObject(testCase);
+ verify(containerUser);
+
+ // Shouldn't crash.
+ containerUser.destroy();
+ }
}
}
diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST
index 269696ce8c..d259c11219 100644
--- a/tests/auto/quick/qquicklistview/BLACKLIST
+++ b/tests/auto/quick/qquicklistview/BLACKLIST
@@ -2,3 +2,6 @@
*
[enforceRange_withoutHighlight]
osx
+#QTBUG-53863
+[populateTransitions]
+opensuse-42.1
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 658ffa1f57..b0d903908f 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -250,6 +250,7 @@ private slots:
void QTBUG_50105();
void keyNavigationEnabled();
void QTBUG_50097_stickyHeader_positionViewAtIndex();
+ void itemFiltered();
private:
template <class T> void items(const QUrl &source);
@@ -629,6 +630,8 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v
}
listview->setContentY(contentY);
+ QQuickItemViewPrivate::get(listview)->layout();
+
QList<QPair<QString, QString> > newData;
for (int i=0; i<insertCount; i++)
newData << qMakePair(QString("value %1").arg(i), QString::number(i));
@@ -650,6 +653,14 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v
QCOMPARE(item0->y(), itemsOffsetAfterMove);
#endif
+ QList<FxViewItem *> visibleItems = QQuickItemViewPrivate::get(listview)->visibleItems;
+ for (QList<FxViewItem *>::const_iterator itemIt = visibleItems.begin(); itemIt != visibleItems.end(); ++itemIt) {
+ FxViewItem *item = *itemIt;
+ if (item->item->position().y() >= 0 && item->item->position().y() < listview->height()) {
+ QVERIFY(!QQuickItemPrivate::get(item->item)->culled);
+ }
+ }
+
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
for (int i=0; i<items.count(); i++) {
@@ -735,7 +746,7 @@ void tst_QQuickListView::inserted_more_data()
<< 15 << 1
<< 0.0;
- QTest::newRow("add 1, at end of visible, content at start")
+ QTest::newRow("add multiple, at end of visible, content at start")
<< 0.0
<< 15 << 3
<< 0.0;
@@ -756,7 +767,7 @@ void tst_QQuickListView::inserted_more_data()
<< 16 << 1
<< 0.0;
- QTest::newRow("add 1, after visible, content at start")
+ QTest::newRow("add multiple, after visible, content at start")
<< 0.0
<< 16 << 3
<< 0.0;
@@ -770,6 +781,11 @@ void tst_QQuickListView::inserted_more_data()
<< 80.0 // show 4-19
<< 20 << 3
<< 0.0;
+
+ QTest::newRow("add multiple, within visible, content at start")
+ << 0.0
+ << 2 << 50
+ << 0.0;
}
void tst_QQuickListView::insertBeforeVisible()
@@ -8328,6 +8344,37 @@ void tst_QQuickListView::QTBUG_50097_stickyHeader_positionViewAtIndex()
QTRY_COMPARE(listview->contentY(), -100.0); // back to the same position: header visible, items not under the header.
}
+void tst_QQuickListView::itemFiltered()
+{
+ QStringListModel model(QStringList() << "one" << "two" << "three" << "four" << "five" << "six");
+ QSortFilterProxyModel proxy1;
+ proxy1.setSourceModel(&model);
+ proxy1.setSortRole(Qt::DisplayRole);
+ proxy1.setDynamicSortFilter(true);
+ proxy1.sort(0);
+
+ QSortFilterProxyModel proxy2;
+ proxy2.setSourceModel(&proxy1);
+ proxy2.setFilterRole(Qt::DisplayRole);
+ proxy2.setFilterRegExp("^[^ ]*$");
+ proxy2.setDynamicSortFilter(true);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->engine()->rootContext()->setContextProperty("_model", &proxy2);
+ QQmlComponent component(window->engine());
+ component.setData("import QtQuick 2.4; ListView { "
+ "anchors.fill: parent; model: _model; delegate: Text { width: parent.width;"
+ "text: model.display; } }",
+ QUrl());
+ window->setContent(QUrl(), &component, component.create());
+
+ window->show();
+ QTest::qWaitForWindowExposed(window.data());
+
+ // this should not crash
+ model.setData(model.index(2), QStringLiteral("modified three"), Qt::DisplayRole);
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"
diff --git a/tests/auto/quick/qquickloader/data/qmldir b/tests/auto/quick/qquickloader/data/qmldir
deleted file mode 100644
index bf42b507c0..0000000000
--- a/tests/auto/quick/qquickloader/data/qmldir
+++ /dev/null
@@ -1 +0,0 @@
-# For tst_QDeclarativeLoader::networkRequestUrl; no types needed though.
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index fe22a238b2..77af4796b6 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -213,7 +213,7 @@ void tst_QQuickLoader::sourceOrComponent_data()
QTest::newRow("source with encoded subdir binding") << "source" << "source: encodeURIComponent('subdir/Test.qml')\n" << testFileUrl("subdir/Test.qml") << "";
QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml")
- << QString(testFileUrl("IDontExist.qml").toString() + ": File not found");
+ << QString(testFileUrl("IDontExist.qml").toString() + ": No such file or directory");
}
void tst_QQuickLoader::clear()
@@ -748,7 +748,7 @@ void tst_QQuickLoader::initialPropertyValuesError_data()
<< (QStringList() << QString(testFileUrl("initialPropertyValues.error.1.qml").toString() + ":6:5: QML Loader: setSource: value is not an object"));
QTest::newRow("nonexistent source url") << testFileUrl("initialPropertyValues.error.2.qml")
- << (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": File not found"));
+ << (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": No such file or directory"));
QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml")
<< (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
@@ -901,7 +901,7 @@ void tst_QQuickLoader::asynchronous_data()
<< QStringList();
QTest::newRow("Non-existent component") << testFileUrl("IDoNotExist.qml")
- << (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": File not found"));
+ << (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": No such file or directory"));
QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml")
<< (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
diff --git a/tests/auto/quick/qquickmousearea/data/qtbug54019.qml b/tests/auto/quick/qquickmousearea/data/qtbug54019.qml
new file mode 100644
index 0000000000..75cca2691a
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/qtbug54019.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.7
+
+Item {
+ width: 200
+ height: 200
+ MouseArea {
+ id: ma
+ property string str: "foo!"
+ width: 150; height: 150
+ hoverEnabled: true
+
+ Rectangle {
+ anchors.fill: parent
+ color: ma.containsMouse ? "lightsteelblue" : "gray"
+ }
+ Text {
+ text: ma.str
+ textFormat: Text.PlainText // consequently Text does not care about hover events
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 3f78bcf1eb..b69c6eedf8 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -29,6 +29,7 @@
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
#include <QtQuick/private/qquickdrag_p.h>
+#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <private/qquickflickable_p.h>
@@ -82,6 +83,7 @@ private slots:
void dragging_data() { acceptedButton_data(); }
void dragging();
void dragSmoothed();
+ void dragThreshold_data();
void dragThreshold();
void invalidDrag_data() { rejectedButton_data(); }
void invalidDrag();
@@ -106,6 +108,7 @@ private slots:
void hoverPropagation();
void hoverVisible();
void hoverAfterPress();
+ void subtreeHoverEnabled();
void disableAfterPress();
void onWheel();
void transformedMouseArea_data();
@@ -122,8 +125,12 @@ private slots:
void containsPress_data();
void containsPress();
void ignoreBySource();
+ void notPressedAfterStolenGrab();
private:
+ int startDragDistance() const {
+ return QGuiApplication::styleHints()->startDragDistance();
+ }
void acceptedButton_data();
void rejectedButton_data();
QTouchDevice *device;
@@ -319,7 +326,8 @@ void tst_QQuickMouseArea::dragging()
QVERIFY(!drag->active());
- QTest::mousePress(&window, button, 0, QPoint(100,100));
+ QPoint p = QPoint(100,100);
+ QTest::mousePress(&window, button, 0, p);
QVERIFY(!drag->active());
QCOMPARE(blackRect->x(), 50.0);
@@ -330,18 +338,32 @@ void tst_QQuickMouseArea::dragging()
// The item is moved relative to the position of the mouse when the drag
// was triggered, this prevents a sudden change in position when the drag
// threshold is exceeded.
- QTest::mouseMove(&window, QPoint(111,111), 50);
- QTest::mouseMove(&window, QPoint(116,116), 50);
- QTest::mouseMove(&window, QPoint(122,122), 50);
+ int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+
+ // move the minimum distance to activate drag
+ p += QPoint(dragThreshold + 1, dragThreshold + 1);
+ QTest::mouseMove(&window, p);
+ QVERIFY(!drag->active());
+
+ // from here on move the item
+ p += QPoint(1, 1);
+ QTest::mouseMove(&window, p);
+ QTRY_VERIFY(drag->active());
+ // on macOS the cursor movement is going through a native event which
+ // means that it can actually take some time to show
+ QTRY_COMPARE(blackRect->x(), 50.0 + 1);
+ QCOMPARE(blackRect->y(), 50.0 + 1);
+
+ p += QPoint(10, 10);
+ QTest::mouseMove(&window, p);
QTRY_VERIFY(drag->active());
QTRY_COMPARE(blackRect->x(), 61.0);
QCOMPARE(blackRect->y(), 61.0);
- QTest::mouseRelease(&window, button, 0, QPoint(122,122));
-
+ QTest::mouseRelease(&window, button, 0, p);
QTRY_VERIFY(!drag->active());
- QCOMPARE(blackRect->x(), 61.0);
+ QTRY_COMPARE(blackRect->x(), 61.0);
QCOMPARE(blackRect->y(), 61.0);
}
@@ -390,8 +412,17 @@ void tst_QQuickMouseArea::dragSmoothed()
QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 122));
}
+void tst_QQuickMouseArea::dragThreshold_data()
+{
+ QTest::addColumn<bool>("preventStealing");
+ QTest::newRow("without preventStealing") << false;
+ QTest::newRow("with preventStealing") << true;
+}
+
void tst_QQuickMouseArea::dragThreshold()
{
+ QFETCH(bool, preventStealing);
+
QQuickView window;
QByteArray errorMessage;
QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData());
@@ -401,6 +432,7 @@ void tst_QQuickMouseArea::dragThreshold()
QVERIFY(window.rootObject() != 0);
QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion");
+ mouseRegion->setPreventStealing(preventStealing);
QQuickDrag *drag = mouseRegion->drag();
drag->setThreshold(5);
@@ -520,15 +552,18 @@ void tst_QQuickMouseArea::cancelDragging()
QVERIFY(!drag->active());
- QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100));
+ QPoint p = QPoint(100,100);
+ QTest::mousePress(&window, Qt::LeftButton, 0, p);
QVERIFY(!drag->active());
QCOMPARE(blackRect->x(), 50.0);
QCOMPARE(blackRect->y(), 50.0);
- QTest::mouseMove(&window, QPoint(111,111), 50);
- QTest::mouseMove(&window, QPoint(116,116), 50);
- QTest::mouseMove(&window, QPoint(122,122), 50);
+ p += QPoint(startDragDistance() + 1, 0);
+ QTest::mouseMove(&window, p);
+
+ p += QPoint(11, 11);
+ QTest::mouseMove(&window, p);
QTRY_VERIFY(drag->active());
QTRY_COMPARE(blackRect->x(), 61.0);
@@ -563,7 +598,8 @@ void tst_QQuickMouseArea::setDragOnPressed()
QQuickItem *target = mouseArea->findChild<QQuickItem*>("target");
QVERIFY(target);
- QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100));
+ QPoint p = QPoint(100, 100);
+ QTest::mousePress(&window, Qt::LeftButton, 0, p);
QQuickDrag *drag = mouseArea->drag();
QVERIFY(drag);
@@ -575,19 +611,17 @@ void tst_QQuickMouseArea::setDragOnPressed()
// First move event triggers drag, second is acted upon.
// This is due to possibility of higher stacked area taking precedence.
- QTest::mouseMove(&window, QPoint(111,102));
- QTest::qWait(50);
- QTest::mouseMove(&window, QPoint(122,122));
- QTest::qWait(50);
+ p += QPoint(startDragDistance() + 1, 0);
+ QTest::mouseMove(&window, p);
- QVERIFY(drag->active());
- QCOMPARE(target->x(), 61.0);
+ p += QPoint(11, 0);
+ QTest::mouseMove(&window, p);
+ QTRY_VERIFY(drag->active());
+ QTRY_COMPARE(target->x(), 61.0);
QCOMPARE(target->y(), 50.0);
- QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(122,122));
- QTest::qWait(50);
-
- QVERIFY(!drag->active());
+ QTest::mouseRelease(&window, Qt::LeftButton, 0, p);
+ QTRY_VERIFY(!drag->active());
QCOMPARE(target->x(), 61.0);
QCOMPARE(target->y(), 50.0);
}
@@ -736,7 +770,7 @@ void tst_QQuickMouseArea::onMousePressRejected()
QVERIFY(!window.rootObject()->property("mr1_canceled").toBool());
QVERIFY(window.rootObject()->property("mr2_pressed").toBool());
QVERIFY(!window.rootObject()->property("mr2_released").toBool());
- QVERIFY(window.rootObject()->property("mr2_canceled").toBool());
+ QVERIFY(!window.rootObject()->property("mr2_canceled").toBool());
QTest::qWait(200);
@@ -780,14 +814,14 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
QGuiApplication::sendEvent(&window, &pressEvent);
- QVERIFY(window.rootObject()->property("pressed").toBool());
+ QTRY_VERIFY(window.rootObject()->property("pressed").toBool());
QVERIFY(!window.rootObject()->property("canceled").toBool());
QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease);
QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks);
if (doubleClick) {
QGuiApplication::sendEvent(&window, &releaseEvent);
- QVERIFY(!window.rootObject()->property("pressed").toBool());
+ QTRY_VERIFY(!window.rootObject()->property("pressed").toBool());
QVERIFY(!window.rootObject()->property("canceled").toBool());
QCOMPARE(window.rootObject()->property("released").toInt(), ++expectedRelease);
QCOMPARE(window.rootObject()->property("clicked").toInt(), ++expectedClicks);
@@ -796,7 +830,7 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
QMouseEvent pressEvent2(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
QGuiApplication::sendEvent(&window, &pressEvent2);
- QVERIFY(window.rootObject()->property("pressed").toBool());
+ QTRY_VERIFY(window.rootObject()->property("pressed").toBool());
QVERIFY(!window.rootObject()->property("canceled").toBool());
QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease);
QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks);
@@ -808,23 +842,21 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
secondWindow->setProperty("visible", true);
QTest::qWaitForWindowExposed(secondWindow);
- QVERIFY(!window.rootObject()->property("pressed").toBool());
+ QTRY_VERIFY(!window.rootObject()->property("pressed").toBool());
QVERIFY(window.rootObject()->property("canceled").toBool());
QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease);
QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks);
//press again
QGuiApplication::sendEvent(&window, &pressEvent);
- QVERIFY(window.rootObject()->property("pressed").toBool());
+ QTRY_VERIFY(window.rootObject()->property("pressed").toBool());
QVERIFY(!window.rootObject()->property("canceled").toBool());
QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease);
QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks);
- QTest::qWait(200);
-
//release
QGuiApplication::sendEvent(&window, &releaseEvent);
- QVERIFY(!window.rootObject()->property("pressed").toBool());
+ QTRY_VERIFY(!window.rootObject()->property("pressed").toBool());
QVERIFY(!window.rootObject()->property("canceled").toBool());
QCOMPARE(window.rootObject()->property("released").toInt(), ++expectedRelease);
QCOMPARE(window.rootObject()->property("clicked").toInt(), ++expectedClicks);
@@ -982,48 +1014,60 @@ void tst_QQuickMouseArea::preventStealing()
QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QQuickMouseEvent*)));
- QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(80, 80));
+ QPoint p = QPoint(80, 80);
+ QTest::mousePress(&window, Qt::LeftButton, 0, p);
// Without preventStealing, mouse movement over MouseArea would
// cause the Flickable to steal mouse and trigger content movement.
- QTest::mouseMove(&window,QPoint(69,69));
- QTest::mouseMove(&window,QPoint(58,58));
- QTest::mouseMove(&window,QPoint(47,47));
+ p += QPoint(-startDragDistance() * 2, -startDragDistance() * 2);
+ QTest::mouseMove(&window, p);
+ p += QPoint(-10, -10);
+ QTest::mouseMove(&window, p);
+ p += QPoint(-10, -10);
+ QTest::mouseMove(&window, p);
+ p += QPoint(-10, -10);
+ QTest::mouseMove(&window, p);
- // We should have received all three move events
- QCOMPARE(mousePositionSpy.count(), 3);
+ // We should have received all four move events
+ QTRY_COMPARE(mousePositionSpy.count(), 4);
+ mousePositionSpy.clear();
QVERIFY(mouseArea->pressed());
// Flickable content should not have moved.
QCOMPARE(flickable->contentX(), 0.);
QCOMPARE(flickable->contentY(), 0.);
- QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(47, 47));
+ QTest::mouseRelease(&window, Qt::LeftButton, 0, p);
// Now allow stealing and confirm Flickable does its thing.
window.rootObject()->setProperty("stealing", false);
- QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(80, 80));
+ p = QPoint(80, 80);
+ QTest::mousePress(&window, Qt::LeftButton, 0, p);
// Without preventStealing, mouse movement over MouseArea would
// cause the Flickable to steal mouse and trigger content movement.
- QTest::mouseMove(&window,QPoint(69,69));
- QTest::mouseMove(&window,QPoint(58,58));
- QTest::mouseMove(&window,QPoint(47,47));
+ p += QPoint(-startDragDistance() * 2, -startDragDistance() * 2);
+ QTest::mouseMove(&window, p);
+ p += QPoint(-10, -10);
+ QTest::mouseMove(&window, p);
+ p += QPoint(-10, -10);
+ QTest::mouseMove(&window, p);
+ p += QPoint(-10, -10);
+ QTest::mouseMove(&window, p);
// We should only have received the first move event
- QCOMPARE(mousePositionSpy.count(), 4);
+ QTRY_COMPARE(mousePositionSpy.count(), 1);
// Our press should be taken away
QVERIFY(!mouseArea->pressed());
- // Flickable content should have moved.
-
- QCOMPARE(flickable->contentX(), 11.);
- QCOMPARE(flickable->contentY(), 11.);
+ // Flickable swallows the first move, then moves 2*10 px
+ QTRY_COMPARE(flickable->contentX(), 20.);
+ QCOMPARE(flickable->contentY(), 20.);
- QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50));
+ QTest::mouseRelease(&window, Qt::LeftButton, 0, p);
}
void tst_QQuickMouseArea::clickThrough()
@@ -1036,17 +1080,17 @@ void tst_QQuickMouseArea::clickThrough()
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QVERIFY(window->rootObject() != 0);
+ // to avoid generating a double click.
+ const int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval() + 10;
+
QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
QTRY_COMPARE(window->rootObject()->property("presses").toInt(), 0);
QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1);
- // to avoid generating a double click.
- int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval() + 10;
- QTest::qWait(doubleClickInterval);
-
- QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QCOMPARE(window->rootObject()->property("doubleClicks").toInt(), 0);
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval);
QTest::qWait(1000);
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
@@ -1076,9 +1120,7 @@ void tst_QQuickMouseArea::clickThrough()
QCOMPARE(window->rootObject()->property("presses").toInt(), 0);
QCOMPARE(window->rootObject()->property("clicks").toInt(), 0);
- QTest::qWait(doubleClickInterval); // to avoid generating a double click.
-
- QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval);
QTest::qWait(1000);
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
QTest::qWait(100);
@@ -1097,15 +1139,13 @@ void tst_QQuickMouseArea::clickThrough()
window->rootObject()->setProperty("letThrough", QVariant(true));
- QTest::qWait(doubleClickInterval); // to avoid generating a double click.
- QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval);
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
QCOMPARE(window->rootObject()->property("presses").toInt(), 0);
QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1);
- QTest::qWait(doubleClickInterval); // to avoid generating a double click.
- QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval);
QTest::qWait(1000);
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
QTest::qWait(100);
@@ -1124,12 +1164,10 @@ void tst_QQuickMouseArea::clickThrough()
window->rootObject()->setProperty("noPropagation", QVariant(true));
- QTest::qWait(doubleClickInterval); // to avoid generating a double click.
- QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval);
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
- QTest::qWait(doubleClickInterval); // to avoid generating a double click.
- QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval);
QTest::qWait(1000);
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
QTest::qWait(100);
@@ -1150,7 +1188,7 @@ void tst_QQuickMouseArea::clickThrough()
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QVERIFY(window->rootObject() != 0);
- QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval);
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 1);
@@ -1158,8 +1196,7 @@ void tst_QQuickMouseArea::clickThrough()
window->rootObject()->setProperty("disableLower", QVariant(true));
- QTest::qWait(doubleClickInterval); // to avoid generating a double click.
- QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval);
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 2);
@@ -1275,6 +1312,26 @@ void tst_QQuickMouseArea::hoverAfterPress()
QCOMPARE(mouseArea->hovered(), false);
}
+void tst_QQuickMouseArea::subtreeHoverEnabled()
+{
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(initView(window, testFileUrl("qtbug54019.qml"), true, &errorMessage), errorMessage.constData());
+ QQuickItem *root = window.rootObject();
+ QVERIFY(root != 0);
+
+ QQuickMouseArea *mouseArea = root->findChild<QQuickMouseArea*>();
+ QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(root);
+ QVERIFY(mouseArea != 0);
+ QTest::mouseMove(&window, QPoint(10, 160));
+ QCOMPARE(mouseArea->hovered(), false);
+ QVERIFY(rootPrivate->subtreeHoverEnabled);
+ QTest::mouseMove(&window, QPoint(10, 10));
+ QCOMPARE(mouseArea->hovered(), true);
+ QTest::mouseMove(&window, QPoint(160, 10));
+ QCOMPARE(mouseArea->hovered(), false);
+}
+
void tst_QQuickMouseArea::disableAfterPress()
{
QQuickView window;
@@ -1299,9 +1356,8 @@ void tst_QQuickMouseArea::disableAfterPress()
QCOMPARE(blackRect, drag->target());
QVERIFY(!drag->active());
-
- QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100));
-
+ QPoint p = QPoint(100,100);
+ QTest::mousePress(&window, Qt::LeftButton, 0, p);
QTRY_COMPARE(mousePressSpy.count(), 1);
QVERIFY(!drag->active());
@@ -1311,22 +1367,24 @@ void tst_QQuickMouseArea::disableAfterPress()
// First move event triggers drag, second is acted upon.
// This is due to possibility of higher stacked area taking precedence.
- QTest::mouseMove(&window, QPoint(111,111));
- QTest::qWait(50);
- QTest::mouseMove(&window, QPoint(122,122));
+ p += QPoint(startDragDistance() + 1, 0);
+ QTest::mouseMove(&window, p);
+ p += QPoint(11, 11);
+ QTest::mouseMove(&window, p);
QTRY_COMPARE(mousePositionSpy.count(), 2);
- QVERIFY(drag->active());
- QCOMPARE(blackRect->x(), 61.0);
+ QTRY_VERIFY(drag->active());
+ QTRY_COMPARE(blackRect->x(), 61.0);
QCOMPARE(blackRect->y(), 61.0);
mouseArea->setEnabled(false);
// move should still be acted upon
- QTest::mouseMove(&window, QPoint(133,133));
- QTest::qWait(50);
- QTest::mouseMove(&window, QPoint(144,144));
+ p += QPoint(11, 11);
+ QTest::mouseMove(&window, p);
+ p += QPoint(11, 11);
+ QTest::mouseMove(&window, p);
QTRY_COMPARE(mousePositionSpy.count(), 4);
@@ -1337,7 +1395,7 @@ void tst_QQuickMouseArea::disableAfterPress()
QVERIFY(mouseArea->pressed());
QVERIFY(mouseArea->hovered());
- QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(144,144));
+ QTest::mouseRelease(&window, Qt::LeftButton, 0, p);
QTRY_COMPARE(mouseReleaseSpy.count(), 1);
@@ -1594,36 +1652,39 @@ void tst_QQuickMouseArea::changeAxis()
QVERIFY(!drag->active());
// Start a diagonal drag
- QTest::mousePress(&view, Qt::LeftButton, 0, QPoint(100, 100));
+ QPoint p = QPoint(100, 100);
+ QTest::mousePress(&view, Qt::LeftButton, 0, p);
QVERIFY(!drag->active());
QCOMPARE(blackRect->x(), 50.0);
QCOMPARE(blackRect->y(), 50.0);
- QTest::mouseMove(&view, QPoint(111, 111));
- QTest::qWait(50);
- QTest::mouseMove(&view, QPoint(122, 122));
-
+ p += QPoint(startDragDistance() + 1, startDragDistance() + 1);
+ QTest::mouseMove(&view, p);
+ p += QPoint(11, 11);
+ QTest::mouseMove(&view, p);
QTRY_VERIFY(drag->active());
- QCOMPARE(blackRect->x(), 61.0);
+ QTRY_COMPARE(blackRect->x(), 61.0);
QCOMPARE(blackRect->y(), 61.0);
QCOMPARE(drag->axis(), QQuickDrag::XAndYAxis);
/* When blackRect.x becomes bigger than 75, the drag axis is changed to
* Drag.YAxis by the QML code. Verify that this happens, and that the drag
* movement is effectively constrained to the Y axis. */
- QTest::mouseMove(&view, QPoint(144, 144));
+ p += QPoint(22, 22);
+ QTest::mouseMove(&view, p);
QTRY_COMPARE(blackRect->x(), 83.0);
QTRY_COMPARE(blackRect->y(), 83.0);
QTRY_COMPARE(drag->axis(), QQuickDrag::YAxis);
- QTest::mouseMove(&view, QPoint(155, 155));
+ p += QPoint(11, 11);
+ QTest::mouseMove(&view, p);
QTRY_COMPARE(blackRect->y(), 94.0);
QCOMPARE(blackRect->x(), 83.0);
- QTest::mouseRelease(&view, Qt::LeftButton, 0, QPoint(155, 155));
+ QTest::mouseRelease(&view, Qt::LeftButton, 0, p);
QTRY_VERIFY(!drag->active());
QCOMPARE(blackRect->x(), 83.0);
@@ -1673,11 +1734,17 @@ void tst_QQuickMouseArea::moveAndReleaseWithoutPress()
QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100));
+ // the press was not accepted, make sure there is no move or release event
QTest::mouseMove(&window, QPoint(110,110), 50);
- QTRY_COMPARE(root->property("hadMove").toBool(), false);
+
+ // use qwait here because we want to make sure an event does NOT happen
+ // the test fails if the default state changes, while it shouldn't
+ QTest::qWait(100);
+ QCOMPARE(root->property("hadMove").toBool(), false);
QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(110,110));
- QTRY_COMPARE(root->property("hadRelease").toBool(), false);
+ QTest::qWait(100);
+ QCOMPARE(root->property("hadRelease").toBool(), false);
}
void tst_QQuickMouseArea::nestedStopAtBounds_data()
@@ -1829,33 +1896,43 @@ void tst_QQuickMouseArea::ignoreBySource()
QVERIFY(flickable);
// MouseArea should grab the press because it's interested in non-synthesized mouse events
- QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(80, 80));
- QVERIFY(window.mouseGrabberItem() == mouseArea);
+ QPoint p = QPoint(80, 80);
+ QTest::mousePress(&window, Qt::LeftButton, 0, p);
+ QCOMPARE(window.mouseGrabberItem(), mouseArea);
// That was a real mouse event
- QVERIFY(root->property("lastEventSource").toInt() == Qt::MouseEventNotSynthesized);
+ QCOMPARE(root->property("lastEventSource").toInt(), int(Qt::MouseEventNotSynthesized));
// Flickable content should not move
- QTest::mouseMove(&window,QPoint(69,69));
- QTest::mouseMove(&window,QPoint(58,58));
- QTest::mouseMove(&window,QPoint(47,47));
+ p -= QPoint(startDragDistance() + 1, startDragDistance() + 1);
+ QTest::mouseMove(&window, p);
+ p -= QPoint(11, 11);
+ QTest::mouseMove(&window, p);
+ p -= QPoint(11, 11);
+ QTest::mouseMove(&window, p);
QCOMPARE(flickable->contentX(), 0.);
QCOMPARE(flickable->contentY(), 0.);
- QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(47, 47));
+ QTest::mouseRelease(&window, Qt::LeftButton, 0, p);
+ QCOMPARE(window.mouseGrabberItem(), nullptr);
// Now try touch events and confirm that MouseArea ignores them, while Flickable does its thing
-
- QTest::touchEvent(&window, device).press(0, QPoint(80, 80), &window);
+ p = QPoint(80, 80);
+ QTest::touchEvent(&window, device).press(0, p, &window);
QQuickTouchUtils::flush(&window);
- QVERIFY(window.mouseGrabberItem() != mouseArea);
+ QCOMPARE(window.mouseGrabberItem(), flickable);
+
// That was a fake mouse event
QCOMPARE(root->property("lastEventSource").toInt(), int(Qt::MouseEventSynthesizedByQt));
- QTest::touchEvent(&window, device).move(0, QPoint(69,69), &window);
- QTest::touchEvent(&window, device).move(0, QPoint(69,69), &window);
- QTest::touchEvent(&window, device).move(0, QPoint(47,47), &window);
+ p -= QPoint(startDragDistance() + 1, startDragDistance() + 1);
+ QTest::touchEvent(&window, device).move(0, p, &window);
+ p -= QPoint(11, 11);
+ QTest::touchEvent(&window, device).move(0, p, &window);
+ p -= QPoint(11, 11);
+ QTest::touchEvent(&window, device).move(0, p, &window);
+
QQuickTouchUtils::flush(&window);
QCOMPARE(window.mouseGrabberItem(), flickable);
- QTest::touchEvent(&window, device).release(0, QPoint(47,47), &window);
+ QTest::touchEvent(&window, device).release(0, p, &window);
QQuickTouchUtils::flush(&window);
// Flickable content should have moved
@@ -1870,15 +1947,19 @@ void tst_QQuickMouseArea::ignoreBySource()
// MouseArea should ignore the press because it's interested in synthesized mouse events
- QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(80, 80));
+ p = QPoint(80, 80);
+ QTest::mousePress(&window, Qt::LeftButton, 0, p);
QVERIFY(window.mouseGrabberItem() != mouseArea);
// That was a real mouse event
QVERIFY(root->property("lastEventSource").toInt() == Qt::MouseEventNotSynthesized);
// Flickable content should move
- QTest::mouseMove(&window,QPoint(69,69));
- QTest::mouseMove(&window,QPoint(58,58));
- QTest::mouseMove(&window,QPoint(47,47));
+ p -= QPoint(startDragDistance() + 1, startDragDistance() + 1);
+ QTest::mouseMove(&window, p);
+ p -= QPoint(11, 11);
+ QTest::mouseMove(&window, p);
+ p -= QPoint(11, 11);
+ QTest::mouseMove(&window, p);
QTRY_VERIFY(flickable->contentX() > 1);
QVERIFY(flickable->contentY() > 1);
@@ -1887,13 +1968,16 @@ void tst_QQuickMouseArea::ignoreBySource()
flickable->setContentY(0);
// Now try touch events and confirm that MouseArea gets them, while Flickable doesn't
-
- QTest::touchEvent(&window, device).press(0, QPoint(80, 80), &window);
+ p = QPoint(80, 80);
+ QTest::touchEvent(&window, device).press(0, p, &window);
QQuickTouchUtils::flush(&window);
QCOMPARE(window.mouseGrabberItem(), mouseArea);
- QTest::touchEvent(&window, device).move(0, QPoint(69,69), &window);
- QTest::touchEvent(&window, device).move(0, QPoint(69,69), &window);
- QTest::touchEvent(&window, device).move(0, QPoint(47,47), &window);
+ p -= QPoint(startDragDistance() + 1, startDragDistance() + 1);
+ QTest::touchEvent(&window, device).move(0, p, &window);
+ p -= QPoint(11, 11);
+ QTest::touchEvent(&window, device).move(0, p, &window);
+ p -= QPoint(11, 11);
+ QTest::touchEvent(&window, device).move(0, p, &window);
QQuickTouchUtils::flush(&window);
QCOMPARE(window.mouseGrabberItem(), mouseArea);
QTest::touchEvent(&window, device).release(0, QPoint(47,47), &window);
@@ -1904,6 +1988,23 @@ void tst_QQuickMouseArea::ignoreBySource()
QCOMPARE(flickable->contentY(), 0.);
}
+void tst_QQuickMouseArea::notPressedAfterStolenGrab()
+{
+ QQuickWindow window;
+ window.resize(200, 200);
+ window.show();
+ QTest::qWaitForWindowExposed(&window);
+
+ QQuickMouseArea *ma = new QQuickMouseArea(window.contentItem());
+ ma->setSize(window.size());
+ QObject::connect(ma,
+ static_cast<void (QQuickMouseArea::*)(QQuickMouseEvent*)>(&QQuickMouseArea::pressed),
+ [&]() { window.contentItem()->grabMouse(); });
+
+ QTest::mouseClick(&window, Qt::LeftButton);
+ QVERIFY(!ma->pressed());
+}
+
QTEST_MAIN(tst_QQuickMouseArea)
#include "tst_qquickmousearea.moc"
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml b/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml
new file mode 100644
index 0000000000..e108003bca
--- /dev/null
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.0
+
+MultiPointTouchArea {
+ width: 240
+ height: 320
+
+ minimumTouchPoints: 1
+ maximumTouchPoints: 5
+ touchPoints: [
+ TouchPoint { objectName: "point1" },
+ TouchPoint { objectName: "point2" },
+ TouchPoint { objectName: "point3" },
+ TouchPoint { objectName: "point4" },
+ TouchPoint { objectName: "point5" }
+ ]
+
+ function clearCounts() {
+ touchPointPressCount = 0;
+ touchPointUpdateCount = 0;
+ touchPointReleaseCount = 0;
+ touchPointCancelCount = 0;
+ touchCount = 0;
+ touchUpdatedHandled = false;
+ }
+
+ property int touchPointPressCount: 0
+ property int touchPointUpdateCount: 0
+ property int touchPointReleaseCount: 0
+ property int touchPointCancelCount: 0
+ property int touchCount: 0
+ property bool touchUpdatedHandled: false
+
+ onPressed: { touchPointPressCount = touchPoints.length }
+ onUpdated: { touchPointUpdateCount = touchPoints.length }
+ onReleased: { touchPointReleaseCount = touchPoints.length }
+ onCanceled: { touchPointCancelCount = touchPoints.length }
+ onTouchUpdated: {
+ touchCount = touchPoints.length
+ touchUpdatedHandled = true
+ }
+}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
index 8320d899f9..2872556a94 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
+++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
@@ -69,6 +69,7 @@ private slots:
void transformedTouchArea();
void mouseInteraction();
void mouseInteraction_data();
+ void cancel();
private:
QQuickView *createAndShowView(const QString &file);
@@ -914,13 +915,13 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint()
// Touch both, release one, manipulate other touchpoint with mouse
QTest::touchEvent(window.data(), device).press(1, touch1);
QQuickTouchUtils::flush(window.data());
- QTest::touchEvent(window.data(), device).press(2, touch2);
+ QTest::touchEvent(window.data(), device).move(1, touch1).press(2, touch2);
QQuickTouchUtils::flush(window.data());
QCOMPARE(touch1rect->property("x").toInt(), touch1.x());
QCOMPARE(touch1rect->property("y").toInt(), touch1.y());
QCOMPARE(touch2rect->property("x").toInt(), touch2.x());
QCOMPARE(touch2rect->property("y").toInt(), touch2.y());
- QTest::touchEvent(window.data(), device).release(1, touch1);
+ QTest::touchEvent(window.data(), device).release(1, touch1).move(2, touch2);
touch1.setY(20);
QTest::mousePress(window.data(), Qt::LeftButton, 0, touch1);
QQuickTouchUtils::flush(window.data());
@@ -1195,6 +1196,60 @@ void tst_QQuickMultiPointTouchArea::mouseInteraction()
QCOMPARE(area->property("touchCount").toInt(), 0);
}
+void tst_QQuickMultiPointTouchArea::cancel()
+{
+ QScopedPointer<QQuickView> window(createAndShowView("cancel.qml"));
+ QVERIFY(window->rootObject() != 0);
+
+ QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject());
+ QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device);
+ QQuickTouchPoint *point1 = area->findChild<QQuickTouchPoint*>("point1");
+
+ QPoint p1(20,100);
+ sequence.press(0, p1).commit();
+ QQuickTouchUtils::flush(window.data());
+ QCOMPARE(point1->pressed(), true);
+ QCOMPARE(area->property("touchPointPressCount").toInt(), 1);
+ QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointCancelCount").toInt(), 0);
+ QCOMPARE(area->property("touchCount").toInt(), 1);
+ QMetaObject::invokeMethod(area, "clearCounts");
+
+ area->setVisible(false);
+ // we should get a onCancel signal
+ QCOMPARE(point1->pressed(), false);
+ QCOMPARE(area->property("touchPointPressCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointCancelCount").toInt(), 1);
+ QCOMPARE(area->property("touchCount").toInt(), 0);
+ QMetaObject::invokeMethod(area, "clearCounts");
+ area->setVisible(true);
+
+
+ sequence.press(0, p1).commit();
+ QQuickTouchUtils::flush(window.data());
+ QCOMPARE(point1->pressed(), true);
+ QCOMPARE(area->property("touchPointPressCount").toInt(), 1);
+ QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointCancelCount").toInt(), 0);
+ QCOMPARE(area->property("touchCount").toInt(), 1);
+ QMetaObject::invokeMethod(area, "clearCounts");
+
+ area->setEnabled(false);
+ // we should get a onCancel signal
+ QCOMPARE(point1->pressed(), false);
+ QCOMPARE(area->property("touchPointPressCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0);
+ QCOMPARE(area->property("touchPointCancelCount").toInt(), 1);
+ QCOMPARE(area->property("touchCount").toInt(), 0);
+ QMetaObject::invokeMethod(area, "clearCounts");
+
+}
+
QTEST_MAIN(tst_QQuickMultiPointTouchArea)
diff --git a/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp b/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp
index 355301878d..3bf61e8f17 100644
--- a/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp
+++ b/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp
@@ -48,7 +48,7 @@ private slots:
void tst_QQuickOpenGLInfo::testProperties()
{
QQuickView view;
- view.setSource(QUrl::fromLocalFile("data/basic.qml"));
+ view.setSource(testFileUrl("basic.qml"));
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
diff --git a/tests/auto/quick/qquickpathview/data/qtbug37815.qml b/tests/auto/quick/qquickpathview/data/qtbug37815.qml
new file mode 100644
index 0000000000..3fd4daca63
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/qtbug37815.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Netris
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.0
+
+Rectangle {
+ width: 600
+ height: 400
+ PathView {
+ objectName: "pathView"
+ model: 10
+ anchors.fill: parent
+ pathItemCount: 5
+ cacheItemCount: 5
+ highlightRangeMode: PathView.StrictlyEnforceRange
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+
+ path: Path {
+ startX: 0
+ startY: 50
+ PathLine {
+ x: 600
+ y: 50
+ }
+ }
+
+ delegate: Component {
+ Text {
+ width: 50
+ height: 50
+ text: index
+ objectName: "delegate" + index
+ font.pixelSize: 24
+ color: PathView.isCurrentItem ? "green" : "black"
+ }
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickpathview/data/qtbug53464.qml b/tests/auto/quick/qquickpathview/data/qtbug53464.qml
new file mode 100644
index 0000000000..d30d404e68
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/qtbug53464.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Netris
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.0
+
+Rectangle {
+ width: 600
+ height: 400
+ PathView {
+ objectName: "pathView"
+ model: 10
+ anchors.fill: parent
+ pathItemCount: 5
+ highlightRangeMode: PathView.StrictlyEnforceRange
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ currentIndex: 8
+
+ path: Path {
+ startX: 0
+ startY: 50
+ PathLine {
+ x: 600
+ y: 50
+ }
+ }
+
+ delegate: Component {
+ Text {
+ width: 50
+ height: 50
+ text: index
+ objectName: "delegate" + index
+ font.pixelSize: 24
+ color: PathView.isCurrentItem ? "green" : "black"
+ }
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index 6761313210..d013d190ec 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -135,7 +135,9 @@ private slots:
void nestedinFlickable();
void flickableDelegate();
void jsArrayChange();
+ void qtbug37815();
void qtbug42716();
+ void qtbug53464();
void addCustomAttribute();
void movementDirection_data();
void movementDirection();
@@ -2330,6 +2332,31 @@ void tst_QQuickPathView::jsArrayChange()
QCOMPARE(spy.count(), 1);
}
+void tst_QQuickPathView::qtbug37815()
+{
+ QScopedPointer<QQuickView> window(createView());
+
+ window->setSource(testFileUrl("qtbug37815.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ // cache items will be created async. Let's wait...
+ QTest::qWait(1000);
+
+ QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView");
+ QVERIFY(pathView != Q_NULLPTR);
+
+ const int pathItemCount = pathView->pathItemCount();
+ const int cacheItemCount = pathView->cacheItemCount();
+ int totalCount = 0;
+ foreach (QQuickItem *item, pathView->childItems()) {
+ if (item->objectName().startsWith(QLatin1String("delegate")))
+ ++totalCount;
+ }
+ QCOMPARE(pathItemCount + cacheItemCount, totalCount);
+}
+
/* This bug was one where if you jump the list such that the sole missing item needed to be
* added in the middle of the list, it would instead move an item somewhere else in the list
* to the middle (messing it up very badly).
@@ -2378,6 +2405,29 @@ void tst_QQuickPathView::qtbug42716()
QVERIFY(!itemMiss);
}
+void tst_QQuickPathView::qtbug53464()
+{
+ QScopedPointer<QQuickView> window(createView());
+
+ window->setSource(testFileUrl("qtbug53464.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView");
+ QVERIFY(pathView != Q_NULLPTR);
+ const int currentIndex = pathView->currentIndex();
+ QCOMPARE(currentIndex, 8);
+
+ const int pathItemCount = pathView->pathItemCount();
+ int totalCount = 0;
+ foreach (QQuickItem *item, pathView->childItems()) {
+ if (item->objectName().startsWith(QLatin1String("delegate")))
+ ++totalCount;
+ }
+ QCOMPARE(pathItemCount, totalCount);
+}
+
void tst_QQuickPathView::addCustomAttribute()
{
const QScopedPointer<QQuickView> window(createView());
diff --git a/tests/auto/quick/qquickpincharea/data/pinchproperties.qml b/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
index 37d706fc8e..c5daf6cbfe 100644
--- a/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
+++ b/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
@@ -2,7 +2,7 @@ import QtQuick 2.0
Rectangle {
id: whiteRect
property variant center
- property real scale
+ property real scale: -1.0
property int pointCount: 0
property bool pinchActive: false
width: 240; height: 320
diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
index aee35b4b90..c1a51fd659 100644
--- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
+++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
@@ -286,6 +286,7 @@ void tst_QQuickPinchArea::pan()
QPoint p1(80, 80);
QPoint p2(100, 100);
{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
pinchSequence.press(0, p1, window).commit();
QQuickTouchUtils::flush(window);
@@ -293,23 +294,63 @@ void tst_QQuickPinchArea::pan()
// we have to reuse the same pinchSequence object.
pinchSequence.stationary(0).press(1, p2, window).commit();
QQuickTouchUtils::flush(window);
- p1 += QPoint(10,10);
- p2 += QPoint(10,10);
- pinchSequence.move(0, p1,window).move(1, p2,window).commit();
+ QVERIFY(!root->property("pinchActive").toBool());
+ QCOMPARE(root->property("scale").toReal(), -1.0);
+
+ p1 += QPoint(dragThreshold - 1, 0);
+ p2 += QPoint(dragThreshold - 1, 0);
+ pinchSequence.move(0, p1, window).move(1, p2, window).commit();
QQuickTouchUtils::flush(window);
+ // movement < dragThreshold: pinch not yet active
+ QVERIFY(!root->property("pinchActive").toBool());
+ QCOMPARE(root->property("scale").toReal(), -1.0);
- QCOMPARE(root->property("scale").toReal(), 1.0);
+ // exactly the dragThreshold: pinch starts
+ p1 += QPoint(1, 0);
+ p2 += QPoint(1, 0);
+ pinchSequence.move(0, p1, window).move(1, p2, window).commit();
+ QQuickTouchUtils::flush(window);
QVERIFY(root->property("pinchActive").toBool());
+ QCOMPARE(root->property("scale").toReal(), 1.0);
- p1 += QPoint(10,10);
- p2 += QPoint(10,10);
- pinchSequence.move(0, p1,window).move(1, p2,window).commit();
+ // Calculation of the center point is tricky at first:
+ // center point of the two touch points in item coordinates:
+ // scene coordinates: (80, 80) + (dragThreshold, 0), (100, 100) + (dragThreshold, 0)
+ // = ((180+dT)/2, 180/2) = (90+dT, 90)
+ // item coordinates: (scene) - (50, 50) = (40+dT, 40)
+ QCOMPARE(root->property("center").toPointF(), QPointF(40 + dragThreshold, 40));
+ // pan started, but no actual movement registered yet:
+ // blackrect starts at 50,50
+ QCOMPARE(blackRect->x(), 50.0);
+ QCOMPARE(blackRect->y(), 50.0);
+
+ p1 += QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, window).move(1, p2, window).commit();
QQuickTouchUtils::flush(window);
- }
+ QCOMPARE(root->property("center").toPointF(), QPointF(40 + 10 + dragThreshold, 40));
+ QCOMPARE(blackRect->x(), 60.0);
+ QCOMPARE(blackRect->y(), 50.0);
- QCOMPARE(root->property("center").toPointF(), QPointF(60, 60)); // blackrect is at 50,50
- QCOMPARE(blackRect->x(), 60.0);
- QCOMPARE(blackRect->y(), 60.0);
+ p1 += QPoint(0, 10);
+ p2 += QPoint(0, 10);
+ pinchSequence.move(0, p1, window).move(1, p2, window).commit();
+ QQuickTouchUtils::flush(window);
+ // next big surprise: the center is in item local coordinates and the item was just
+ // moved 10 to the right... which offsets the center point 10 to the left
+ QCOMPARE(root->property("center").toPointF(), QPointF(40 + 10 - 10 + dragThreshold, 40 + 10));
+ QCOMPARE(blackRect->x(), 60.0);
+ QCOMPARE(blackRect->y(), 60.0);
+
+ p1 += QPoint(10, 10);
+ p2 += QPoint(10, 10);
+ pinchSequence.move(0, p1, window).move(1, p2, window).commit();
+ QQuickTouchUtils::flush(window);
+ // now the item moved again, thus the center point of the touch is moved in total by (10, 10)
+ QCOMPARE(root->property("center").toPointF(), QPointF(50 + dragThreshold, 50));
+ QCOMPARE(blackRect->x(), 70.0);
+ QCOMPARE(blackRect->y(), 70.0);
+ }
// pan x beyond bound
p1 += QPoint(100,100);
@@ -318,7 +359,7 @@ void tst_QQuickPinchArea::pan()
QQuickTouchUtils::flush(window);
QCOMPARE(blackRect->x(), 140.0);
- QCOMPARE(blackRect->y(), 160.0);
+ QCOMPARE(blackRect->y(), 170.0);
QTest::touchEvent(window, device).release(0, p1, window).release(1, p2, window);
QQuickTouchUtils::flush(window);
@@ -470,6 +511,7 @@ void tst_QQuickPinchArea::cancel()
QCOMPARE(blackRect->scale(), 1.5);
QTouchEvent cancelEvent(QEvent::TouchCancel);
+ cancelEvent.setDevice(device);
QCoreApplication::sendEvent(window, &cancelEvent);
QQuickTouchUtils::flush(window);
diff --git a/tests/auto/quick/qquickscreen/data/screen.qml b/tests/auto/quick/qquickscreen/data/screen.qml
index c246b3cd83..cf60d0ae40 100644
--- a/tests/auto/quick/qquickscreen/data/screen.qml
+++ b/tests/auto/quick/qquickscreen/data/screen.qml
@@ -1,5 +1,5 @@
import QtQuick 2.0
-import QtQuick.Window 2.0 as Window
+import QtQuick.Window 2.3 as Window
Item {
width: 100
@@ -10,6 +10,18 @@ Item {
property int priOrientation: Window.Screen.primaryOrientation
property int updateMask: Window.Screen.orientationUpdateMask
property real devicePixelRatio: Window.Screen.devicePixelRatio
+ property int vx: Window.Screen.virtualX
+ property int vy: Window.Screen.virtualY
Window.Screen.orientationUpdateMask: Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation
+
+ property int screenCount: Qt.application.screens.length
+
+ property variant allScreens
+ Component.onCompleted: {
+ allScreens = [];
+ var s = Qt.application.screens;
+ for (var i = 0; i < s.length; ++i)
+ allScreens.push(s[i]);
+ }
}
diff --git a/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp b/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp
index 92afdf6864..26b687a4a6 100644
--- a/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp
+++ b/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp
@@ -33,13 +33,15 @@
#include <QtQuick/QQuickView>
#include <QtGui/QScreen>
#include "../../shared/util.h"
-
+#include <QtQuick/private/qquickscreen_p.h>
+#include <QDebug>
class tst_qquickscreen : public QQmlDataTest
{
Q_OBJECT
private slots:
void basicProperties();
void screenOnStartup();
+ void fullScreenList();
};
void tst_qquickscreen::basicProperties()
@@ -62,6 +64,10 @@ void tst_qquickscreen::basicProperties()
QCOMPARE(int(screen->orientationUpdateMask()), root->property("updateMask").toInt());
QCOMPARE(screen->devicePixelRatio(), root->property("devicePixelRatio").toReal());
QVERIFY(screen->devicePixelRatio() >= 1.0);
+ QCOMPARE(screen->geometry().x(), root->property("vx").toInt());
+ QCOMPARE(screen->geometry().y(), root->property("vy").toInt());
+
+ QVERIFY(root->property("screenCount").toInt() == QGuiApplication::screens().count());
}
void tst_qquickscreen::screenOnStartup()
@@ -83,6 +89,38 @@ void tst_qquickscreen::screenOnStartup()
QCOMPARE(int(screen->orientationUpdateMask()), root->property("updateMask").toInt());
QCOMPARE(screen->devicePixelRatio(), root->property("devicePixelRatio").toReal());
QVERIFY(screen->devicePixelRatio() >= 1.0);
+ QCOMPARE(screen->geometry().x(), root->property("vx").toInt());
+ QCOMPARE(screen->geometry().y(), root->property("vy").toInt());
+}
+
+void tst_qquickscreen::fullScreenList()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("screen.qml"));
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickItem* root = view.rootObject();
+ QVERIFY(root);
+
+ QJSValue screensArray = root->property("allScreens").value<QJSValue>();
+ QVERIFY(screensArray.isArray());
+ int length = screensArray.property("length").toInt();
+ const QList<QScreen *> screenList = QGuiApplication::screens();
+ QVERIFY(length == screenList.count());
+
+ for (int i = 0; i < length; ++i) {
+ QQuickScreenInfo *info = qobject_cast<QQuickScreenInfo *>(screensArray.property(i).toQObject());
+ QVERIFY(info != nullptr);
+ QCOMPARE(screenList[i]->name(), info->name());
+ QCOMPARE(screenList[i]->size().width(), info->width());
+ QCOMPARE(screenList[i]->size().height(), info->height());
+ QCOMPARE(screenList[i]->availableVirtualGeometry().width(), info->desktopAvailableWidth());
+ QCOMPARE(screenList[i]->availableVirtualGeometry().height(), info->desktopAvailableHeight());
+ QCOMPARE(screenList[i]->devicePixelRatio(), info->devicePixelRatio());
+ QCOMPARE(screenList[i]->geometry().x(), info->virtualX());
+ QCOMPARE(screenList[i]->geometry().y(), info->virtualY());
+ }
}
QTEST_MAIN(tst_qquickscreen)
diff --git a/tests/auto/quick/qquickshadereffect/data/MyIcon.qml b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml
new file mode 100644
index 0000000000..b83da321f2
--- /dev/null
+++ b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.4
+
+Item {
+ id: root
+
+ property alias source: image.source
+ property bool shaderActive: false
+
+ implicitWidth: image.width
+
+ Image {
+ id: image
+ objectName: "image"
+ anchors { top: parent.top; bottom: parent.bottom }
+ sourceSize.height: height
+
+ visible: !shaderActive
+ }
+
+ ShaderEffect {
+ id: colorizedImage
+
+ anchors.fill: parent
+ visible: shaderActive && image.status == Image.Ready
+ supportsAtlasTextures: true
+
+ property Image source: visible ? image : null
+
+ fragmentShader: "
+ varying highp vec2 qt_TexCoord0;
+ uniform sampler2D source;
+ void main() {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }"
+ }
+}
diff --git a/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml
new file mode 100644
index 0000000000..d1292f74b8
--- /dev/null
+++ b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of 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.4
+
+Item {
+ width: 400
+ height: 700
+
+ MyIcon {
+ id: icon
+
+ height: 24
+ source: "star.png"
+ shaderActive: true
+ }
+
+ MyIcon {
+ anchors.top: icon.bottom
+
+ height: 24
+ source: "star.png"
+ }
+}
diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
index 171e0800e1..fe33dbd4d8 100644
--- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
+++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
@@ -33,12 +33,13 @@
#include <private/qquickopenglshadereffect_p.h>
#include <QMatrix4x4>
#include <QtQuick/QQuickView>
+#include <QtQml/QQmlEngine>
#include "../../shared/util.h"
class TestShaderEffect : public QQuickShaderEffect
{
Q_OBJECT
- Q_PROPERTY(QVariant source READ dummyRead NOTIFY dummyChanged)
+ Q_PROPERTY(QVariant source READ dummyRead NOTIFY sourceChanged)
Q_PROPERTY(QVariant _0aA9zZ READ dummyRead NOTIFY dummyChanged)
Q_PROPERTY(QVariant x86 READ dummyRead NOTIFY dummyChanged)
Q_PROPERTY(QVariant X READ dummyRead NOTIFY dummyChanged)
@@ -47,17 +48,18 @@ class TestShaderEffect : public QQuickShaderEffect
public:
QMatrix4x4 mat4x4Read() const { return QMatrix4x4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1); }
QVariant dummyRead() const { return QVariant(); }
- bool isConnected(const QMetaMethod &signal) const { return m_signals.contains(signal); }
+
+ int signalsConnected = 0;
protected:
- void connectNotify(const QMetaMethod &signal) { m_signals.append(signal); }
- void disconnectNotify(const QMetaMethod &signal) { m_signals.removeOne(signal); }
+ void connectNotify(const QMetaMethod &) { ++signalsConnected; }
+ void disconnectNotify(const QMetaMethod &) { --signalsConnected; }
signals:
void dummyChanged();
+ void sourceChanged();
private:
- QList<QMetaMethod> m_signals;
};
class tst_qquickshadereffect : public QQmlDataTest
@@ -75,6 +77,7 @@ private slots:
void deleteSourceItem();
void deleteShaderEffectSource();
+ void twoImagesOneShaderEffect();
private:
enum PresenceFlags {
@@ -82,12 +85,13 @@ private:
TexCoordPresent = 0x02,
MatrixPresent = 0x04,
OpacityPresent = 0x08,
- PropertyPresent = 0x10
+ SourcePresent = 0x10
};
};
tst_qquickshadereffect::tst_qquickshadereffect()
{
+ qmlRegisterType<TestShaderEffect>("ShaderEffectTest", 1, 0, "TestShaderEffect");
}
void tst_qquickshadereffect::initTestCase()
@@ -120,7 +124,7 @@ void tst_qquickshadereffect::lookThroughShaderCode_data()
"void main() { \n"
" gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; \n"
"}")
- << (VertexPresent | TexCoordPresent | MatrixPresent | OpacityPresent | PropertyPresent);
+ << (VertexPresent | TexCoordPresent | MatrixPresent | OpacityPresent | SourcePresent);
QTest::newRow("empty")
<< QByteArray(" ") // one space -- if completely empty, default will be used instead.
@@ -133,14 +137,14 @@ void tst_qquickshadereffect::lookThroughShaderCode_data()
"attribute highp vec4 qt_Vertex;\n"
"// attribute highp vec2 qt_MultiTexCoord0;")
<< QByteArray("uniform int source; // uniform lowp float qt_Opacity;")
- << (VertexPresent | PropertyPresent);
+ << (VertexPresent | SourcePresent);
QTest::newRow("inside block comments")
<< QByteArray("/*uniform highp mat4 qt_Matrix;\n"
"*/attribute highp vec4 qt_Vertex;\n"
"/*/attribute highp vec2 qt_MultiTexCoord0;//**/")
<< QByteArray("/**/uniform int source; /* uniform lowp float qt_Opacity; */")
- << (VertexPresent | PropertyPresent);
+ << (VertexPresent | SourcePresent);
QTest::newRow("inside preprocessor directive")
<< QByteArray("#define uniform\nhighp mat4 qt_Matrix;\n"
@@ -148,7 +152,7 @@ void tst_qquickshadereffect::lookThroughShaderCode_data()
"#if\\\nattribute highp vec2 qt_MultiTexCoord0;")
<< QByteArray("uniform int source;\n"
" # undef uniform lowp float qt_Opacity;")
- << (VertexPresent | PropertyPresent);
+ << (VertexPresent | SourcePresent);
QTest::newRow("line comments between")
@@ -156,21 +160,21 @@ void tst_qquickshadereffect::lookThroughShaderCode_data()
"attribute//\nhighp//\nvec4//\nqt_Vertex;\n"
" //*/ uniform \n attribute //\\ \n highp //// \n vec2 //* \n qt_MultiTexCoord0;")
<< QByteArray("uniform// lowp float qt_Opacity;\nsampler2D source;")
- << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent);
+ << (VertexPresent | TexCoordPresent | MatrixPresent | SourcePresent);
QTest::newRow("block comments between")
<< QByteArray("uniform/*foo*/highp/*/bar/*/mat4/**//**/qt_Matrix;\n"
"attribute/**/highp/**/vec4/**/qt_Vertex;\n"
" /* * */ attribute /*///*/ highp /****/ vec2 /**/ qt_MultiTexCoord0;")
<< QByteArray("uniform/*/ uniform//lowp/*float qt_Opacity;*/sampler2D source;")
- << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent);
+ << (VertexPresent | TexCoordPresent | MatrixPresent | SourcePresent);
QTest::newRow("preprocessor directive between")
<< QByteArray("uniform\n#foo\nhighp\n#bar\nmat4\n#baz\\\nblimey\nqt_Matrix;\n"
"attribute\n#\nhighp\n#\nvec4\n#\nqt_Vertex;\n"
" #uniform \n attribute \n # foo \n highp \n # bar \n vec2 \n#baz \n qt_MultiTexCoord0;")
<< QByteArray("uniform\n#if lowp float qt_Opacity;\nsampler2D source;")
- << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent);
+ << (VertexPresent | TexCoordPresent | MatrixPresent | SourcePresent);
QTest::newRow("newline between")
<< QByteArray("uniform\nhighp\nmat4\nqt_Matrix\n;\n"
@@ -178,7 +182,7 @@ void tst_qquickshadereffect::lookThroughShaderCode_data()
" \n attribute \n highp \n vec2 \n qt_Multi\nTexCoord0 \n ;")
<< QByteArray("uniform\nsampler2D\nsource;"
"uniform lowp float qt_Opacity;")
- << (VertexPresent | MatrixPresent | OpacityPresent | PropertyPresent);
+ << (VertexPresent | MatrixPresent | OpacityPresent | SourcePresent);
QTest::newRow("extra characters #1")
@@ -219,28 +223,28 @@ void tst_qquickshadereffect::lookThroughShaderCode_data()
"attribute highp qt_MultiTexCoord0;\n")
<< QByteArray("uniform lowp float qt_Opacity;\n"
"uniform mediump float source;\n")
- << (MatrixPresent | OpacityPresent | PropertyPresent);
+ << (MatrixPresent | OpacityPresent | SourcePresent);
QTest::newRow("property name #1")
<< QByteArray("uniform highp vec3 _0aA9zZ;")
<< QByteArray(" ")
- << int(PropertyPresent);
+ << int(SourcePresent);
QTest::newRow("property name #2")
<< QByteArray("uniform mediump vec2 x86;")
<< QByteArray(" ")
- << int(PropertyPresent);
+ << int(SourcePresent);
QTest::newRow("property name #3")
<< QByteArray("uniform lowp float X;")
<< QByteArray(" ")
- << int(PropertyPresent);
+ << int(SourcePresent);
QTest::newRow("property name #4")
<< QByteArray("uniform highp mat4 mat4x4;")
<< QByteArray(" ")
- << int(PropertyPresent);
+ << int(SourcePresent);
}
void tst_qquickshadereffect::lookThroughShaderCode()
@@ -249,9 +253,11 @@ void tst_qquickshadereffect::lookThroughShaderCode()
QFETCH(QByteArray, fragmentShader);
QFETCH(int, presenceFlags);
- TestShaderEffect item;
- QMetaMethod dummyChangedSignal = QMetaMethod::fromSignal(&TestShaderEffect::dummyChanged);
- QVERIFY(!item.isConnected(dummyChangedSignal)); // Nothing connected yet.
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\nimport ShaderEffectTest 1.0\nTestShaderEffect {}", QUrl());
+ QScopedPointer<TestShaderEffect> item(qobject_cast<TestShaderEffect*>(component.create()));
+ QCOMPARE(item->signalsConnected, 1);
QString expected;
if ((presenceFlags & VertexPresent) == 0)
@@ -263,12 +269,12 @@ void tst_qquickshadereffect::lookThroughShaderCode()
if ((presenceFlags & OpacityPresent) == 0)
expected += "Warning: Shaders are missing reference to \'qt_Opacity\'.\n";
- item.setVertexShader(vertexShader);
- item.setFragmentShader(fragmentShader);
- QCOMPARE(item.parseLog(), expected);
+ item->setVertexShader(vertexShader);
+ item->setFragmentShader(fragmentShader);
+ QCOMPARE(item->parseLog(), expected);
// If the uniform was successfully parsed, the notify signal has been connected to an update slot.
- QCOMPARE(item.isConnected(dummyChangedSignal), (presenceFlags & PropertyPresent) != 0);
+ QCOMPARE(item->signalsConnected, (presenceFlags & SourcePresent) ? 2 : 1);
}
void tst_qquickshadereffect::deleteSourceItem()
@@ -301,6 +307,19 @@ void tst_qquickshadereffect::deleteShaderEffectSource()
delete view;
}
+void tst_qquickshadereffect::twoImagesOneShaderEffect()
+{
+ // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash
+ QQuickView *view = new QQuickView(0);
+ view->setSource(QUrl::fromLocalFile(testFile("twoImagesOneShaderEffect.qml")));
+ view->show();
+ QVERIFY(QTest::qWaitForWindowExposed(view));
+ QVERIFY(view);
+ QObject *obj = view->rootObject();
+ QVERIFY(obj);
+ delete view;
+}
+
QTEST_MAIN(tst_qquickshadereffect)
#include "tst_qquickshadereffect.moc"
diff --git a/tests/auto/quick/qquicktext/BLACKLIST b/tests/auto/quick/qquicktext/BLACKLIST
index 223d8feb67..f400af1d10 100644
--- a/tests/auto/quick/qquicktext/BLACKLIST
+++ b/tests/auto/quick/qquicktext/BLACKLIST
@@ -4,3 +4,5 @@
*
[lineLaidOutRelayout]
msvc-2015
+[fontSizeMode]
+opensuse-42.1
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 6c0da40b8e..6f7d494255 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -2771,18 +2771,19 @@ void tst_qquicktext::lineLaidOutRelayout()
QVERIFY(!textPrivate->extra.isAllocated());
- qreal maxH = 0;
+ qreal y = 0.0;
for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
QTextLine line = textPrivate->layout.lineAt(i);
const QRectF r = line.rect();
- const qreal h = line.height();
if (r.x() == 0) {
- QCOMPARE(r.y(), i * h);
- maxH = qMax(maxH, r.y() + h);
+ QCOMPARE(r.y(), y);
} else {
+ if (qFuzzyIsNull(r.y()))
+ y = 0.0;
QCOMPARE(r.x(), myText->width() / 2);
- QCOMPARE(r.y(), i * h - maxH);
+ QCOMPARE(r.y(), y);
}
+ y += line.height();
}
}
diff --git a/tests/auto/quick/qquicktextinput/data/focusOnlyOneOnPress.qml b/tests/auto/quick/qquicktextinput/data/focusOnlyOneOnPress.qml
new file mode 100644
index 0000000000..037b36c8ff
--- /dev/null
+++ b/tests/auto/quick/qquicktextinput/data/focusOnlyOneOnPress.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.2
+
+Rectangle {
+ width: 400
+ height: 400
+
+ Column {
+ spacing: 5
+ TextInput {
+ objectName: "first"
+ onEditingFinished: second.focus = true
+ width: 100
+ Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 }
+ }
+ TextInput {
+ id: second
+ objectName: "second"
+ onEditingFinished: third.focus = true
+ width: 100
+ Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 }
+ }
+ TextInput {
+ objectName: "third"
+ id: third
+ width: 100
+ Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 }
+ }
+ Component.onCompleted: {
+ second.focus = true
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index f505487a14..8dc3053d89 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -154,6 +154,7 @@ private slots:
#endif
void readOnly();
void focusOnPress();
+ void focusOnPressOnlyOneItem();
void openInputPanel();
void setHAlignClearCache();
@@ -200,6 +201,8 @@ private slots:
void implicitSize();
void implicitSizeBinding_data();
void implicitSizeBinding();
+ void implicitResize_data();
+ void implicitResize();
void negativeDimensions();
@@ -3511,6 +3514,46 @@ void tst_qquicktextinput::focusOnPress()
QTest::mouseRelease(&window, Qt::LeftButton, noModifiers);
}
+void tst_qquicktextinput::focusOnPressOnlyOneItem()
+{
+ QQuickView window(testFileUrl("focusOnlyOneOnPress.qml"));
+ window.show();
+ window.requestActivate();
+ QTest::qWaitForWindowActive(&window);
+
+ QQuickTextInput *first = window.rootObject()->findChild<QQuickTextInput*>("first");
+ QQuickTextInput *second = window.rootObject()->findChild<QQuickTextInput*>("second");
+ QQuickTextInput *third = window.rootObject()->findChild<QQuickTextInput*>("third");
+
+ // second is focused onComplete
+ QVERIFY(second->hasActiveFocus());
+
+ // and first will try focus when we press it
+ QVERIFY(first->focusOnPress());
+
+ // write some text to start editing
+ QTest::keyClick(&window, Qt::Key_A);
+
+ // click the first input. naturally, we are giving focus on press, but
+ // second's editingFinished also attempts to assign focus. lastly, focus
+ // should bounce back to second from first's editingFinished signal.
+ //
+ // this is a contrived example to be sure, but at the end of this, the
+ // important thing is that only one thing should have activeFocus.
+ Qt::KeyboardModifiers noModifiers = 0;
+ QTest::mousePress(&window, Qt::LeftButton, noModifiers, QPoint(10, 10));
+
+ // make sure the press is processed.
+ QGuiApplication::processEvents();
+
+ QVERIFY(second->hasActiveFocus()); // make sure it's still there
+ QVERIFY(!third->hasActiveFocus()); // make sure it didn't end up anywhere else
+ QVERIFY(!first->hasActiveFocus()); // make sure it didn't end up anywhere else
+
+ // reset state
+ QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, QPoint(10, 10));
+}
+
void tst_qquicktextinput::openInputPanel()
{
PlatformInputContext platformInputContext;
@@ -5969,6 +6012,39 @@ void tst_qquicktextinput::implicitSizeBinding()
QCOMPARE(textObject->height(), textObject->implicitHeight());
}
+void tst_qquicktextinput::implicitResize_data()
+{
+ QTest::addColumn<int>("alignment");
+ QTest::newRow("left") << int(Qt::AlignLeft);
+ QTest::newRow("center") << int(Qt::AlignHCenter);
+ QTest::newRow("right") << int(Qt::AlignRight);
+}
+
+void tst_qquicktextinput::implicitResize()
+{
+ QFETCH(int, alignment);
+
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\nTextInput { }", QUrl::fromLocalFile(""));
+
+ QScopedPointer<QQuickTextInput> textInput(qobject_cast<QQuickTextInput *>(component.create()));
+ QVERIFY(!textInput.isNull());
+
+ QScopedPointer<QQuickTextInput> textField(qobject_cast<QQuickTextInput *>(component.create()));
+ QVERIFY(!textField.isNull());
+ QQuickTextInputPrivate::get(textField.data())->setImplicitResizeEnabled(false);
+
+ textInput->setWidth(200);
+ textField->setImplicitWidth(200);
+
+ textInput->setHAlign(QQuickTextInput::HAlignment(alignment));
+ textField->setHAlign(QQuickTextInput::HAlignment(alignment));
+
+ textInput->setText("Qt");
+ textField->setText("Qt");
+
+ QCOMPARE(textField->positionToRectangle(0), textInput->positionToRectangle(0));
+}
void tst_qquicktextinput::negativeDimensions()
{
diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp
index 05922ae20f..fa9192edb4 100644
--- a/tests/auto/quick/qquickview/tst_qquickview.cpp
+++ b/tests/auto/quick/qquickview/tst_qquickview.cpp
@@ -36,6 +36,30 @@
#include <QtCore/QDebug>
#include <QtQml/qqmlengine.h>
+class SizeChangesListener : public QObject, public QVector<QSize>
+{
+ Q_OBJECT
+public:
+ explicit SizeChangesListener(QQuickItem *item);
+private slots:
+ void onSizeChanged();
+private:
+ QQuickItem *item;
+
+};
+
+SizeChangesListener::SizeChangesListener(QQuickItem *item) :
+ item(item)
+{
+ connect(item, &QQuickItem::widthChanged, this, &SizeChangesListener::onSizeChanged);
+ connect(item, &QQuickItem::heightChanged, this, &SizeChangesListener::onSizeChanged);
+}
+
+void SizeChangesListener::onSizeChanged()
+{
+ append(QSize(item->width(), item->height()));
+}
+
class tst_QQuickView : public QQmlDataTest
{
Q_OBJECT
@@ -127,7 +151,6 @@ void tst_QQuickView::resizemodeitem()
QCOMPARE(item->width(), 80.0);
QCOMPARE(item->height(), 100.0);
QTRY_COMPARE(view->size(), QSize(80, 100));
- QCOMPARE(view->size(), QSize(80, 100));
QCOMPARE(view->size(), view->sizeHint());
// size update from root object disabled
@@ -139,8 +162,16 @@ void tst_QQuickView::resizemodeitem()
QCOMPARE(QSize(item->width(), item->height()), view->sizeHint());
// size update from view
+ QCoreApplication::processEvents(); // make sure the last resize events are gone
+ SizeChangesListener sizeListener(item);
view->resize(QSize(200,300));
QTRY_COMPARE(item->width(), 200.0);
+
+ for (int i = 0; i < sizeListener.count(); ++i) {
+ // Check that we have the correct geometry on all signals
+ QCOMPARE(sizeListener.at(i), view->size());
+ }
+
QCOMPARE(item->height(), 300.0);
QCOMPARE(view->size(), QSize(200, 300));
QCOMPARE(view->size(), view->sizeHint());
diff --git a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
index 17c09805aa..cabfb97914 100644
--- a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
+++ b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
@@ -4094,9 +4094,10 @@ void tst_qquickvisualdatamodel::asynchronousRemove()
controller.incubateFor(50);
} while (timer.elapsed() < 1000 && controller.incubatingObjectCount() > 0);
- QVERIFY(requester.itemInitialized);
- QCOMPARE(requester.itemCreated, requester.itemInitialized);
- QCOMPARE(requester.itemDestroyed, requester.itemInitialized);
+ // The item was removed before incubation started. We should not have any item created.
+ QVERIFY(!requester.itemInitialized);
+ QVERIFY(!requester.itemCreated);
+ QVERIFY(!requester.itemDestroyed);
} else {
item = qobject_cast<QQuickItem*>(visualModel->object(completeIndex, false));
QVERIFY(item);
diff --git a/tests/auto/quick/qquickwindow/data/windowWithScreen.qml b/tests/auto/quick/qquickwindow/data/windowWithScreen.qml
new file mode 100644
index 0000000000..fdc0be3388
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/windowWithScreen.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+import QtQuick.Window 2.3 as Window
+
+Window.Window {
+ color: "#00FF00"
+ targetScreen: Qt.application.screens[0]
+ Item {
+ objectName: "item"
+ }
+}
diff --git a/tests/auto/quick/qquickwindow/qquickwindow.pro b/tests/auto/quick/qquickwindow/qquickwindow.pro
index f0d287f30f..05093ba8e0 100644
--- a/tests/auto/quick/qquickwindow/qquickwindow.pro
+++ b/tests/auto/quick/qquickwindow/qquickwindow.pro
@@ -7,7 +7,7 @@ include(../shared/util.pri)
macx:CONFIG -= app_bundle
-QT += core-private gui-private qml-private quick-private testlib
+QT += core-private qml-private quick-private testlib
TESTDATA = data/*
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 0985198d65..bfffa6f7f5 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -40,7 +40,6 @@
#include "../shared/visualtestutil.h"
#include "../shared/viewtestutil.h"
#include <QSignalSpy>
-#include <qpa/qwindowsysteminterface.h>
#include <private/qquickwindow_p.h>
#include <private/qguiapplication_p.h>
#include <QRunnable>
@@ -158,6 +157,7 @@ public:
lastVelocity = lastVelocityFromMouseMove = QVector2D();
lastMousePos = QPointF();
lastMouseCapabilityFlags = 0;
+ touchEventCount = 0;
}
static void clearMousePressCounter()
@@ -275,22 +275,14 @@ class tst_qquickwindow : public QQmlDataTest
Q_OBJECT
public:
tst_qquickwindow()
+ : touchDevice(QTest::createTouchDevice())
+ , touchDeviceWithVelocity(QTest::createTouchDevice())
{
QQuickWindow::setDefaultAlphaBuffer(true);
+ touchDeviceWithVelocity->setCapabilities(QTouchDevice::Position | QTouchDevice::Velocity);
}
private slots:
- void initTestCase()
- {
- QQmlDataTest::initTestCase();
- touchDevice = new QTouchDevice;
- touchDevice->setType(QTouchDevice::TouchScreen);
- QWindowSystemInterface::registerTouchDevice(touchDevice);
- touchDeviceWithVelocity = new QTouchDevice;
- touchDeviceWithVelocity->setType(QTouchDevice::TouchScreen);
- touchDeviceWithVelocity->setCapabilities(QTouchDevice::Position | QTouchDevice::Velocity);
- QWindowSystemInterface::registerTouchDevice(touchDeviceWithVelocity);
- }
void cleanup();
#ifndef QT_NO_OPENGL
void openglContextCreatedSignal();
@@ -311,11 +303,15 @@ private slots:
void touchEvent_reentrant();
void touchEvent_velocity();
+ void mergeTouchPointLists_data();
+ void mergeTouchPointLists();
+
void mouseFromTouch_basic();
void clearWindow();
void qmlCreation();
+ void qmlCreationWithScreen();
void clearColor();
void defaultState();
@@ -370,6 +366,10 @@ private slots:
void testRenderJob();
void testHoverChildMouseEventFilter();
+ void testHoverTimestamp();
+
+ void pointerEventTypeAndPointCount();
+
private:
QTouchDevice *touchDevice;
QTouchDevice *touchDeviceWithVelocity;
@@ -529,9 +529,8 @@ void tst_qquickwindow::touchEvent_basic()
// press single point
QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window);
- QTest::qWait(50);
-
- QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QQuickTouchUtils::flush(window);
+ QTRY_COMPARE(topItem->lastEvent.touchPoints.count(), 1);
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
@@ -539,9 +538,10 @@ void tst_qquickwindow::touchEvent_basic()
// would put the decorated window at that position rather than the window itself.
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
topItem->reset();
+ QTest::touchEvent(window, touchDevice).release(0, topItem->mapToScene(pos).toPoint(), window);
// press multiple points
- QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window)
+ QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window)
.press(1, bottomItem->mapToScene(pos).toPoint(), window);
QQuickTouchUtils::flush(window);
QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
@@ -551,6 +551,7 @@ void tst_qquickwindow::touchEvent_basic()
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
topItem->reset();
bottomItem->reset();
+ QTest::touchEvent(window, touchDevice).release(0, topItem->mapToScene(pos).toPoint(), window).release(1, bottomItem->mapToScene(pos).toPoint(), window);
// touch point on top item moves to bottom item, but top item should still receive the event
QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window);
@@ -561,6 +562,7 @@ void tst_qquickwindow::touchEvent_basic()
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved,
makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
topItem->reset();
+ QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window);
// touch point on bottom item moves to top item, but bottom item should still receive the event
QTest::touchEvent(window, touchDevice).press(0, bottomItem->mapToScene(pos).toPoint(), window);
@@ -571,6 +573,7 @@ void tst_qquickwindow::touchEvent_basic()
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved,
makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos)));
bottomItem->reset();
+ QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window);
// a single stationary press on an item shouldn't cause an event
QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window);
@@ -675,6 +678,7 @@ void tst_qquickwindow::touchEvent_propagation()
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))));
+ QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window);
// touch top and middle items, middle item should get both events
QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
@@ -686,6 +690,8 @@ void tst_qquickwindow::touchEvent_propagation()
COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
(QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))
<< makeTouchPoint(middleItem, pos) )));
+ QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window)
+ .release(1, pointInMiddleItem, window);
middleItem->reset();
// disable middleItem as well
@@ -710,6 +716,8 @@ void tst_qquickwindow::touchEvent_propagation()
bottomItem->acceptTouchEvents = acceptTouchEvents;
bottomItem->setEnabled(enableItem);
bottomItem->setVisible(showItem);
+ QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window)
+ .release(1, pointInMiddleItem, window);
// no events should be received
QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
@@ -719,7 +727,9 @@ void tst_qquickwindow::touchEvent_propagation()
QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
-
+ QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window)
+ .release(1, pointInMiddleItem, window)
+ .release(2, pointInBottomItem, window);
topItem->reset();
middleItem->reset();
bottomItem->reset();
@@ -745,6 +755,7 @@ void tst_qquickwindow::touchEvent_propagation()
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
makeTouchPoint(topItem, pos)));
}
+ QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window);
delete topItem;
delete middleItem;
@@ -863,6 +874,8 @@ void tst_qquickwindow::touchEvent_velocity()
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points);
QGuiApplication::processEvents();
QQuickTouchUtils::flush(window);
+ QCOMPARE(item->touchEventCount, 1);
+
points[0].state = Qt::TouchPointMoved;
points[0].area.adjust(5, 5, 5, 5);
QVector2D velocity(1.5, 2.5);
@@ -895,6 +908,67 @@ void tst_qquickwindow::touchEvent_velocity()
delete item;
}
+void tst_qquickwindow::mergeTouchPointLists_data()
+{
+ QTest::addColumn<QVector<QQuickItem*>>("list1");
+ QTest::addColumn<QVector<QQuickItem*>>("list2");
+ QTest::addColumn<QVector<QQuickItem*>>("expected");
+ QTest::addColumn<bool>("showItem");
+
+ // FIXME: do not leak all these items
+ auto item1 = new QQuickItem();
+ auto item2 = new QQuickItem();
+ auto item3 = new QQuickItem();
+ auto item4 = new QQuickItem();
+ auto item5 = new QQuickItem();
+
+ QTest::newRow("empty") << QVector<QQuickItem*>() << QVector<QQuickItem*>() << QVector<QQuickItem*>();
+ QTest::newRow("single list left")
+ << (QVector<QQuickItem*>() << item1 << item2 << item3)
+ << QVector<QQuickItem*>()
+ << (QVector<QQuickItem*>() << item1 << item2 << item3);
+ QTest::newRow("single list right")
+ << QVector<QQuickItem*>()
+ << (QVector<QQuickItem*>() << item1 << item2 << item3)
+ << (QVector<QQuickItem*>() << item1 << item2 << item3);
+ QTest::newRow("two lists identical")
+ << (QVector<QQuickItem*>() << item1 << item2 << item3)
+ << (QVector<QQuickItem*>() << item1 << item2 << item3)
+ << (QVector<QQuickItem*>() << item1 << item2 << item3);
+ QTest::newRow("two lists 1")
+ << (QVector<QQuickItem*>() << item1 << item2 << item5)
+ << (QVector<QQuickItem*>() << item3 << item4 << item5)
+ << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4 << item5);
+ QTest::newRow("two lists 2")
+ << (QVector<QQuickItem*>() << item1 << item2 << item5)
+ << (QVector<QQuickItem*>() << item3 << item4 << item5)
+ << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4 << item5);
+ QTest::newRow("two lists 3")
+ << (QVector<QQuickItem*>() << item1 << item2 << item3)
+ << (QVector<QQuickItem*>() << item1 << item4 << item5)
+ << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4 << item5);
+ QTest::newRow("two lists 4")
+ << (QVector<QQuickItem*>() << item1 << item3 << item4)
+ << (QVector<QQuickItem*>() << item2 << item3 << item5)
+ << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4 << item5);
+ QTest::newRow("two lists 5")
+ << (QVector<QQuickItem*>() << item1 << item2 << item4)
+ << (QVector<QQuickItem*>() << item1 << item3 << item4)
+ << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4);
+}
+
+void tst_qquickwindow::mergeTouchPointLists()
+{
+ QFETCH(QVector<QQuickItem*>, list1);
+ QFETCH(QVector<QQuickItem*>, list2);
+ QFETCH(QVector<QQuickItem*>, expected);
+
+ QQuickWindow win;
+ auto windowPrivate = QQuickWindowPrivate::get(&win);
+ auto targetList = windowPrivate->mergePointerTargets(list1, list2);
+ QCOMPARE(targetList, expected);
+}
+
void tst_qquickwindow::mouseFromTouch_basic()
{
// Turn off accepting touch events with acceptTouchEvents. This
@@ -1049,6 +1123,24 @@ void tst_qquickwindow::qmlCreation()
QCOMPARE(item->window(), window);
}
+void tst_qquickwindow::qmlCreationWithScreen()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("windowWithScreen.qml"));
+ QObject *created = component.create();
+ QScopedPointer<QObject> cleanup(created);
+ QVERIFY(created);
+
+ QQuickWindow *window = qobject_cast<QQuickWindow*>(created);
+ QVERIFY(window);
+ QCOMPARE(window->color(), QColor(Qt::green));
+
+ QQuickItem *item = window->findChild<QQuickItem*>("item");
+ QVERIFY(item);
+ QCOMPARE(item->window(), window);
+}
+
void tst_qquickwindow::clearColor()
{
//::grab examines rendering to make sure it works visually
@@ -2326,6 +2418,142 @@ void tst_qquickwindow::testHoverChildMouseEventFilter()
QCOMPARE(middleItem->eventCount(QEvent::HoverEnter), 0);
}
+class HoverTimestampConsumer : public QQuickItem
+{
+ Q_OBJECT
+public:
+ HoverTimestampConsumer(QQuickItem *parent = 0)
+ : QQuickItem(parent)
+ {
+ setAcceptHoverEvents(true);
+ }
+
+ void hoverEnterEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); }
+ void hoverLeaveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); }
+ void hoverMoveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); }
+
+ QList<ulong> hoverTimestamps;
+};
+
+// Checks that a QHoverEvent carries the timestamp of the QMouseEvent that caused it.
+// QTBUG-54600
+void tst_qquickwindow::testHoverTimestamp()
+{
+ QQuickWindow window;
+
+ window.resize(200, 200);
+ window.setPosition(100, 100);
+ window.setTitle(QTest::currentTestFunction());
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ HoverTimestampConsumer *hoverConsumer = new HoverTimestampConsumer(window.contentItem());
+ hoverConsumer->setWidth(100);
+ hoverConsumer->setHeight(100);
+ hoverConsumer->setX(50);
+ hoverConsumer->setY(50);
+
+ // First position, outside
+ {
+ QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(40, 40), QPointF(40, 40), QPointF(140, 140),
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized);
+ mouseEvent.setTimestamp(10);
+ QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent));
+ }
+
+ // Enter
+ {
+ QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(50, 50), QPointF(50, 50), QPointF(150, 150),
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized);
+ mouseEvent.setTimestamp(20);
+ QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent));
+ }
+ QCOMPARE(hoverConsumer->hoverTimestamps.size(), 1);
+ QCOMPARE(hoverConsumer->hoverTimestamps.last(), 20UL);
+
+ // Move
+ {
+ QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(60, 60), QPointF(60, 60), QPointF(160, 160),
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized);
+ mouseEvent.setTimestamp(30);
+ QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent));
+ }
+ QCOMPARE(hoverConsumer->hoverTimestamps.size(), 2);
+ QCOMPARE(hoverConsumer->hoverTimestamps.last(), 30UL);
+
+ // Move
+ {
+ QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(100, 100), QPointF(100, 100), QPointF(200, 200),
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized);
+ mouseEvent.setTimestamp(40);
+ QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent));
+ }
+ QCOMPARE(hoverConsumer->hoverTimestamps.size(), 3);
+ QCOMPARE(hoverConsumer->hoverTimestamps.last(), 40UL);
+
+ // Leave
+ {
+ QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(160, 160), QPointF(160, 160), QPointF(260, 260),
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized);
+ mouseEvent.setTimestamp(5);
+ QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent));
+ }
+ QCOMPARE(hoverConsumer->hoverTimestamps.size(), 4);
+ QCOMPARE(hoverConsumer->hoverTimestamps.last(), 5UL);
+}
+
+void tst_qquickwindow::pointerEventTypeAndPointCount()
+{
+ QPointF localPosition(33, 66);
+ QPointF scenePosition(133, 166);
+ QPointF screenPosition(333, 366);
+ QMouseEvent me(QEvent::MouseButtonPress, localPosition, scenePosition, screenPosition,
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ QTouchEvent te(QEvent::TouchBegin, touchDevice, Qt::NoModifier, Qt::TouchPointPressed,
+ QList<QTouchEvent::TouchPoint>() << QTouchEvent::TouchPoint(1));
+
+
+ QQuickPointerMouseEvent pme;
+ pme.reset(&me);
+ QVERIFY(pme.isValid());
+ QCOMPARE(pme.asMouseEvent(localPosition), &me);
+ QVERIFY(pme.asPointerMouseEvent());
+ QVERIFY(!pme.asPointerTouchEvent());
+ QVERIFY(!pme.asPointerTabletEvent());
+// QVERIFY(!pe->asTabletEvent()); // TODO
+ QCOMPARE(pme.pointCount(), 1);
+ QCOMPARE(pme.point(0)->scenePos(), scenePosition);
+ QCOMPARE(pme.asMouseEvent(localPosition)->localPos(), localPosition);
+ QCOMPARE(pme.asMouseEvent(localPosition)->screenPos(), screenPosition);
+
+ QQuickPointerTouchEvent pte;
+ pte.reset(&te);
+ QVERIFY(pte.isValid());
+ QCOMPARE(pte.asTouchEvent(), &te);
+ QVERIFY(!pte.asPointerMouseEvent());
+ QVERIFY(pte.asPointerTouchEvent());
+ QVERIFY(!pte.asPointerTabletEvent());
+ QVERIFY(pte.asTouchEvent());
+// QVERIFY(!pte.asTabletEvent()); // TODO
+ QCOMPARE(pte.pointCount(), 1);
+ QCOMPARE(pte.touchPointById(1)->id(), 1);
+ QVERIFY(!pte.touchPointById(0));
+
+ te.setTouchPoints(QList<QTouchEvent::TouchPoint>() << QTouchEvent::TouchPoint(1) << QTouchEvent::TouchPoint(2));
+ pte.reset(&te);
+ QCOMPARE(pte.pointCount(), 2);
+ QCOMPARE(pte.touchPointById(1)->id(), 1);
+ QCOMPARE(pte.touchPointById(2)->id(), 2);
+ QVERIFY(!pte.touchPointById(0));
+
+ te.setTouchPoints(QList<QTouchEvent::TouchPoint>() << QTouchEvent::TouchPoint(2));
+ pte.reset(&te);
+ QCOMPARE(pte.pointCount(), 1);
+ QCOMPARE(pte.touchPointById(2)->id(), 2);
+ QVERIFY(!pte.touchPointById(1));
+ QVERIFY(!pte.touchPointById(0));
+}
+
QTEST_MAIN(tst_qquickwindow)
#include "tst_qquickwindow.moc"
diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro
index 70e5b8ef6a..6e9998c061 100644
--- a/tests/auto/quick/quick.pro
+++ b/tests/auto/quick/quick.pro
@@ -4,8 +4,9 @@ PUBLICTESTS += \
geometry \
qquickpixmapcache
-contains(QT_CONFIG, opengl(es1|es2)?) {
+qtConfig(opengl(es1|es2)?) {
PUBLICTESTS += \
+ drawingmodes \
rendernode
qtHaveModule(widgets): PUBLICTESTS += nodes
@@ -88,9 +89,9 @@ QUICKTESTS = \
SUBDIRS += $$PUBLICTESTS
-!contains(QT_CONFIG, accessibility):QUICKTESTS -= qquickaccessible
+!qtConfig(accessibility):QUICKTESTS -= qquickaccessible
-contains(QT_CONFIG, private_tests) {
+qtConfig(private_tests) {
SUBDIRS += $$PRIVATETESTS
SUBDIRS += $$QUICKTESTS
}
diff --git a/tests/auto/quick/rendernode/tst_rendernode.cpp b/tests/auto/quick/rendernode/tst_rendernode.cpp
index 313e5ac196..e15649e62c 100644
--- a/tests/auto/quick/rendernode/tst_rendernode.cpp
+++ b/tests/auto/quick/rendernode/tst_rendernode.cpp
@@ -215,16 +215,18 @@ void tst_rendernode::renderOrder()
QSKIP("This test does not work at display depths < 24");
QImage fb = runTest("RenderOrder.qml");
- QCOMPARE(fb.width(), 200);
- QCOMPARE(fb.height(), 200);
+ QQuickView v;
+ int devicePixelRatio = static_cast<int>(v.devicePixelRatio());
+ QCOMPARE(fb.width(), 200 * devicePixelRatio);
+ QCOMPARE(fb.height(), 200 * devicePixelRatio);
- QCOMPARE(fb.pixel(50, 50), qRgb(0xff, 0xff, 0xff));
- QCOMPARE(fb.pixel(50, 150), qRgb(0xff, 0xff, 0xff));
- QCOMPARE(fb.pixel(150, 50), qRgb(0x00, 0x00, 0xff));
+ QCOMPARE(fb.pixel(50 * devicePixelRatio, 50 * devicePixelRatio), qRgb(0xff, 0xff, 0xff));
+ QCOMPARE(fb.pixel(50 * devicePixelRatio, 150 * devicePixelRatio), qRgb(0xff, 0xff, 0xff));
+ QCOMPARE(fb.pixel(150 * devicePixelRatio, 50 * devicePixelRatio), qRgb(0x00, 0x00, 0xff));
QByteArray errorMessage;
- QVERIFY2(fuzzyCompareColor(fb.pixel(150, 150), qRgb(0x7f, 0x7f, 0xff), &errorMessage),
- msgColorMismatchAt(errorMessage, 150, 150).constData());
+ QVERIFY2(fuzzyCompareColor(fb.pixel(150 * devicePixelRatio, 150 * devicePixelRatio), qRgb(0x7f, 0x7f, 0xff), &errorMessage),
+ msgColorMismatchAt(errorMessage, 150 * devicePixelRatio, 150 * devicePixelRatio).constData());
}
/* The test uses a number of nested rectangles with clipping
diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
index c0d1b53e92..f6d624d871 100644
--- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp
+++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
@@ -44,6 +44,7 @@
#include <private/qsgcontext_p.h>
#include <private/qsgrenderloop_p.h>
+#include "../../shared/util.h"
#include "../shared/visualtestutil.h"
using namespace QQuickVisualTestUtil;
@@ -92,7 +93,7 @@ private:
QColor m_color;
};
-class tst_SceneGraph : public QObject
+class tst_SceneGraph : public QQmlDataTest
{
Q_OBJECT
@@ -112,6 +113,7 @@ private slots:
private:
bool m_brokenMipmapSupport;
+ QQuickView *createView(const QString &file, QWindow *parent = 0, int x = -1, int y = -1, int w = -1, int h = -1);
};
template <typename T> class ScopedList : public QList<T> {
@@ -123,6 +125,8 @@ void tst_SceneGraph::initTestCase()
{
qmlRegisterType<PerPixelRect>("SceneGraphTest", 1, 0, "PerPixelRect");
+ QQmlDataTest::initTestCase();
+
QSGRenderLoop *loop = QSGRenderLoop::instance();
qDebug() << "RenderLoop: " << loop;
@@ -162,26 +166,16 @@ void tst_SceneGraph::initTestCase()
#endif
}
-QQuickView *createView(const QString &file, QWindow *parent = 0, int x = -1, int y = -1, int w = -1, int h = -1)
+QQuickView *tst_SceneGraph::createView(const QString &file, QWindow *parent, int x, int y, int w, int h)
{
QQuickView *view = new QQuickView(parent);
- view->setSource(QUrl::fromLocalFile("data/" + file));
+ view->setSource(testFileUrl(file));
if (x >= 0 && y >= 0) view->setPosition(x, y);
if (w >= 0 && h >= 0) view->resize(w, h);
view->show();
return view;
}
-QImage showAndGrab(const QString &file, int w, int h)
-{
- QQuickView view;
- view.setSource(QUrl::fromLocalFile(QStringLiteral("data/") + file));
- if (w >= 0 && h >= 0)
- view.resize(w, h);
- view.create();
- return view.grabWindow();
-}
-
// Assumes the images are opaque white...
bool containsSomethingOtherThanWhite(const QImage &image)
{
@@ -384,17 +378,17 @@ void tst_SceneGraph::render_data()
QTest::addColumn<QList<Sample> >("finalStage");
QList<QString> files;
- files << "data/render_DrawSets.qml"
- << "data/render_Overlap.qml"
- << "data/render_MovingOverlap.qml"
- << "data/render_BreakOpacityBatch.qml"
- << "data/render_OutOfFloatRange.qml"
- << "data/render_StackingOrder.qml"
- << "data/render_ImageFiltering.qml"
- << "data/render_bug37422.qml"
- << "data/render_OpacityThroughBatchRoot.qml";
+ files << "render_DrawSets.qml"
+ << "render_Overlap.qml"
+ << "render_MovingOverlap.qml"
+ << "render_BreakOpacityBatch.qml"
+ << "render_OutOfFloatRange.qml"
+ << "render_StackingOrder.qml"
+ << "render_ImageFiltering.qml"
+ << "render_bug37422.qml"
+ << "render_OpacityThroughBatchRoot.qml";
if (!m_brokenMipmapSupport)
- files << "data/render_Mipmap.qml";
+ files << "render_Mipmap.qml";
QRegExp sampleCount("#samples: *(\\d+)");
// X:int Y:int R:float G:float B:float Error:float
@@ -402,7 +396,7 @@ void tst_SceneGraph::render_data()
QRegExp finalSamples("#final: *(\\d+) *(\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+)");
foreach (QString fileName, files) {
- QFile file(fileName);
+ QFile file(testFile(fileName));
if (!file.open(QFile::ReadOnly)) {
qFatal("render_data: QFile::open failed! file=%s, error=%s",
qPrintable(fileName), qPrintable(file.errorString()));
@@ -452,7 +446,7 @@ void tst_SceneGraph::render()
QQuickView view;
view.rootContext()->setContextProperty("suite", &suite);
- view.setSource(QUrl::fromLocalFile(file));
+ view.setSource(testFileUrl(file));
view.setResizeMode(QQuickView::SizeViewToRootObject);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
@@ -501,7 +495,7 @@ void tst_SceneGraph::hideWithOtherContext()
{
QQuickView view;
- view.setSource(QUrl::fromLocalFile("data/simple.qml"));
+ view.setSource(testFileUrl("simple.qml"));
view.setResizeMode(QQuickView::SizeViewToRootObject);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
@@ -549,6 +543,7 @@ void tst_SceneGraph::createTextureFromImage()
QQuickView view;
view.show();
QTest::qWaitForWindowExposed(&view);
+ QTRY_VERIFY(view.isSceneGraphInitialized());
QScopedPointer<QSGTexture> texture(view.createTextureFromImage(image, (QQuickWindow::CreateTextureOptions) flags));
QCOMPARE(texture->hasAlphaChannel(), expectedAlpha);
diff --git a/tests/auto/quick/touchmouse/data/touchpointdeliveryorder.qml b/tests/auto/quick/touchmouse/data/touchpointdeliveryorder.qml
new file mode 100644
index 0000000000..9f67c226a0
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/touchpointdeliveryorder.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Rectangle {
+ id: root
+
+ width: 600
+ height: 400
+
+ EventItem {
+ objectName: "background"
+ width: 600
+ height: 400
+ Rectangle { anchors.fill: parent; color: "lightsteelblue" }
+
+ EventItem {
+ objectName: "left"
+ width: 300
+ height: 300
+ Rectangle { anchors.fill: parent; color: "yellow" }
+ }
+
+ EventItem {
+ objectName: "right"
+ x: 300
+ width: 300
+ height: 300
+ Rectangle { anchors.fill: parent; color: "green" }
+ }
+
+ EventItem {
+ objectName: "middle"
+ x: 150
+ width: 300
+ height: 300
+ Rectangle { anchors.fill: parent; color: "blue" }
+ }
+ }
+}
diff --git a/tests/auto/quick/touchmouse/touchmouse.pro b/tests/auto/quick/touchmouse/touchmouse.pro
index 0df9bc53d3..49818bb399 100644
--- a/tests/auto/quick/touchmouse/touchmouse.pro
+++ b/tests/auto/quick/touchmouse/touchmouse.pro
@@ -1,7 +1,7 @@
CONFIG += testcase
TARGET = tst_touchmouse
-QT += core-private gui-private qml-private quick-private testlib
+QT += core-private qml-private quick-private testlib
macx:CONFIG -= app_bundle
diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
index 15d7ffd9d9..1594da46bd 100644
--- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp
+++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
@@ -33,13 +33,12 @@
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquickevents_p_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuick/private/qquickmultipointtoucharea_p.h>
#include <QtQuick/private/qquickpincharea_p.h>
#include <QtQuick/private/qquickflickable_p.h>
-#include <qpa/qwindowsysteminterface.h>
-
-#include <private/qquickwindow_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
@@ -66,15 +65,22 @@ struct Event
class EventItem : public QQuickItem
{
Q_OBJECT
+
+Q_SIGNALS:
+ void onTouchEvent(QQuickItem *receiver);
+
public:
EventItem(QQuickItem *parent = 0)
: QQuickItem(parent), acceptMouse(false), acceptTouch(false), filterTouch(false)
- {}
+ {
+ setAcceptedMouseButtons(Qt::LeftButton);
+ }
void touchEvent(QTouchEvent *event)
{
eventList.append(Event(event->type(), event->touchPoints()));
event->setAccepted(acceptTouch);
+ emit onTouchEvent(this);
}
void mousePressEvent(QMouseEvent *event)
{
@@ -132,7 +138,7 @@ class tst_TouchMouse : public QQmlDataTest
Q_OBJECT
public:
tst_TouchMouse()
- :device(0)
+ :device(QTest::createTouchDevice())
{}
private slots:
@@ -155,6 +161,7 @@ private slots:
void tapOnDismissiveTopMouseAreaClicksBottomOne();
void touchGrabCausesMouseUngrab();
+ void touchPointDeliveryOrder();
void hoverEnabled();
@@ -191,11 +198,6 @@ void tst_TouchMouse::initTestCase()
QQmlDataTest::initTestCase();
qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem");
- if (!device) {
- device = new QTouchDevice;
- device->setType(QTouchDevice::TouchScreen);
- QWindowSystemInterface::registerTouchDevice(device);
- }
}
void tst_TouchMouse::simpleTouchEvent()
@@ -217,15 +219,17 @@ void tst_TouchMouse::simpleTouchEvent()
p1 = QPoint(20, 20);
QTest::touchEvent(window, device).press(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 1);
+ // Get a touch and then mouse event offered
+ QCOMPARE(eventItem1->eventList.size(), 2);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
p1 += QPoint(10, 0);
QTest::touchEvent(window, device).move(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 1);
+ // Not accepted, no updates
+ QCOMPARE(eventItem1->eventList.size(), 2);
QTest::touchEvent(window, device).release(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 1);
+ QCOMPARE(eventItem1->eventList.size(), 2);
eventItem1->eventList.clear();
// Accept touch
@@ -256,8 +260,7 @@ void tst_TouchMouse::simpleTouchEvent()
QCOMPARE(eventItem1->eventList.size(), 2);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
- QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
- QCOMPARE(windowPriv->mouseGrabberItem, eventItem1);
+ QCOMPARE(window->mouseGrabberItem(), eventItem1);
QPoint localPos = eventItem1->mapFromScene(p1).toPoint();
QPoint globalPos = window->mapToGlobal(p1);
@@ -292,17 +295,16 @@ void tst_TouchMouse::simpleTouchEvent()
p1 = QPoint(20, 20);
QTest::touchEvent(window, device).press(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 2);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
- QCOMPARE(eventItem1->eventList.at(2).type, QEvent::UngrabMouse);
p1 += QPoint(10, 0);
QTest::touchEvent(window, device).move(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 2);
QTest::touchEvent(window, device).release(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 2);
eventItem1->eventList.clear();
// wait to avoid getting a double click event
@@ -579,8 +581,9 @@ void tst_TouchMouse::buttonOnFlickable()
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
QCOMPARE(windowPriv->touchMouseId, 0);
- QCOMPARE(windowPriv->itemForTouchPointId[0], eventItem1);
- QCOMPARE(windowPriv->mouseGrabberItem, eventItem1);
+ auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent();
+ QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1);
+ QCOMPARE(window->mouseGrabberItem(), eventItem1);
p1 += QPoint(0, -10);
QPoint p2 = p1 + QPoint(0, -10);
@@ -598,9 +601,9 @@ void tst_TouchMouse::buttonOnFlickable()
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate);
QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove);
- QCOMPARE(windowPriv->mouseGrabberItem, flickable);
+ QCOMPARE(window->mouseGrabberItem(), flickable);
QCOMPARE(windowPriv->touchMouseId, 0);
- QCOMPARE(windowPriv->itemForTouchPointId[0], flickable);
+ QCOMPARE(pointerEvent->point(0)->grabber(), flickable);
QVERIFY(flickable->isMovingVertically());
QTest::touchEvent(window, device).release(0, p3, window);
@@ -660,12 +663,13 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable()
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
QCOMPARE(filteredEventList.count(), 1);
- // eventItem1 should have the mouse grab, and have moved the itemForTouchPointId
+ // eventItem1 should have the mouse grab, and have moved the grab
// for the touchMouseId to the new grabber.
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
QCOMPARE(windowPriv->touchMouseId, 0);
- QCOMPARE(windowPriv->itemForTouchPointId[0], eventItem1);
- QCOMPARE(windowPriv->mouseGrabberItem, eventItem1);
+ auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent();
+ QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1);
+ QCOMPARE(window->mouseGrabberItem(), eventItem1);
p1 += QPoint(0, -10);
QPoint p2 = p1 + QPoint(0, -10);
@@ -681,9 +685,9 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable()
// flickable should have the mouse grab, and have moved the itemForTouchPointId
// for the touchMouseId to the new grabber.
- QCOMPARE(windowPriv->mouseGrabberItem, flickable);
+ QCOMPARE(window->mouseGrabberItem(), flickable);
QCOMPARE(windowPriv->touchMouseId, 0);
- QCOMPARE(windowPriv->itemForTouchPointId[0], flickable);
+ QCOMPARE(pointerEvent->point(0)->grabber(), flickable);
QTest::touchEvent(window, device).release(0, p3, window);
QQuickTouchUtils::flush(window);
@@ -1097,9 +1101,7 @@ void tst_TouchMouse::mouseOnFlickableOnPinch()
pinchSequence.move(0, p, window).commit();
QQuickTouchUtils::flush(window);
- QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
- qDebug() << "Mouse Grabber: " << windowPriv->mouseGrabberItem << " itemForTouchPointId: " << windowPriv->itemForTouchPointId;
- QCOMPARE(windowPriv->mouseGrabberItem, flickable);
+ QCOMPARE(window->mouseGrabberItem(), flickable);
// Add a second finger, this should lead to stealing
p1 = QPoint(40, 100);
@@ -1229,14 +1231,117 @@ void tst_TouchMouse::touchGrabCausesMouseUngrab()
delete window;
}
+void tst_TouchMouse::touchPointDeliveryOrder()
+{
+ // Touch points should be first delivered to the item under the primary finger
+ QScopedPointer<QQuickView> window(createView());
+
+ window->setSource(testFileUrl("touchpointdeliveryorder.qml"));
+ /*
+ The items are positioned from left to right:
+ | background |
+ | left |
+ | | right |
+ | middle |
+ 0 150 300 450 600
+ */
+ QPoint pLeft = QPoint(100, 100);
+ QPoint pRight = QPoint(500, 100);
+ QPoint pLeftMiddle = QPoint(200, 100);
+ QPoint pRightMiddle = QPoint(350, 100);
+
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QVector<QQuickItem*> events;
+ EventItem *background = window->rootObject()->findChild<EventItem*>("background");
+ EventItem *left = window->rootObject()->findChild<EventItem*>("left");
+ EventItem *middle = window->rootObject()->findChild<EventItem*>("middle");
+ EventItem *right = window->rootObject()->findChild<EventItem*>("right");
+ QVERIFY(background);
+ QVERIFY(left);
+ QVERIFY(middle);
+ QVERIFY(right);
+ connect(background, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); });
+ connect(left, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); });
+ connect(middle, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); });
+ connect(right, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); });
+
+ QTest::touchEvent(window.data(), device).press(0, pLeft, window.data());
+ QQuickTouchUtils::flush(window.data());
+
+ // Touch on left, then background
+ QCOMPARE(events.size(), 2);
+ QCOMPARE(events.at(0), left);
+ QCOMPARE(events.at(1), background);
+ events.clear();
+
+ // New press events are deliverd first, the stationary point was not accepted, thus it doesn't get delivered
+ QTest::touchEvent(window.data(), device).stationary(0).press(1, pRightMiddle, window.data());
+ QQuickTouchUtils::flush(window.data());
+ QCOMPARE(events.size(), 3);
+ QCOMPARE(events.at(0), middle);
+ QCOMPARE(events.at(1), right);
+ QCOMPARE(events.at(2), background);
+ events.clear();
+
+ QTest::touchEvent(window.data(), device).release(0, pLeft, window.data()).release(1, pRightMiddle, window.data());
+ QQuickTouchUtils::flush(window.data());
+ QCOMPARE(events.size(), 0); // no accepted events
+
+ // Two presses, the first point should come first
+ QTest::touchEvent(window.data(), device).press(0, pLeft, window.data()).press(1, pRight, window.data());
+ QQuickTouchUtils::flush(window.data());
+ QCOMPARE(events.size(), 3);
+ QCOMPARE(events.at(0), left);
+ QCOMPARE(events.at(1), right);
+ QCOMPARE(events.at(2), background);
+ QTest::touchEvent(window.data(), device).release(0, pLeft, window.data()).release(1, pRight, window.data());
+ events.clear();
+
+ // Again, pressing right first
+ QTest::touchEvent(window.data(), device).press(0, pRight, window.data()).press(1, pLeft, window.data());
+ QQuickTouchUtils::flush(window.data());
+ QCOMPARE(events.size(), 3);
+ QCOMPARE(events.at(0), right);
+ QCOMPARE(events.at(1), left);
+ QCOMPARE(events.at(2), background);
+ QTest::touchEvent(window.data(), device).release(0, pRight, window.data()).release(1, pLeft, window.data());
+ events.clear();
+
+ // Two presses, both hitting the middle item on top, then branching left and right, then bottom
+ // Each target should be offered the events exactly once, middle first, left must come before right (id 0)
+ QTest::touchEvent(window.data(), device).press(0, pLeftMiddle, window.data()).press(1, pRightMiddle, window.data());
+ QCOMPARE(events.size(), 4);
+ QCOMPARE(events.at(0), middle);
+ QCOMPARE(events.at(1), left);
+ QCOMPARE(events.at(2), right);
+ QCOMPARE(events.at(3), background);
+ QTest::touchEvent(window.data(), device).release(0, pLeftMiddle, window.data()).release(1, pRightMiddle, window.data());
+ events.clear();
+
+ QTest::touchEvent(window.data(), device).press(0, pRightMiddle, window.data()).press(1, pLeftMiddle, window.data());
+ qDebug() << events;
+ QCOMPARE(events.size(), 4);
+ QCOMPARE(events.at(0), middle);
+ QCOMPARE(events.at(1), right);
+ QCOMPARE(events.at(2), left);
+ QCOMPARE(events.at(3), background);
+ QTest::touchEvent(window.data(), device).release(0, pRightMiddle, window.data()).release(1, pLeftMiddle, window.data());
+}
+
void tst_TouchMouse::hoverEnabled()
{
// QTouchDevice *device = new QTouchDevice;
// device->setType(QTouchDevice::TouchScreen);
// QWindowSystemInterface::registerTouchDevice(device);
+ // Ensure the cursor is away from the window
+ QCursor::setPos(0, 0);
+
QQuickView *window = createView();
window->setSource(testFileUrl("hoverMouseAreas.qml"));
+ window->setPosition(10, 10);
window->show();
window->requestActivate();
@@ -1272,8 +1377,8 @@ void tst_TouchMouse::hoverEnabled()
// ------------------------- Touch click on mouseArea1
QTest::touchEvent(window, device).press(0, p1, window);
- QVERIFY(enterSpy1.count() == 1);
- QVERIFY(enterSpy2.count() == 0);
+ QCOMPARE(enterSpy1.count(), 1);
+ QCOMPARE(enterSpy2.count(), 0);
QVERIFY(mouseArea1->pressed());
QVERIFY(mouseArea1->hovered());
QVERIFY(!mouseArea2->hovered());
@@ -1284,33 +1389,36 @@ void tst_TouchMouse::hoverEnabled()
QVERIFY(!mouseArea2->hovered());
// ------------------------- Touch click on mouseArea2
+ if (QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive) == 0)
+ QSKIP("hover can be momentarily inconsistent on X11, depending on timing of flushFrameSynchronousEvents with touch and mouse movements (QTBUG-55350)");
+
QTest::touchEvent(window, device).press(0, p2, window);
QVERIFY(mouseArea1->hovered());
QVERIFY(mouseArea2->hovered());
QVERIFY(mouseArea2->pressed());
- QVERIFY(enterSpy1.count() == 1);
- QVERIFY(enterSpy2.count() == 1);
+ QCOMPARE(enterSpy1.count(), 1);
+ QCOMPARE(enterSpy2.count(), 1);
QTest::touchEvent(window, device).release(0, p2, window);
QVERIFY(clickSpy2.count() == 1);
QVERIFY(mouseArea1->hovered());
QVERIFY(!mouseArea2->hovered());
- QVERIFY(exitSpy1.count() == 0);
- QVERIFY(exitSpy2.count() == 1);
+ QCOMPARE(exitSpy1.count(), 0);
+ QCOMPARE(exitSpy2.count(), 1);
// ------------------------- Another touch click on mouseArea1
QTest::touchEvent(window, device).press(0, p1, window);
- QVERIFY(enterSpy1.count() == 1);
- QVERIFY(enterSpy2.count() == 1);
+ QCOMPARE(enterSpy1.count(), 1);
+ QCOMPARE(enterSpy2.count(), 1);
QVERIFY(mouseArea1->pressed());
QVERIFY(mouseArea1->hovered());
QVERIFY(!mouseArea2->hovered());
QTest::touchEvent(window, device).release(0, p1, window);
- QVERIFY(clickSpy1.count() == 2);
+ QCOMPARE(clickSpy1.count(), 2);
QVERIFY(mouseArea1->hovered());
QVERIFY(!mouseArea1->pressed());
QVERIFY(!mouseArea2->hovered());
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index 09359060f6..5e8f762e23 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -34,6 +34,7 @@
#include <QtQuick/qquickitem.h>
#include "../../shared/util.h"
#include <QtGui/QWindow>
+#include <QtGui/QImage>
#include <QtCore/QDebug>
#include <QtQml/qqmlengine.h>
@@ -55,6 +56,8 @@ private slots:
void readback();
void renderingSignals();
void grabBeforeShow();
+ void reparentToNewWindow();
+ void nullEngine();
};
@@ -301,6 +304,39 @@ void tst_qquickwidget::grabBeforeShow()
QVERIFY(!widget.grab().isNull());
}
+void tst_qquickwidget::reparentToNewWindow()
+{
+ QWidget window1;
+ QWidget window2;
+
+ QQuickWidget *qqw = new QQuickWidget(&window1);
+ qqw->setSource(testFileUrl("rectangle.qml"));
+ window1.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window1, 5000));
+ window2.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window2, 5000));
+
+ QSignalSpy afterRenderingSpy(qqw->quickWindow(), &QQuickWindow::afterRendering);
+ qqw->setParent(&window2);
+ qqw->show();
+ QTRY_VERIFY(afterRenderingSpy.size() > 0);
+
+ QImage img = qqw->grabFramebuffer();
+ QCOMPARE(img.pixel(5, 5), qRgb(255, 0, 0));
+}
+
+void tst_qquickwidget::nullEngine()
+{
+ QQuickWidget widget;
+ // Default should have no errors, even with a null qml engine
+ QVERIFY(widget.errors().isEmpty());
+ QCOMPARE(widget.status(), QQuickWidget::Null);
+
+ // A QML engine should be created lazily.
+ QVERIFY(widget.rootContext());
+ QVERIFY(widget.engine());
+}
+
QTEST_MAIN(tst_qquickwidget)
#include "tst_qquickwidget.moc"
diff --git a/tests/auto/shared/util.cpp b/tests/auto/shared/util.cpp
index 55041eeb4d..96beb51612 100644
--- a/tests/auto/shared/util.cpp
+++ b/tests/auto/shared/util.cpp
@@ -101,11 +101,15 @@ Q_GLOBAL_STATIC(QMutex, qQmlTestMessageHandlerMutex)
QQmlTestMessageHandler *QQmlTestMessageHandler::m_instance = 0;
-void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &, const QString &message)
+void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message)
{
QMutexLocker locker(qQmlTestMessageHandlerMutex());
- if (QQmlTestMessageHandler::m_instance)
- QQmlTestMessageHandler::m_instance->m_messages.push_back(message);
+ if (QQmlTestMessageHandler::m_instance) {
+ if (QQmlTestMessageHandler::m_instance->m_includeCategories)
+ QQmlTestMessageHandler::m_instance->m_messages.push_back(QString("%1: %2").arg(context.category, message));
+ else
+ QQmlTestMessageHandler::m_instance->m_messages.push_back(message);
+ }
}
QQmlTestMessageHandler::QQmlTestMessageHandler()
@@ -114,6 +118,7 @@ QQmlTestMessageHandler::QQmlTestMessageHandler()
Q_ASSERT(!QQmlTestMessageHandler::m_instance);
QQmlTestMessageHandler::m_instance = this;
m_oldHandler = qInstallMessageHandler(messageHandler);
+ m_includeCategories = false;
}
QQmlTestMessageHandler::~QQmlTestMessageHandler()
diff --git a/tests/auto/shared/util.h b/tests/auto/shared/util.h
index 47a4aae231..33d7cbd1d0 100644
--- a/tests/auto/shared/util.h
+++ b/tests/auto/shared/util.h
@@ -87,12 +87,15 @@ public:
void clear() { m_messages.clear(); }
+ void setIncludeCategoriesEnabled(bool enabled) { m_includeCategories = enabled; }
+
private:
- static void messageHandler(QtMsgType, const QMessageLogContext &, const QString &message);
+ static void messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message);
static QQmlTestMessageHandler *m_instance;
QStringList m_messages;
QtMessageHandler m_oldHandler;
+ bool m_includeCategories;
};
#endif // QQMLTESTUTILS_H
diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro
index bd071ecf5c..5e6bc65815 100644
--- a/tests/benchmarks/benchmarks.pro
+++ b/tests/benchmarks/benchmarks.pro
@@ -1,5 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = qml script
-contains(QT_CONFIG, private_tests) {
- contains(QT_CONFIG, opengl(es1|es2)?):SUBDIRS += particles
+qtConfig(private_tests) {
+ qtConfig(opengl(es1|es2)?):SUBDIRS += particles
}
diff --git a/tests/benchmarks/particles/affectors/tst_affectors.cpp b/tests/benchmarks/particles/affectors/tst_affectors.cpp
index 475b8d28ec..99d175564b 100644
--- a/tests/benchmarks/particles/affectors/tst_affectors.cpp
+++ b/tests/benchmarks/particles/affectors/tst_affectors.cpp
@@ -86,7 +86,7 @@ void tst_affectors::test_basic()
int stillAlive = 0;
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 1000, 10));//Small simulation variance is permissible.
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
@@ -126,7 +126,7 @@ void tst_affectors::test_filtered()
int stillAlive = 0;
QVERIFY(extremelyFuzzyCompare(system->groupData[1]->size(), 1000, 10));//Small simulation variance is permissible.
- foreach (QQuickParticleData *d, system->groupData[1]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/benchmarks/particles/emission/tst_emission.cpp b/tests/benchmarks/particles/emission/tst_emission.cpp
index b107120a28..fe08305f68 100644
--- a/tests/benchmarks/particles/emission/tst_emission.cpp
+++ b/tests/benchmarks/particles/emission/tst_emission.cpp
@@ -79,7 +79,7 @@ void tst_emission::test_basic()
int stillAlive = 0;
QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 1000, 10));//Small simulation variance is permissible.
- foreach (QQuickParticleData *d, system->groupData[0]->data) {
+ for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/benchmarks/qml/animation/tst_animation.cpp b/tests/benchmarks/qml/animation/tst_animation.cpp
index 4f693f9fa8..59f5a57f5c 100644
--- a/tests/benchmarks/qml/animation/tst_animation.cpp
+++ b/tests/benchmarks/qml/animation/tst_animation.cpp
@@ -107,8 +107,8 @@ void tst_animation::animationelements_data()
{
QTest::addColumn<QString>("type");
- QSet<QString> types = QQmlMetaType::qmlTypeNames().toSet();
- foreach (const QString &type, types) {
+ const QSet<QString> types = QQmlMetaType::qmlTypeNames().toSet();
+ for (const QString &type : types) {
if (type.contains(QLatin1String("Animation")))
QTest::newRow(type.toLatin1()) << type;
}
diff --git a/tests/benchmarks/qml/creation/creation.pro b/tests/benchmarks/qml/creation/creation.pro
index bb4d2841fe..42faf729a0 100644
--- a/tests/benchmarks/qml/creation/creation.pro
+++ b/tests/benchmarks/qml/creation/creation.pro
@@ -1,7 +1,7 @@
CONFIG += benchmark
TEMPLATE = app
TARGET = tst_creation
-QT += core-private gui-private qml-private quick-private widgets testlib
+QT += core-private gui-private qml-private quick-private testlib
macx:CONFIG -= app_bundle
SOURCES += tst_creation.cpp
diff --git a/tests/benchmarks/qml/creation/tst_creation.cpp b/tests/benchmarks/qml/creation/tst_creation.cpp
index ca5802a8e7..a1c09db158 100644
--- a/tests/benchmarks/qml/creation/tst_creation.cpp
+++ b/tests/benchmarks/qml/creation/tst_creation.cpp
@@ -31,8 +31,6 @@
#include <QQmlComponent>
#include <private/qqmlmetatype_p.h>
#include <QDebug>
-#include <QGraphicsScene>
-#include <QGraphicsItem>
#include <QQuickItem>
#include <QQmlContext>
#include <private/qobject_p.h>
@@ -47,7 +45,6 @@ private slots:
void qobject_cpp();
void qobject_qml();
void qobject_qmltype();
- void qobject_alloc();
void qobject_10flat_qml();
void qobject_10flat_cpp();
@@ -62,9 +59,6 @@ private slots:
void itemtree_qml();
void itemtree_scene_cpp();
- void elements_data();
- void elements();
-
void itemtests_qml_data();
void itemtests_qml();
@@ -210,35 +204,6 @@ void tst_creation::qobject_qmltype()
}
}
-struct QObjectFakeData {
- char data[sizeof(QObjectPrivate)];
-};
-
-struct QObjectFake {
- QObjectFake();
- virtual ~QObjectFake();
-private:
- QObjectFakeData *d;
-};
-
-QObjectFake::QObjectFake()
-{
- d = new QObjectFakeData;
-}
-
-QObjectFake::~QObjectFake()
-{
- delete d;
-}
-
-void tst_creation::qobject_alloc()
-{
- QBENCHMARK {
- QObjectFake *obj = new QObjectFake;
- delete obj;
- }
-}
-
struct QQmlGraphics_Derived : public QObject
{
void setParent_noEvent(QObject *parent) {
@@ -333,28 +298,6 @@ void tst_creation::itemtree_scene_cpp()
delete root;
}
-void tst_creation::elements_data()
-{
- QTest::addColumn<QString>("type");
-
- QList<QString> types = QQmlMetaType::qmlTypeNames();
- foreach (QString type, types)
- QTest::newRow(type.toLatin1()) << type;
-}
-
-void tst_creation::elements()
-{
- QFETCH(QString, type);
- QQmlType *t = QQmlMetaType::qmlType(type, 2, 0);
- if (!t || !t->isCreatable())
- QSKIP("Non-creatable type");
-
- QBENCHMARK {
- QObject *obj = t->create();
- delete obj;
- }
-}
-
void tst_creation::itemtests_qml_data()
{
QTest::addColumn<QString>("filepath");
diff --git a/tests/benchmarks/qml/librarymetrics_performance/tst_librarymetrics_performance.cpp b/tests/benchmarks/qml/librarymetrics_performance/tst_librarymetrics_performance.cpp
index 5513dcb9a7..d7c54703ad 100644
--- a/tests/benchmarks/qml/librarymetrics_performance/tst_librarymetrics_performance.cpp
+++ b/tests/benchmarks/qml/librarymetrics_performance/tst_librarymetrics_performance.cpp
@@ -36,9 +36,6 @@
// for the standard set of elements, properties and expressions which
// are provided in the QtDeclarative library (QtQml and QtQuick).
-#define AVERAGE_OVER_N 10
-#define IGNORE_N_OUTLIERS 2
-
class ModuleApi : public QObject
{
Q_OBJECT
@@ -214,123 +211,37 @@ void tst_librarymetrics_performance::compilation()
}
}
- QList<qint64> nResults;
-
- // generate AVERAGE_OVER_N results
- for (int i = 0; i < AVERAGE_OVER_N; ++i) {
+ QBENCHMARK {
cleanState(&e);
- {
- QElapsedTimer et;
- et.start();
- QQmlComponent c(e, this);
- c.loadUrl(qmlfile); // just compile.
- qint64 etime = et.nsecsElapsed();
- nResults.append(etime);
- }
- }
-
- // sort the list
- qSort(nResults);
-
- // remove IGNORE_N_OUTLIERS*2 from ONLY the worst end (remove gc interference)
- for (int i = 0; i < IGNORE_N_OUTLIERS; ++i) {
- if (!nResults.isEmpty()) nResults.removeLast();
- if (!nResults.isEmpty()) nResults.removeLast();
+ QQmlComponent c(e, this);
+ c.loadUrl(qmlfile); // just compile.
}
-
- // now generate an average
- qint64 totaltime = 0;
- if (nResults.size() == 0) nResults.append(9999);
- for (int i = 0; i < nResults.size(); ++i)
- totaltime += nResults.at(i);
- double average = ((double)totaltime) / nResults.count();
-
- // and return it as the result
- QTest::setBenchmarkResult(average, QTest::WalltimeNanoseconds);
- QTest::setBenchmarkResult(average, QTest::WalltimeNanoseconds); // twice to workaround bug in QTestLib
}
void tst_librarymetrics_performance::instantiation_cached()
{
QFETCH(QUrl, qmlfile);
-
cleanState(&e);
- QList<qint64> nResults;
- // generate AVERAGE_OVER_N results
- for (int i = 0; i < AVERAGE_OVER_N; ++i) {
- QElapsedTimer et;
- et.start();
+ QBENCHMARK {
QQmlComponent c(e, this);
c.loadUrl(qmlfile); // just compile.
QObject *o = c.create();
- qint64 etime = et.nsecsElapsed();
- nResults.append(etime);
delete o;
}
-
- // sort the list
- qSort(nResults);
-
- // remove IGNORE_N_OUTLIERS*2 from ONLY the worst end (remove gc interference)
- for (int i = 0; i < IGNORE_N_OUTLIERS; ++i) {
- if (!nResults.isEmpty()) nResults.removeLast();
- if (!nResults.isEmpty()) nResults.removeLast();
- }
-
- // now generate an average
- qint64 totaltime = 0;
- if (nResults.size() == 0) nResults.append(9999);
- for (int i = 0; i < nResults.size(); ++i)
- totaltime += nResults.at(i);
- double average = ((double)totaltime) / nResults.count();
-
- // and return it as the result
- QTest::setBenchmarkResult(average, QTest::WalltimeNanoseconds);
- QTest::setBenchmarkResult(average, QTest::WalltimeNanoseconds); // twice to workaround bug in QTestLib
}
void tst_librarymetrics_performance::instantiation()
{
QFETCH(QUrl, qmlfile);
- cleanState(&e);
- QList<qint64> nResults;
-
- // generate AVERAGE_OVER_N results
- for (int i = 0; i < AVERAGE_OVER_N; ++i) {
+ QBENCHMARK {
cleanState(&e);
- {
- QElapsedTimer et;
- et.start();
- QQmlComponent c(e, this);
- c.loadUrl(qmlfile); // just compile.
- QObject *o = c.create();
- qint64 etime = et.nsecsElapsed();
- nResults.append(etime);
- delete o;
- }
- }
-
- // sort the list
- qSort(nResults);
-
- // remove IGNORE_N_OUTLIERS*2 from ONLY the worst end (remove gc interference)
- for (int i = 0; i < IGNORE_N_OUTLIERS; ++i) {
- if (!nResults.isEmpty()) nResults.removeLast();
- if (!nResults.isEmpty()) nResults.removeLast();
+ QQmlComponent c(e, this);
+ c.loadUrl(qmlfile); // just compile.
+ QObject *o = c.create();
+ delete o;
}
-
- // now generate an average
- qint64 totaltime = 0;
- if (nResults.size() == 0) nResults.append(9999);
- for (int i = 0; i < nResults.size(); ++i)
- totaltime += nResults.at(i);
- double average = ((double)totaltime) / nResults.count();
-
- // and return it as the result
- QTest::setBenchmarkResult(average, QTest::WalltimeNanoseconds);
- QTest::setBenchmarkResult(average, QTest::WalltimeNanoseconds); // twice to workaround bug in QTestLib
}
void tst_librarymetrics_performance::positioners_data()
@@ -351,43 +262,13 @@ void tst_librarymetrics_performance::positioners()
{
QFETCH(QUrl, qmlfile);
- cleanState(&e);
- QList<qint64> nResults;
-
- // generate AVERAGE_OVER_N results
- for (int i = 0; i < AVERAGE_OVER_N; ++i) {
+ QBENCHMARK {
cleanState(&e);
- {
- QElapsedTimer et;
- et.start();
- QQmlComponent c(e, this);
- c.loadUrl(qmlfile); // just compile.
- QObject *o = c.create();
- qint64 etime = et.nsecsElapsed();
- nResults.append(etime);
- delete o;
- }
- }
-
- // sort the list
- qSort(nResults);
-
- // remove IGNORE_N_OUTLIERS*2 from ONLY the worst end (remove gc interference)
- for (int i = 0; i < IGNORE_N_OUTLIERS; ++i) {
- if (!nResults.isEmpty()) nResults.removeLast();
- if (!nResults.isEmpty()) nResults.removeLast();
+ QQmlComponent c(e, this);
+ c.loadUrl(qmlfile); // just compile.
+ QObject *o = c.create();
+ delete o;
}
-
- // now generate an average
- qint64 totaltime = 0;
- if (nResults.size() == 0) nResults.append(9999);
- for (int i = 0; i < nResults.size(); ++i)
- totaltime += nResults.at(i);
- double average = ((double)totaltime) / nResults.count();
-
- // and return it as the result
- QTest::setBenchmarkResult(average, QTest::WalltimeNanoseconds);
- QTest::setBenchmarkResult(average, QTest::WalltimeNanoseconds); // twice to workaround bug in QTestLib
}
QTEST_MAIN(tst_librarymetrics_performance)
diff --git a/tests/benchmarks/qml/qml.pro b/tests/benchmarks/qml/qml.pro
index d3ce69c713..2cf2dff413 100644
--- a/tests/benchmarks/qml/qml.pro
+++ b/tests/benchmarks/qml/qml.pro
@@ -5,14 +5,14 @@ SUBDIRS += \
compilation \
javascript \
holistic \
+ qqmlchangeset \
qqmlcomponent \
- qqmlimage \
qqmlmetaproperty \
librarymetrics_performance \
# script \ ### FIXME: doesn't build
- js
+ js \
+ creation
qtHaveModule(opengl): SUBDIRS += painting qquickwindow
-qtHaveModule(widgets): SUBDIRS += creation
include(../trusted-benchmarks.pri)
diff --git a/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro b/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro
new file mode 100644
index 0000000000..fc0ccdf8ed
--- /dev/null
+++ b/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro
@@ -0,0 +1,10 @@
+CONFIG += benchmark
+TEMPLATE = app
+TARGET = tst_qqmlchangeset
+QT += qml quick-private testlib
+osx:CONFIG -= app_bundle
+
+SOURCES += tst_qqmlchangeset.cpp
+
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
diff --git a/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp b/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp
new file mode 100644
index 0000000000..bbfb52343c
--- /dev/null
+++ b/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+
+#include <QDebug>
+
+#include <private/qqmlchangeset_p.h>
+
+class tst_qqmlchangeset : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void move();
+};
+
+void tst_qqmlchangeset::move()
+{
+ QBENCHMARK {
+ QQmlChangeSet set;
+ const int MAX_ROWS = 30000;
+ for (int i = 0; i < MAX_ROWS; ++i) {
+ set.move(i, MAX_ROWS - 1 - i, 1, i);
+ }
+ }
+}
+
+QTEST_MAIN(tst_qqmlchangeset)
+#include "tst_qqmlchangeset.moc"
diff --git a/tests/benchmarks/qml/qqmlimage/image.png b/tests/benchmarks/qml/qqmlimage/image.png
deleted file mode 100644
index 623d36233d..0000000000
--- a/tests/benchmarks/qml/qqmlimage/image.png
+++ /dev/null
Binary files differ
diff --git a/tests/benchmarks/qml/qqmlimage/qqmlimage.pro b/tests/benchmarks/qml/qqmlimage/qqmlimage.pro
deleted file mode 100644
index 421f232a4f..0000000000
--- a/tests/benchmarks/qml/qqmlimage/qqmlimage.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-CONFIG += benchmark
-TEMPLATE = app
-TARGET = tst_qqmlimage
-QT += qml quick-private testlib
-macx:CONFIG -= app_bundle
-CONFIG += release
-
-SOURCES += tst_qqmlimage.cpp
-
-DEFINES += SRCDIR=\\\"$$PWD\\\"
-
diff --git a/tests/benchmarks/qml/qqmlimage/tst_qqmlimage.cpp b/tests/benchmarks/qml/qqmlimage/tst_qqmlimage.cpp
deleted file mode 100644
index 38fca802c5..0000000000
--- a/tests/benchmarks/qml/qqmlimage/tst_qqmlimage.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <qtest.h>
-#include <QQmlEngine>
-#include <QQmlComponent>
-#include <private/qquickimage_p.h>
-
-class tst_qmlgraphicsimage : public QObject
-{
- Q_OBJECT
-public:
- tst_qmlgraphicsimage() {}
-
-private slots:
- void qmlgraphicsimage();
- void qmlgraphicsimage_file();
- void qmlgraphicsimage_url();
-
-private:
- QQmlEngine engine;
-};
-
-void tst_qmlgraphicsimage::qmlgraphicsimage()
-{
- int x = 0;
- QUrl url(SRCDIR "/image.png");
- QBENCHMARK {
- QUrl url2("http://localhost/image" + QString::number(x++) + ".png");
- QQuickImage *image = new QQuickImage;
- QQmlEngine::setContextForObject(image, engine.rootContext());
- delete image;
- }
-}
-
-void tst_qmlgraphicsimage::qmlgraphicsimage_file()
-{
- int x = 0;
- QUrl url(SRCDIR "/image.png");
- //get rid of initialization effects
- {
- QQuickImage *image = new QQuickImage;
- QQmlEngine::setContextForObject(image, engine.rootContext());
- image->setSource(url);
- }
- QBENCHMARK {
- QUrl url2("http://localhost/image" + QString::number(x++) + ".png");
- QQuickImage *image = new QQuickImage;
- QQmlEngine::setContextForObject(image, engine.rootContext());
- image->setSource(url);
- delete image;
- }
-}
-
-void tst_qmlgraphicsimage::qmlgraphicsimage_url()
-{
- int x = 0;
- QUrl url(SRCDIR "/image.png");
- QBENCHMARK {
- QUrl url2("http://localhost/image" + QString::number(x++) + ".png");
- QQuickImage *image = new QQuickImage;
- QQmlEngine::setContextForObject(image, engine.rootContext());
- image->setSource(url2);
- delete image;
- }
-}
-
-QTEST_MAIN(tst_qmlgraphicsimage)
-
-#include "tst_qqmlimage.moc"
diff --git a/tests/manual/highdpi/imageprovider.cpp b/tests/manual/highdpi/imageprovider.cpp
index 33a69cb87e..069fa5998f 100644
--- a/tests/manual/highdpi/imageprovider.cpp
+++ b/tests/manual/highdpi/imageprovider.cpp
@@ -45,7 +45,7 @@
#include <qquickimageprovider.h>
#include <QImage>
#include <QPainter>
-#include <qDebug.h>
+#include <QDebug>
class ColorImageProvider : public QQuickImageProvider
{
diff --git a/tests/manual/nodetypes/Effects.qml b/tests/manual/nodetypes/Effects.qml
index 0d16cd1c84..85e7ab7a15 100644
--- a/tests/manual/nodetypes/Effects.qml
+++ b/tests/manual/nodetypes/Effects.qml
@@ -69,6 +69,7 @@ Item {
NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 600 }
property bool customVertexShader: false // the effect is fine with the default vs, but toggle this to test
+ property bool useHLSLSourceString: false // toggle to provide HLSL shaders as strings instead of bytecode in files
property string glslVertexShader:
"uniform highp mat4 qt_Matrix;" +
@@ -92,12 +93,43 @@ Item {
" gl_FragColor = texture2D(source, qt_TexCoord0 + amplitude * vec2(p.y, -p.x)) * qt_Opacity;" +
"}"
+ property string hlslVertexShader: "cbuffer ConstantBuffer : register(b0) {" +
+ " float4x4 qt_Matrix;" +
+ " float qt_Opacity; }" +
+ "struct PSInput {" +
+ " float4 position : SV_POSITION;" +
+ " float2 coord : TEXCOORD0; };" +
+ "PSInput main(float4 position : POSITION, float2 coord : TEXCOORD0) {" +
+ " PSInput result;" +
+ " result.position = mul(qt_Matrix, position);" +
+ " result.coord = coord;" +
+ " return result;" +
+ "}";
+
+ property string hlslPixelShader:"cbuffer ConstantBuffer : register(b0) {" +
+ " float4x4 qt_Matrix;" +
+ " float qt_Opacity;" +
+ " float amplitude;" +
+ " float frequency;" +
+ " float time; }" +
+ "Texture2D source : register(t0);" +
+ "SamplerState sourceSampler : register(s0);" +
+ "float4 main(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET" +
+ "{" +
+ " float2 p = sin(time + frequency * coord);" +
+ " return source.Sample(sourceSampler, coord + amplitude * float2(p.y, -p.x)) * qt_Opacity;" +
+ "}";
+
property string hlslVertexShaderByteCode: "qrc:/vs_wobble.cso"
property string hlslPixelShaderByteCode: "qrc:/ps_wobble.cso"
- vertexShader: customVertexShader ? (GraphicsInfo.shaderType === GraphicsInfo.HLSL ? hlslVertexShaderByteCode : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? glslVertexShader : "")) : ""
+ vertexShader: customVertexShader ? (GraphicsInfo.shaderType === GraphicsInfo.HLSL
+ ? (useHLSLSourceString ? hlslVertexShader : hlslVertexShaderByteCode)
+ : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? glslVertexShader : "")) : ""
- fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.HLSL ? hlslPixelShaderByteCode : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? glslFragmentShader : "")
+ fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.HLSL
+ ? (useHLSLSourceString ? hlslPixelShader : hlslPixelShaderByteCode)
+ : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? glslFragmentShader : "")
}
Image {
@@ -181,6 +213,9 @@ Item {
Text {
text: GraphicsInfo.shaderType + " " + GraphicsInfo.shaderCompilationType + " " + GraphicsInfo.shaderSourceType
}
+ Text {
+ text: eff.status + " " + eff.log
+ }
}
}
}
diff --git a/tests/manual/qmlplugindump/tst_qmlplugindump.cpp b/tests/manual/qmlplugindump/tst_qmlplugindump.cpp
index ed00682a83..1bedd4427b 100644
--- a/tests/manual/qmlplugindump/tst_qmlplugindump.cpp
+++ b/tests/manual/qmlplugindump/tst_qmlplugindump.cpp
@@ -92,7 +92,7 @@ public:
{
QRegularExpression re;
QRegularExpressionMatch m;
- Q_FOREACH (const QString &e, m_expected) {
+ for (const QString &e : m_expected) {
re.setPattern(e);
m = re.match(QString::fromLatin1(buffer));
if (!m.hasMatch()) {
@@ -187,7 +187,8 @@ Test createTest(const QString &id, const QJsonObject &def)
return Test(id);
}
QStringList patterns;
- Q_FOREACH (const QJsonValue &x, expected.toArray()) {
+ const auto expectedArray = expected.toArray();
+ for (const QJsonValue &x : expectedArray) {
if (!x.isString()) {
qWarning() << "Wrong definition for test: " << id << ".";
return Test(id);
@@ -331,7 +332,7 @@ void tst_qmlplugindump::plugin_data()
QTest::addColumn<QString>("version");
QTest::addColumn<QStringList>("expected");
- Q_FOREACH (const Test &t, tests) {
+ for (const Test &t : qAsConst(tests)) {
if (t.isNull())
QSKIP("Errors in test definition.");
QTest::newRow(t.id.toLatin1().data()) << t.project << t.version << t.expected;
@@ -357,9 +358,9 @@ void tst_qmlplugindump::plugin()
void tst_qmlplugindump::cleanupTestCase()
{
QSet<const QString> projects;
- Q_FOREACH (const Test &t, tests)
+ for (const Test &t : qAsConst(tests))
projects.insert(t.project);
- Q_FOREACH (const QString &p, projects) {
+ for (const QString &p : qAsConst(projects)) {
if (!cleanUpSample(p))
qWarning() << "Error in cleaning up project" << p << ".";
}
diff --git a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp
index a4b1a1be70..886cfc6599 100644
--- a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp
+++ b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp
@@ -134,7 +134,7 @@ private:
};
-extern uint qt_qhash_seed;
+Q_CORE_EXPORT extern QBasicAtomicInt qt_qhash_seed;
int main(int argc, char *argv[])
{
@@ -183,8 +183,8 @@ int main(int argc, char *argv[])
v.setSource(QUrl::fromLocalFile(ifile));
if (noText) {
- QList<QQuickItem*> items = v.rootObject()->findChildren<QQuickItem*>();
- foreach (QQuickItem *item, items) {
+ const QList<QQuickItem*> items = v.rootObject()->findChildren<QQuickItem*>();
+ for (QQuickItem *item : items) {
if (QByteArray(item->metaObject()->className()).contains("Text"))
item->setVisible(false);
}
diff --git a/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp b/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp
index 426e06ccc2..3f28d90e7b 100644
--- a/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp
+++ b/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp
@@ -156,7 +156,7 @@ void tst_Scenegraph::setupTestSuite(const QByteArray& filter)
}
std::sort(itemFiles.begin(), itemFiles.end());
- foreach (const QString &filePath, itemFiles) {
+ for (const QString &filePath : qAsConst(itemFiles)) {
QByteArray itemName = filePath.mid(testSuitePath.length() + 1).toLatin1();
QBaselineTest::newRow(itemName, checksumFileOrDir(filePath)) << filePath;
numItems++;
@@ -238,7 +238,9 @@ quint16 tst_Scenegraph::checksumFileOrDir(const QString &path)
if (fi.isDir()) {
static const QStringList nameFilters = QStringList() << "*.qml" << "*.cpp" << "*.png" << "*.jpg";
quint16 cs = 0;
- foreach (QString item, QDir(fi.filePath()).entryList(nameFilters, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot))
+ const auto entryList = QDir(fi.filePath()).entryList(nameFilters,
+ QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
+ for (const QString &item : entryList)
cs ^= checksumFileOrDir(path + QLatin1Char('/') + item);
return cs;
}
diff --git a/tests/manual/v4/test262 b/tests/manual/v4/test262
-Subproject 0b5af3dcec772bb06b4d685a20b2859cda59d18
+Subproject 9741ac4655808ac46c127e3d1d8ba3d27ada618
diff --git a/tools/fdegen/fdegen.pro b/tools/fdegen/fdegen.pro
deleted file mode 100644
index a52533280e..0000000000
--- a/tools/fdegen/fdegen.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-TEMPLATE = app
-TARGET = fdegen
-INCLUDEPATH += .
-
-# Input
-SOURCES += main.cpp
-
-LIBS += -ldwarf -lelf
diff --git a/tools/fdegen/main.cpp b/tools/fdegen/main.cpp
deleted file mode 100644
index 53ee9dec2a..0000000000
--- a/tools/fdegen/main.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the V4VM module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <libdwarf.h>
-#include <dwarf.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#define DEBUG
-
-#ifdef DEBUG
-#include <libelf.h>
-#endif
-
-#include <qglobal.h>
-
-enum DwarfRegs {
-#if defined(Q_PROCESSOR_X86_64)
- // X86-64
- RAX = 0,
- RDX = 1,
- RCX = 2,
- RBX = 3,
- RSI = 4,
- RDI = 5,
- RBP = 6,
- RSP = 7,
- R8 = 8,
- R9 = 9,
- R10 = 10,
- R11 = 11,
- R12 = 12,
- R13 = 13,
- R14 = 14,
- R15 = 15,
- RIP = 16,
-
- InstructionPointerRegister = RIP,
- StackPointerRegister = RSP,
- StackFrameRegister = RBP
-#elif defined(Q_PROCESSOR_X86)
- // x86
- EAX = 0,
- EDX = 1,
- ECX = 2,
- EBX = 3,
- ESP = 4,
- EBP = 5,
- ESI = 6,
- EDI = 7,
- EIP = 8,
-
- InstructionPointerRegister = EIP,
- StackPointerRegister = ESP,
- StackFrameRegister = EBP
-#else
-#error Not ported yet
-#endif
-};
-
-static const DwarfRegs calleeSavedRegisters[] = {
-#if defined(Q_PROCESSOR_X86_64)
- R12,
- R14
-#elif defined(Q_PROCESSOR_X86)
- ESI,
- EDI
-#endif
-};
-static const int calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / sizeof(calleeSavedRegisters[0]);
-
-#if QT_POINTER_SIZE == 8
-#define Elf_Ehdr Elf64_Ehdr
-#define elf_newehdr elf64_newehdr
-#define Elf_Shdr Elf64_Shdr
-#define elf_getshdr elf64_getshdr
-#else
-#define Elf_Ehdr Elf32_Ehdr
-#define elf_newehdr elf32_newehdr
-#define Elf_Shdr Elf32_Shdr
-#define elf_getshdr elf32_getshdr
-#endif
-
-static void die(const char *msg)
-{
- fprintf(stderr, "error: %s\n", msg);
- exit(1);
-}
-
-static int createSectionCallback(
- char *name,
- int size,
- Dwarf_Unsigned /*type*/,
- Dwarf_Unsigned /*flags*/,
- Dwarf_Unsigned /*link*/,
- Dwarf_Unsigned /*info*/,
- Dwarf_Unsigned* /*sect_name_index*/,
- void * /*user_data*/,
- int* /*error*/)
-{
- if (strcmp(name, ".debug_frame"))
- return 0;
- fprintf(stderr, "createsection called with %s and size %d\n", name, size);
- return 1;
-}
-
-static unsigned char cie_init_instructions[] = {
- DW_CFA_def_cfa, StackPointerRegister, /*offset in bytes */sizeof(void*),
- DW_CFA_offset | InstructionPointerRegister, 1,
-};
-
-int main()
-{
- Dwarf_Error error = 0;
- Dwarf_P_Debug dw = dwarf_producer_init_c(DW_DLC_WRITE | DW_DLC_SIZE_64,
- createSectionCallback,
- /* error handler */0,
- /* error arg */0,
- /* user data */0,
- &error);
- if (error != 0)
- die("dwarf_producer_init_c failed");
-
- Dwarf_Unsigned cie = dwarf_add_frame_cie(dw,
- "",
- /* code alignment factor */sizeof(void*),
- /* data alignment factor */-sizeof(void*),
- /* return address reg*/InstructionPointerRegister,
- cie_init_instructions,
- sizeof(cie_init_instructions),
- &error);
- if (error != 0)
- die("dwarf_add_frame_cie failed");
-
- Dwarf_P_Fde fde = dwarf_new_fde(dw, &error);
- if (error != 0)
- die("dwarf_new_fde failed");
-
- /* New entry in state machine for code offset 1 after push rbp instruction */
- dwarf_add_fde_inst(fde,
- DW_CFA_advance_loc,
- /*offset in code alignment units*/ 1,
- /* unused*/ 0,
- &error);
-
- /* After "push rbp" the offset to the CFA is now 2 instead of 1 */
- dwarf_add_fde_inst(fde,
- DW_CFA_def_cfa_offset_sf,
- /*offset in code alignment units*/ -2,
- /* unused*/ 0,
- &error);
-
- /* After "push rbp" the value of rbp is now stored at offset 1 from CFA */
- dwarf_add_fde_inst(fde,
- DW_CFA_offset,
- StackFrameRegister,
- 2,
- &error);
-
- /* New entry in state machine for code offset 3 for mov rbp, rsp instruction */
- dwarf_add_fde_inst(fde,
- DW_CFA_advance_loc,
- /*offset in code alignment units*/ 3,
- /* unused */ 0,
- &error);
-
- /* After "mov rbp, rsp" the cfa is reachable via rbp */
- dwarf_add_fde_inst(fde,
- DW_CFA_def_cfa_register,
- StackFrameRegister,
- /* unused */0,
- &error);
-
- /* Callee saved registers */
- for (int i = 0; i < calleeSavedRegisterCount; ++i) {
- dwarf_add_fde_inst(fde,
- DW_CFA_offset,
- calleeSavedRegisters[i],
- i + 3,
- &error);
- }
-
- dwarf_add_frame_fde(dw, fde,
- /* die */0,
- cie,
- /*virt addr */0,
- /* length of code */0,
- /* symbol index */0,
- &error);
- if (error != 0)
- die("dwarf_add_frame_fde failed");
-
- dwarf_transform_to_disk_form(dw, &error);
- if (error != 0)
- die("dwarf_transform_to_disk_form failed");
-
- Dwarf_Unsigned len = 0;
- Dwarf_Signed elfIdx = 0;
- unsigned char *bytes = (unsigned char *)dwarf_get_section_bytes(dw, /* section */1,
- &elfIdx, &len, &error);
- if (error != 0)
- die("dwarf_get_section_bytes failed");
-
- // libdwarf doesn't add a terminating FDE with zero length, so let's add one
- // ourselves.
- unsigned char *newBytes = (unsigned char *)alloca(len + 4);
- memcpy(newBytes, bytes, len);
- newBytes[len] = 0;
- newBytes[len + 1] = 0;
- newBytes[len + 2] = 0;
- newBytes[len + 3] = 0;
- newBytes[len + 4] = 0;
- bytes = newBytes;
- len += 4;
-
- // Reset CIE-ID back to 0 as expected for .eh_frames
- bytes[4] = 0;
- bytes[5] = 0;
- bytes[6] = 0;
- bytes[7] = 0;
-
- unsigned fde_offset = bytes[0] + 4;
-
- bytes[fde_offset + 4] = fde_offset + 4;
-
- printf("static const unsigned char cie_fde_data[] = {\n");
- int i = 0;
- while (i < len) {
- printf(" ");
- for (int j = 0; i < len && j < 8; ++j, ++i)
- printf("0x%x, ", bytes[i]);
- printf("\n");
- }
- printf("};\n");
-
- printf("static const int fde_offset = %d;\n", fde_offset);
- printf("static const int initial_location_offset = %d;\n", fde_offset + 8);
- printf("static const int address_range_offset = %d;\n", fde_offset + 8 + sizeof(void*));
-
-#ifdef DEBUG
- {
- if (elf_version(EV_CURRENT) == EV_NONE)
- die("wrong elf version");
- int fd = open("debug.o", O_WRONLY | O_CREAT, 0777);
- if (fd < 0)
- die("cannot create debug.o");
-
- Elf *e = elf_begin(fd, ELF_C_WRITE, 0);
- if (!e)
- die("elf_begin failed");
-
- Elf_Ehdr *ehdr = elf_newehdr(e);
- if (!ehdr)
- die(elf_errmsg(-1));
-
- ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
-#if defined(Q_PROCESSOR_X86_64)
- ehdr->e_machine = EM_X86_64;
-#elif defined(Q_PROCESSOR_X86)
- ehdr->e_machine = EM_386;
-#else
-#error port me :)
-#endif
- ehdr->e_type = ET_EXEC;
- ehdr->e_version = EV_CURRENT;
-
- Elf_Scn *section = elf_newscn(e);
- if (!section)
- die("elf_newscn failed");
-
- Elf_Data *data = elf_newdata(section);
- if (!data)
- die(elf_errmsg(-1));
- data->d_align = 4;
- data->d_off = 0;
- data->d_buf = bytes;
- data->d_size = len;
- data->d_type = ELF_T_BYTE;
- data->d_version = EV_CURRENT;
-
- Elf_Shdr *shdr = elf_getshdr(section);
- if (!shdr)
- die(elf_errmsg(-1));
-
- shdr->sh_name = 1;
- shdr->sh_type = SHT_PROGBITS;
- shdr->sh_entsize = 0;
-
- char stringTable[] = {
- 0,
- '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0,
- '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0
- };
-
- section = elf_newscn(e);
- if (!section)
- die("elf_newscn failed");
-
- data = elf_newdata(section);
- if (!data)
- die(elf_errmsg(-1));
- data->d_align = 1;
- data->d_off = 0;
- data->d_buf = stringTable;
- data->d_size = sizeof(stringTable);
- data->d_type = ELF_T_BYTE;
- data->d_version = EV_CURRENT;
-
- shdr = elf_getshdr(section);
- if (!shdr)
- die(elf_errmsg(-1));
-
- shdr->sh_name = 11;
- shdr->sh_type = SHT_STRTAB;
- shdr->sh_flags = SHF_STRINGS | SHF_ALLOC;
- shdr->sh_entsize = 0;
-
- ehdr->e_shstrndx = elf_ndxscn(section);
-
- if (elf_update(e, ELF_C_WRITE) < 0)
- die(elf_errmsg(-1));
-
- elf_end(e);
- close(fd);
- }
-#endif
-
- dwarf_producer_finish(dw, &error);
- if (error != 0)
- die("dwarf_producer_finish failed");
- return 0;
-}
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index a795144984..fdfc66f3a6 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -160,18 +160,23 @@ public:
LoadWatcher(QQmlApplicationEngine *e, int expected)
: QObject(e)
, earlyExit(false)
+ , returnCode(0)
, expect(expected)
, haveOne(false)
{
connect(e, SIGNAL(objectCreated(QObject*,QUrl)),
this, SLOT(checkFinished(QObject*)));
// QQmlApplicationEngine also connects quit() to QCoreApplication::quit
- // but if called before exec() then QCoreApplication::quit does nothing
+ // and exit() to QCoreApplication::exit but if called before exec()
+ // then QCoreApplication::quit or QCoreApplication::exit does nothing
connect(e, SIGNAL(quit()),
this, SLOT(quit()));
+ connect(e, &QQmlEngine::exit,
+ this, &LoadWatcher::exit);
}
bool earlyExit;
+ int returnCode;
private:
void contain(QObject *o, const QUrl &containPath);
@@ -187,7 +192,7 @@ public Q_SLOTS:
checkForWindow(o);
haveOne = true;
if (conf && qae)
- foreach (PartialScene *ps, conf->completers)
+ for (PartialScene *ps : qAsConst(conf->completers))
if (o->inherits(ps->itemType().toUtf8().constData()))
contain(o, ps->container());
}
@@ -196,14 +201,20 @@ public Q_SLOTS:
if (! --expect) {
printf("qml: Did not load any objects, exiting.\n");
- exit(2);//Different return code from qFatal
+ std::exit(2);//Different return code from qFatal
}
}
void quit() {
//Will be checked before calling exec()
earlyExit = true;
+ returnCode = 0;
}
+ void exit(int retCode) {
+ earlyExit = true;
+ returnCode = retCode;
+ }
+
#if defined(QT_GUI_LIB) && !defined(QT_NO_OPENGL)
void onOpenGlContextCreated(QOpenGLContext *context);
#endif
@@ -402,8 +413,8 @@ static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
QObject *dummyData = comp.create();
if (comp.isError()) {
- QList<QQmlError> errors = comp.errors();
- foreach (const QQmlError &error, errors)
+ const QList<QQmlError> errors = comp.errors();
+ for (const QQmlError &error : errors)
qWarning() << error;
}
@@ -452,7 +463,7 @@ int main(int argc, char *argv[])
QString dummyDir;
//Handle main arguments
- QStringList argList = app->arguments();
+ const QStringList argList = app->arguments();
for (int i = 1; i < argList.count(); i++) {
const QString &arg = argList[i];
if (arg == QLatin1String("-quiet"))
@@ -555,7 +566,7 @@ int main(int argc, char *argv[])
if (!dummyDir.isEmpty() && QFileInfo (dummyDir).isDir())
loadDummyDataFiles(e, dummyDir);
- foreach (const QString &path, files) {
+ for (const QString &path : qAsConst(files)) {
//QUrl::fromUserInput doesn't treat no scheme as relative file paths
#ifndef QT_NO_REGULAREXPRESSION
QRegularExpression urlRe("[[:word:]]+://.*");
@@ -582,7 +593,7 @@ int main(int argc, char *argv[])
}
if (lw->earlyExit)
- return 0;
+ return lw->returnCode;
return app->exec();
}
diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro
index fe90916980..5f05054d04 100644
--- a/tools/qml/qml.pro
+++ b/tools/qml/qml.pro
@@ -12,6 +12,6 @@ mac {
ICON = qml.icns
}
-DEFINES += QT_QML_DEBUG_NO_WARNING
+!contains(QT_CONFIG, no-qml-debug): DEFINES += QT_QML_DEBUG_NO_WARNING
load(qt_tool)
diff --git a/tools/qmleasing/mainwindow.cpp b/tools/qmleasing/mainwindow.cpp
index 5a5f651396..d36ab5fd75 100644
--- a/tools/qmleasing/mainwindow.cpp
+++ b/tools/qmleasing/mainwindow.cpp
@@ -73,7 +73,8 @@ MainWindow::MainWindow(QWidget *parent) :
quickView.rootContext()->setContextProperty(QLatin1String("spinBox"), ui_properties.spinBox);
- foreach (const QString &name, splineEditor->presetNames())
+ const auto presetNames = splineEditor->presetNames();
+ for (const QString &name : presetNames)
ui_properties.comboBox->addItem(name);
connect(ui_properties.comboBox, SIGNAL(currentIndexChanged(QString)), splineEditor, SLOT(setPreset(QString)));
diff --git a/tools/qmleasing/splineeditor.cpp b/tools/qmleasing/splineeditor.cpp
index 78ed9606db..d54a101b69 100644
--- a/tools/qmleasing/splineeditor.cpp
+++ b/tools/qmleasing/splineeditor.cpp
@@ -34,6 +34,7 @@
#include <QContextMenuEvent>
#include <QDebug>
#include <QApplication>
+#include <QVector>
const int canvasWidth = 640;
const int canvasHeight = 320;
@@ -287,7 +288,7 @@ QHash<QString, QEasingCurve> SplineEditor::presets() const
QString SplineEditor::generateCode()
{
QString s = QLatin1String("[");
- foreach (const QPointF &point, m_controlPoints) {
+ for (const QPointF &point : qAsConst(m_controlPoints)) {
s += QString::number(point.x(), 'g', 2) + QLatin1Char(',')
+ QString::number(point.y(), 'g', 3) + QLatin1Char(',');
}
@@ -619,7 +620,7 @@ void SplineEditor::mouseMoveEvent(QMouseEvent *e)
if (indexIsRealPoint(m_activeControlPoint)) {
//move also the tangents
QPointF targetPoint = p;
- QPointF distance = targetPoint - m_controlPoints[m_activeControlPoint];
+ QPointF distance = targetPoint - m_controlPoints.at(m_activeControlPoint);
m_controlPoints[m_activeControlPoint] = targetPoint;
m_controlPoints[m_activeControlPoint - 1] += distance;
m_controlPoints[m_activeControlPoint + 1] += distance;
@@ -628,7 +629,7 @@ void SplineEditor::mouseMoveEvent(QMouseEvent *e)
m_controlPoints[m_activeControlPoint] = p;
} else {
QPointF targetPoint = p;
- QPointF distance = targetPoint - m_controlPoints[m_activeControlPoint];
+ QPointF distance = targetPoint - m_controlPoints.at(m_activeControlPoint);
m_controlPoints[m_activeControlPoint] = p;
if ((m_activeControlPoint > 1) && (m_activeControlPoint % 3) == 0) { //right control point
@@ -672,25 +673,23 @@ void SplineEditor::setEasingCurve(const QString &code)
if (m_block)
return;
if (code.startsWith(QLatin1Char('[')) && code.endsWith(QLatin1Char(']'))) {
- QString cleanCode = code;
- cleanCode.remove(0, 1);
- cleanCode.chop(1);
- const QStringList stringList = cleanCode.split(QLatin1Char(','), QString::SkipEmptyParts);
+ const QStringRef cleanCode(&code, 1, code.size() - 2);
+ const auto stringList = cleanCode.split(QLatin1Char(','), QString::SkipEmptyParts);
if (stringList.count() >= 6 && (stringList.count() % 6 == 0)) {
- QList<qreal> realList;
+ QVector<qreal> realList;
realList.reserve(stringList.count());
- foreach (const QString &string, stringList) {
+ for (const QStringRef &string : stringList) {
bool ok;
realList.append(string.toDouble(&ok));
if (!ok)
return;
}
- QList<QPointF> points;
+ QVector<QPointF> points;
const int count = realList.count() / 2;
points.reserve(count);
for (int i = 0; i < count; ++i)
points.append(QPointF(realList.at(i * 2), realList.at(i * 2 + 1)));
- if (points.last() == QPointF(1.0, 1.0)) {
+ if (points.constLast() == QPointF(1.0, 1.0)) {
QEasingCurve easingCurve(QEasingCurve::BezierSpline);
for (int i = 0; i < points.count() / 3; ++i) {
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 2569d78c63..8f476649e9 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -55,6 +55,14 @@ QT_USE_NAMESPACE
QStringList g_qmlImportPaths;
+static inline QString typeLiteral() { return QStringLiteral("type"); }
+static inline QString versionLiteral() { return QStringLiteral("version"); }
+static inline QString nameLiteral() { return QStringLiteral("name"); }
+static inline QString pluginsLiteral() { return QStringLiteral("plugins"); }
+static inline QString pathLiteral() { return QStringLiteral("path"); }
+static inline QString classnamesLiteral() { return QStringLiteral("classnames"); }
+static inline QString dependenciesLiteral() { return QStringLiteral("dependencies"); }
+
static void printUsage(const QString &appNameIn)
{
const std::wstring appName = appNameIn.toStdWString();
@@ -84,14 +92,14 @@ QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, con
// handle directory imports
if (!importNode->fileName.isEmpty()) {
QString name = importNode->fileName.toString();
- import[QStringLiteral("name")] = name;
+ import[nameLiteral()] = name;
if (name.endsWith(QLatin1String(".js"))) {
- import[QStringLiteral("type")] = QStringLiteral("javascript");
+ import[typeLiteral()] = QStringLiteral("javascript");
} else {
- import[QStringLiteral("type")] = QStringLiteral("directory");
+ import[typeLiteral()] = QStringLiteral("directory");
}
- import[QStringLiteral("path")] = QDir::cleanPath(path + QLatin1Char('/') + name);
+ import[pathLiteral()] = QDir::cleanPath(path + QLatin1Char('/') + name);
} else {
// Walk the id chain ("Foo" -> "Bar" -> etc)
QString name;
@@ -103,9 +111,9 @@ QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, con
}
name.chop(1); // remove trailing "."
if (!name.isEmpty())
- import[QStringLiteral("name")] = name;
- import[QStringLiteral("type")] = QStringLiteral("module");
- import[QStringLiteral("version")] = code.mid(importNode->versionToken.offset, importNode->versionToken.length);
+ import[nameLiteral()] = name;
+ import[typeLiteral()] = QStringLiteral("module");
+ import[versionLiteral()] = code.mid(importNode->versionToken.offset, importNode->versionToken.length);
}
imports.append(import);
@@ -117,7 +125,7 @@ QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, con
// Read the qmldir file, extract a list of plugins by
// parsing the "plugin" and "classname" lines.
QVariantMap pluginsForModulePath(const QString &modulePath) {
- QFile qmldirFile(modulePath + QStringLiteral("/qmldir"));
+ QFile qmldirFile(modulePath + QLatin1String("/qmldir"));
if (!qmldirFile.exists())
return QVariantMap();
@@ -137,20 +145,20 @@ QVariantMap pluginsForModulePath(const QString &modulePath) {
classnames += QString::fromUtf8(line.split(' ').at(1));
classnames += QLatin1Char(' ');
} else if (line.startsWith("depends")) {
- QList<QByteArray> dep = line.split(' ');
+ const QList<QByteArray> dep = line.split(' ');
if (dep.length() != 3)
std::cerr << "depends: expected 2 arguments: module identifier and version" << std::endl;
else
- dependencies << QString::fromUtf8(dep[1]) + QStringLiteral(" ") + QString::fromUtf8(dep[2]).simplified();
+ dependencies << QString::fromUtf8(dep[1]) + QLatin1Char(' ') + QString::fromUtf8(dep[2]).simplified();
}
} while (line.length() > 0);
QVariantMap pluginInfo;
- pluginInfo[QStringLiteral("plugins")] = plugins.simplified();
- pluginInfo[QStringLiteral("classnames")] = classnames.simplified();
+ pluginInfo[pluginsLiteral()] = plugins.simplified();
+ pluginInfo[classnamesLiteral()] = classnames.simplified();
if (dependencies.length())
- pluginInfo[QStringLiteral("dependencies")] = dependencies;
+ pluginInfo[dependenciesLiteral()] = dependencies;
return pluginInfo;
}
@@ -163,7 +171,7 @@ QString resolveImportPath(const QString &uri, const QString &version)
QString ver = version;
while (true) {
- foreach (const QString &qmlImportPath, g_qmlImportPaths) {
+ for (const QString &qmlImportPath : qAsConst(g_qmlImportPaths)) {
// Search for the most specific version first, and search
// also for the version in parent modules. For example:
// - qml/QtQml/Models.2.0
@@ -209,26 +217,26 @@ QVariantList findPathsForModuleImports(const QVariantList &imports)
QVariantList importsCopy(imports);
for (int i = 0; i < importsCopy.length(); ++i) {
- QVariantMap import = qvariant_cast<QVariantMap>(importsCopy[i]);
- if (import[QStringLiteral("type")] == QLatin1String("module")) {
- QString path = resolveImportPath(import.value(QStringLiteral("name")).toString(), import.value(QStringLiteral("version")).toString());
+ QVariantMap import = qvariant_cast<QVariantMap>(importsCopy.at(i));
+ if (import.value(typeLiteral()) == QLatin1String("module")) {
+ QString path = resolveImportPath(import.value(nameLiteral()).toString(), import.value(versionLiteral()).toString());
if (!path.isEmpty())
- import[QStringLiteral("path")] = path;
- QVariantMap plugininfo = pluginsForModulePath(import.value(QStringLiteral("path")).toString());
- QString plugins = plugininfo.value(QStringLiteral("plugins")).toString();
- QString classnames = plugininfo.value(QStringLiteral("classnames")).toString();
+ import[pathLiteral()] = path;
+ QVariantMap plugininfo = pluginsForModulePath(import.value(pathLiteral()).toString());
+ QString plugins = plugininfo.value(pluginsLiteral()).toString();
+ QString classnames = plugininfo.value(classnamesLiteral()).toString();
if (!plugins.isEmpty())
- import[QStringLiteral("plugin")] = plugins;
+ import.insert(QStringLiteral("plugin"), plugins);
if (!classnames.isEmpty())
- import[QStringLiteral("classname")] = classnames;
- if (plugininfo.contains(QStringLiteral("dependencies"))) {
- QStringList dependencies = plugininfo.value(QStringLiteral("dependencies")).toStringList();
- foreach (const QString &line, dependencies) {
- QList<QString> dep = line.split(QLatin1Char(' '));
+ import.insert(QStringLiteral("classname"), classnames);
+ if (plugininfo.contains(dependenciesLiteral())) {
+ const QStringList dependencies = plugininfo.value(dependenciesLiteral()).toStringList();
+ for (const QString &line : dependencies) {
+ const auto dep = line.splitRef(QLatin1Char(' '));
QVariantMap depImport;
- depImport[QStringLiteral("type")] = QStringLiteral("module");
- depImport[QStringLiteral("name")] = dep[0];
- depImport[QStringLiteral("version")] = dep[1];
+ depImport[typeLiteral()] = QStringLiteral("module");
+ depImport[nameLiteral()] = dep[0].toString();
+ depImport[versionLiteral()] = dep[1].toString();
importsCopy.append(depImport);
}
}
@@ -248,7 +256,8 @@ static QVariantList findQmlImportsInQmlCode(const QString &filePath, const QStri
if (!parser.parse() || !parser.diagnosticMessages().isEmpty()) {
// Extract errors from the parser
- foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
+ const auto diagnosticMessages = parser.diagnosticMessages();
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
std::cerr << QDir::toNativeSeparators(filePath).toStdString() << ':'
<< m.loc.startLine << ':' << m.message.toStdString() << std::endl;
}
@@ -277,8 +286,8 @@ struct ImportCollector : public QQmlJS::Directives
virtual void importFile(const QString &jsfile, const QString &module, int line, int column)
{
QVariantMap entry;
- entry[QLatin1String("type")] = QStringLiteral("javascript");
- entry[QLatin1String("path")] = jsfile;
+ entry[typeLiteral()] = QStringLiteral("javascript");
+ entry[pathLiteral()] = jsfile;
imports << entry;
Q_UNUSED(module);
@@ -290,12 +299,12 @@ struct ImportCollector : public QQmlJS::Directives
{
QVariantMap entry;
if (uri.contains(QLatin1Char('/'))) {
- entry[QLatin1String("type")] = QStringLiteral("directory");
- entry[QLatin1String("name")] = uri;
+ entry[typeLiteral()] = QStringLiteral("directory");
+ entry[nameLiteral()] = uri;
} else {
- entry[QLatin1String("type")] = QStringLiteral("module");
- entry[QLatin1String("name")] = uri;
- entry[QLatin1String("version")] = version;
+ entry[typeLiteral()] = QStringLiteral("module");
+ entry[nameLiteral()] = uri;
+ entry[versionLiteral()] = version;
}
imports << entry;
@@ -326,7 +335,8 @@ QVariantList findQmlImportsInJavascriptFile(const QString &filePath)
QQmlJS::Parser parser(&ee);
parser.parseProgram();
- foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages())
+ const auto diagnosticMessages = parser.diagnosticMessages();
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages)
if (m.isError())
return QVariantList();
@@ -354,7 +364,7 @@ QVariantList findQmlImportsInFile(const QString &filePath)
QVariantList mergeImports(const QVariantList &a, const QVariantList &b)
{
QVariantList merged = a;
- foreach (const QVariant &variant, b) {
+ for (const QVariant &variant : b) {
if (!merged.contains(variant))
merged.append(variant);
}
@@ -413,19 +423,19 @@ QVariantList findQmlImportsInDirectory(const QString &qmlDir)
continue;
}
- foreach (const QFileInfo &x, entries)
+ for (const QFileInfo &x : entries)
if (x.isFile())
ret = mergeImports(ret, findQmlImportsInFile(x.absoluteFilePath()));
}
return ret;
}
-QSet<QString> importModulePaths(QVariantList imports) {
+QSet<QString> importModulePaths(const QVariantList &imports) {
QSet<QString> ret;
- foreach (const QVariant &importVariant, imports) {
+ for (const QVariant &importVariant : imports) {
QVariantMap import = qvariant_cast<QVariantMap>(importVariant);
- QString path = import.value(QStringLiteral("path")).toString();
- QString type = import.value(QStringLiteral("type")).toString();
+ QString path = import.value(pathLiteral()).toString();
+ QString type = import.value(typeLiteral()).toString();
if (type == QLatin1String("module") && !path.isEmpty())
ret.insert(QDir(path).canonicalPath());
}
@@ -440,13 +450,13 @@ QVariantList findQmlImportsRecursively(const QStringList &qmlDirs, const QString
QVariantList ret;
// scan all app root qml directories for imports
- foreach (const QString &qmlDir, qmlDirs) {
+ for (const QString &qmlDir : qmlDirs) {
QVariantList imports = findQmlImportsInDirectory(qmlDir);
ret = mergeImports(ret, imports);
}
// scan app qml files for imports
- foreach (const QString &file, scanFiles) {
+ for (const QString &file : scanFiles) {
QVariantList imports = findQmlImportsInFile(file);
ret = mergeImports(ret, imports);
}
diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp
index 68aa52ce91..44ff37b925 100644
--- a/tools/qmljs/qmljs.cpp
+++ b/tools/qmljs/qmljs.cpp
@@ -68,7 +68,7 @@ struct Print: FunctionObject
};
V4_OBJECT(FunctionObject)
- static ReturnedValue call(const Managed *, CallData *callData)
+ static void call(const Managed *, Scope &scope, CallData *callData)
{
for (int i = 0; i < callData->argc; ++i) {
QString s = callData->args[i].toQStringNoThrow();
@@ -77,7 +77,7 @@ struct Print: FunctionObject
std::cout << qPrintable(s);
}
std::cout << std::endl;
- return Encode::undefined();
+ scope.result = Encode::undefined();
}
};
@@ -94,10 +94,10 @@ struct GC: public FunctionObject
};
V4_OBJECT(FunctionObject)
- static ReturnedValue call(const Managed *m, CallData *)
+ static void call(const Managed *m, Scope &scope, CallData *)
{
static_cast<const GC *>(m)->engine()->memoryManager->runGC();
- return Encode::undefined();
+ scope.result = Encode::undefined();
}
};
@@ -118,7 +118,7 @@ static void showException(QV4::ExecutionContext *ctx, const QV4::Value &exceptio
std::cerr << "Uncaught exception: " << qPrintable(message->toQStringNoThrow()) << std::endl;
}
- foreach (const QV4::StackFrame &frame, trace) {
+ for (const QV4::StackFrame &frame : trace) {
std::cerr << " at " << qPrintable(frame.function) << " (" << qPrintable(frame.source);
if (frame.line >= 0)
std::cerr << ':' << frame.line;
@@ -145,22 +145,22 @@ int main(int argc, char *argv[])
bool runAsQml = false;
if (!args.isEmpty()) {
- if (args.first() == QLatin1String("--jit")) {
+ if (args.constFirst() == QLatin1String("--jit")) {
mode = use_masm;
args.removeFirst();
}
- if (args.first() == QLatin1String("--interpret")) {
+ if (args.constFirst() == QLatin1String("--interpret")) {
mode = use_moth;
args.removeFirst();
}
- if (args.first() == QLatin1String("--qml")) {
+ if (args.constFirst() == QLatin1String("--qml")) {
runAsQml = true;
args.removeFirst();
}
- if (args.first() == QLatin1String("--help")) {
+ if (args.constFirst() == QLatin1String("--help")) {
std::cerr << "Usage: qmljs [|--jit|--interpret|--qml] file..." << std::endl;
return EXIT_SUCCESS;
}
@@ -188,7 +188,7 @@ int main(int argc, char *argv[])
QV4::ScopedObject gc(scope, vm.memoryManager->allocObject<builtins::GC>(ctx));
vm.globalObject->put(QV4::ScopedString(scope, vm.newIdentifier(QStringLiteral("gc"))).getPointer(), gc);
- foreach (const QString &fn, args) {
+ for (const QString &fn : qAsConst(args)) {
QFile file(fn);
if (file.open(QFile::ReadOnly)) {
const QString code = QString::fromUtf8(file.readAll());
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 211427cc64..99a53110a8 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -59,7 +59,8 @@ static bool lint_file(const QString &filename, bool silent)
bool success = isJavaScript ? parser.parseProgram() : parser.parse();
if (!success && !silent) {
- foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
+ const auto diagnosticMessages = parser.diagnosticMessages();
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
qWarning("%s:%d : %s", qPrintable(filename), m.loc.startLine, qPrintable(m.message));
}
}
@@ -82,15 +83,15 @@ int main(int argv, char *argc[])
parser.process(app);
- if (parser.positionalArguments().isEmpty()) {
+ const auto positionalArguments = parser.positionalArguments();
+ if (positionalArguments.isEmpty()) {
parser.showHelp(-1);
}
bool silent = parser.isSet(silentOption);
bool success = true;
- foreach (const QString &filename, parser.positionalArguments()) {
+ for (const QString &filename : positionalArguments)
success &= lint_file(filename, silent);
- }
return success ? 0 : -1;
}
diff --git a/tools/qmlmin/main.cpp b/tools/qmlmin/main.cpp
index 2b18a8442b..d2bad9d0d5 100644
--- a/tools/qmlmin/main.cpp
+++ b/tools/qmlmin/main.cpp
@@ -120,7 +120,7 @@ protected:
static QString quote(const QString &string)
{
QString quotedString;
- foreach (const QChar &ch, string) {
+ for (const QChar &ch : string) {
if (ch == QLatin1Char('"'))
quotedString += QLatin1String("\\\"");
else {
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index 395b3cd195..3294fa1e87 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -75,6 +75,12 @@
static const uint qtQmlMajorVersion = 2;
static const uint qtQmlMinorVersion = 2;
+static const uint qtQuickMajorVersion = 2;
+static const uint qtQuickMinorVersion = 8;
+
+const QString qtQuickQualifiedName = QString::fromLatin1("QtQuick %1.%2")
+ .arg(qtQuickMajorVersion)
+ .arg(qtQuickMinorVersion);
QString pluginImportPath;
bool verbose = false;
@@ -199,7 +205,8 @@ QByteArray convertToId(const QMetaObject *mo)
// Collect all metaobjects for types registered with qmlRegisterType() without parameters
void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet<const QMetaObject *>& metas ) {
- foreach (const QQmlType *ty, QQmlMetaType::qmlAllTypes()) {
+ const auto qmlAllTypes = QQmlMetaType::qmlAllTypes();
+ for (const QQmlType *ty : qmlAllTypes) {
if ( ! metas.contains(ty->metaObject()) ) {
if (!ty->isComposite()) {
collectReachableMetaObjects(engine, ty, &metas);
@@ -219,7 +226,8 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
metas.insert(FriendlyQObject::qtMeta());
QHash<QByteArray, QSet<QByteArray> > extensions;
- foreach (const QQmlType *ty, QQmlMetaType::qmlTypes()) {
+ const auto qmlTypes = QQmlMetaType::qmlTypes();
+ for (const QQmlType *ty : qmlTypes) {
if (!ty->isCreatable())
noncreatables.insert(ty->metaObject());
if (ty->isSingleton())
@@ -242,15 +250,15 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
QSet<const QQmlType *> baseExports = qmlTypesByCppName.value(it.key());
const QSet<QByteArray> extensionCppNames = it.value();
- foreach (const QByteArray &extensionCppName, extensionCppNames) {
+ for (const QByteArray &extensionCppName : extensionCppNames) {
const QSet<const QQmlType *> extensionExports = qmlTypesByCppName.value(extensionCppName);
// remove extension exports from base imports
// unfortunately the QQmlType pointers don't match, so can't use QSet::subtract
QSet<const QQmlType *> newBaseExports;
- foreach (const QQmlType *baseExport, baseExports) {
+ for (const QQmlType *baseExport : qAsConst(baseExports)) {
bool match = false;
- foreach (const QQmlType *extensionExport, extensionExports) {
+ for (const QQmlType *extensionExport : extensionExports) {
if (baseExport->qmlTypeName() == extensionExport->qmlTypeName()
&& baseExport->majorVersion() == extensionExport->majorVersion()
&& baseExport->minorVersion() == extensionExport->minorVersion()) {
@@ -269,7 +277,7 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
if (creatable) {
// find even more QMetaObjects by instantiating QML types and running
// over the instances
- foreach (QQmlType *ty, QQmlMetaType::qmlTypes()) {
+ for (QQmlType *ty : qmlTypes) {
if (skip.contains(ty))
continue;
if (ty->isExtendedType())
@@ -463,7 +471,7 @@ public:
void dumpComposite(QQmlEngine *engine, const QSet<const QQmlType *> &compositeType, QSet<QByteArray> &defaultReachableNames)
{
- foreach (const QQmlType *type, compositeType)
+ for (const QQmlType *type : compositeType)
dumpCompositeItem(engine, type, defaultReachableNames);
}
@@ -512,7 +520,7 @@ public:
}
}
- foreach (const QMetaObject *meta, objectsToMerge)
+ for (const QMetaObject *meta : qAsConst(objectsToMerge))
writeMetaContent(meta, &knownAttributes);
qml->writeEndObject();
@@ -536,11 +544,11 @@ public:
if (meta->superClass())
qml->writeScriptBinding(QLatin1String("prototype"), enquote(convertToId(meta->superClass())));
- QSet<const QQmlType *> qmlTypes = qmlTypesByCppName.value(meta->className());
+ const QSet<const QQmlType *> qmlTypes = qmlTypesByCppName.value(meta->className());
if (!qmlTypes.isEmpty()) {
QHash<QString, const QQmlType *> exports;
- foreach (const QQmlType *qmlTy, qmlTypes) {
+ for (const QQmlType *qmlTy : qmlTypes) {
const QString exportString = getExportString(qmlTy->qmlTypeName(), qmlTy->majorVersion(), qmlTy->minorVersion());
exports.insert(exportString, qmlTy);
}
@@ -558,7 +566,7 @@ public:
// write meta object revisions
QStringList metaObjectRevisions;
- foreach (const QString &exportString, exportStrings) {
+ for (const QString &exportString : qAsConst(exportStrings)) {
int metaObjectRevision = exports[exportString]->metaObjectRevision();
metaObjectRevisions += QString::number(metaObjectRevision);
}
@@ -730,7 +738,7 @@ void sigSegvHandler(int) {
void printUsage(const QString &appName)
{
std::cerr << qPrintable(QString(
- "Usage: %1 [-v] [-noinstantiate] [-defaultplatform] [-[non]relocatable] [-dependencies <dependencies.json>] [-merge <file-to-merge.qmltypes>] module.uri version [module/import/path]\n"
+ "Usage: %1 [-v] [-noinstantiate] [-defaultplatform] [-[non]relocatable] [-dependencies <dependencies.json>] [-merge <file-to-merge.qmltypes>] [-noforceqtquick] module.uri version [module/import/path]\n"
" %1 [-v] [-noinstantiate] -path path/to/qmldir/directory [version]\n"
" %1 [-v] -builtins\n"
"Example: %1 Qt.labs.folderlistmodel 2.0 /home/user/dev/qt-install/imports").arg(
@@ -738,11 +746,12 @@ void printUsage(const QString &appName)
}
static bool readDependenciesData(QString dependenciesFile, const QByteArray &fileData,
- QStringList *dependencies, const QStringList &urisToSkip) {
+ QStringList *dependencies, const QStringList &urisToSkip,
+ bool forceQtQuickDependency = true) {
if (verbose) {
std::cerr << "parsing "
<< qPrintable( dependenciesFile ) << " skipping";
- foreach (const QString &uriToSkip, urisToSkip)
+ for (const QString &uriToSkip : urisToSkip)
std::cerr << ' ' << qPrintable(uriToSkip);
std::cerr << std::endl;
}
@@ -756,13 +765,14 @@ static bool readDependenciesData(QString dependenciesFile, const QByteArray &fil
return false;
}
if (doc.isArray()) {
- QStringList requiredKeys = QStringList() << QStringLiteral("name")
- << QStringLiteral("type")
- << QStringLiteral("version");
- foreach (const QJsonValue &dep, doc.array()) {
+ const QStringList requiredKeys = QStringList() << QStringLiteral("name")
+ << QStringLiteral("type")
+ << QStringLiteral("version");
+ const auto deps = doc.array();
+ for (const QJsonValue &dep : deps) {
if (dep.isObject()) {
QJsonObject obj = dep.toObject();
- foreach (const QString &requiredKey, requiredKeys)
+ for (const QString &requiredKey : requiredKeys)
if (!obj.contains(requiredKey) || obj.value(requiredKey).isString())
continue;
if (obj.value(QStringLiteral("type")).toString() != QLatin1String("module"))
@@ -793,8 +803,8 @@ static bool readDependenciesData(QString dependenciesFile, const QByteArray &fil
// qmlplugindump used to import QtQuick, so all types defined in QtQuick used to be skipped when dumping.
// Now that it imports only Qt, it is no longer the case: if no dependency is found all the types defined
// in QtQuick will be dumped, causing conflicts.
- if (dependencies->isEmpty())
- dependencies->push_back(QLatin1String("QtQuick 2.0"));
+ if (forceQtQuickDependency && dependencies->isEmpty())
+ dependencies->push_back(qtQuickQualifiedName);
return true;
}
@@ -812,11 +822,12 @@ static bool readDependenciesFile(const QString &dependenciesFile, QStringList *d
return false;
}
QByteArray fileData = f.readAll();
- return readDependenciesData(dependenciesFile, fileData, dependencies, urisToSkip);
+ return readDependenciesData(dependenciesFile, fileData, dependencies, urisToSkip, false);
}
static bool getDependencies(const QQmlEngine &engine, const QString &pluginImportUri,
- const QString &pluginImportVersion, QStringList *dependencies)
+ const QString &pluginImportVersion, QStringList *dependencies,
+ bool forceQtQuickDependency)
{
QFileInfo selfExe(QCoreApplication::applicationFilePath());
QString command = selfExe.absoluteDir().filePath(QLatin1String("qmlimportscanner")
@@ -825,7 +836,8 @@ static bool getDependencies(const QQmlEngine &engine, const QString &pluginImpor
QStringList commandArgs = QStringList()
<< QLatin1String("-qmlFiles")
<< QLatin1String("-");
- foreach (const QString &path, engine.importPathList())
+ const auto importPathList = engine.importPathList();
+ for (const QString &path : importPathList)
commandArgs << QLatin1String("-importPath") << path;
QProcess importScanner;
@@ -842,20 +854,20 @@ static bool getDependencies(const QQmlEngine &engine, const QString &pluginImpor
if (!importScanner.waitForFinished()) {
std::cerr << "failure to start " << qPrintable(command);
- foreach (const QString &arg, commandArgs)
+ for (const QString &arg : qAsConst(commandArgs))
std::cerr << ' ' << qPrintable(arg);
std::cerr << std::endl;
return false;
}
QByteArray depencenciesData = importScanner.readAllStandardOutput();
if (!readDependenciesData(QLatin1String("<outputOfQmlimportscanner>"), depencenciesData,
- dependencies, QStringList(pluginImportUri))) {
+ dependencies, QStringList(pluginImportUri), forceQtQuickDependency)) {
std::cerr << "failed to proecess output of qmlimportscanner" << std::endl;
return false;
}
QStringList aux;
- foreach (const QString &str, *dependencies) {
+ for (const QString &str : qAsConst(*dependencies)) {
if (!str.startsWith("Qt.test.qtestroot"))
aux += str;
}
@@ -869,20 +881,20 @@ bool compactDependencies(QStringList *dependencies)
if (dependencies->isEmpty())
return false;
dependencies->sort();
- QStringList oldDep = dependencies->first().split(QLatin1Char(' '));
+ QStringList oldDep = dependencies->constFirst().split(QLatin1Char(' '));
Q_ASSERT(oldDep.size() == 2);
int oldPos = 0;
for (int idep = 1; idep < dependencies->size(); ++idep) {
QString depStr = dependencies->at(idep);
const QStringList newDep = depStr.split(QLatin1Char(' '));
Q_ASSERT(newDep.size() == 2);
- if (newDep.first() != oldDep.first()) {
+ if (newDep.constFirst() != oldDep.constFirst()) {
if (++oldPos != idep)
dependencies->replace(oldPos, depStr);
oldDep = newDep;
} else {
- QStringList v1 = oldDep.last().split(QLatin1Char('.'));
- QStringList v2 = newDep.last().split(QLatin1Char('.'));
+ const QStringList v1 = oldDep.constLast().split(QLatin1Char('.'));
+ const QStringList v2 = newDep.constLast().split(QLatin1Char('.'));
Q_ASSERT(v1.size() == 2);
Q_ASSERT(v2.size() == 2);
bool ok;
@@ -891,9 +903,9 @@ bool compactDependencies(QStringList *dependencies)
int major2 = v2.first().toInt(&ok);
Q_ASSERT(ok);
if (major1 != major2) {
- std::cerr << "Found a dependency on " << qPrintable(oldDep.first())
- << " with two major versions:" << qPrintable(oldDep.last())
- << " and " << qPrintable(newDep.last())
+ std::cerr << "Found a dependency on " << qPrintable(oldDep.constFirst())
+ << " with two major versions:" << qPrintable(oldDep.constLast())
+ << " and " << qPrintable(newDep.constLast())
<< " which is unsupported, discarding smaller version" << std::endl;
if (major1 < major2)
dependencies->replace(oldPos, depStr);
@@ -969,10 +981,11 @@ int main(int argc, char *argv[])
}
}
- if (!requireWindowManager)
+ if (!requireWindowManager && qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM"))
qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal"));
+ else
+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
- QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
QGuiApplication app(argc, argv);
const QStringList args = app.arguments();
const QString appName = QFileInfo(app.applicationFilePath()).baseName();
@@ -986,6 +999,7 @@ int main(int argc, char *argv[])
bool relocatable = true;
QString dependenciesFile;
QString mergeFile;
+ bool forceQtQuickDependency = true;
enum Action { Uri, Path, Builtins };
Action action = Uri;
{
@@ -1030,6 +1044,9 @@ int main(int argc, char *argv[])
action = Builtins;
} else if (arg == QLatin1String("-v")) {
verbose = true;
+ } else if (arg == QLatin1String("--noforceqtquick")
+ || arg == QLatin1String("-noforceqtquick")){
+ forceQtQuickDependency = false;
} else if (arg == QLatin1String("--defaultplatform")
|| arg == QLatin1String("-defaultplatform")) {
continue;
@@ -1044,18 +1061,18 @@ int main(int argc, char *argv[])
std::cerr << "Incorrect number of positional arguments" << std::endl;
return EXIT_INVALIDARGUMENTS;
}
- pluginImportUri = positionalArgs[1];
+ pluginImportUri = positionalArgs.at(1);
pluginImportVersion = positionalArgs[2];
if (positionalArgs.size() >= 4)
- pluginImportPath = positionalArgs[3];
+ pluginImportPath = positionalArgs.at(3);
} else if (action == Path) {
if (positionalArgs.size() != 2 && positionalArgs.size() != 3) {
std::cerr << "Incorrect number of positional arguments" << std::endl;
return EXIT_INVALIDARGUMENTS;
}
- pluginImportPath = QDir::fromNativeSeparators(positionalArgs[1]);
+ pluginImportPath = QDir::fromNativeSeparators(positionalArgs.at(1));
if (positionalArgs.size() == 3)
- pluginImportVersion = positionalArgs[2];
+ pluginImportVersion = positionalArgs.at(2);
} else if (action == Builtins) {
if (positionalArgs.size() != 1) {
std::cerr << "Incorrect number of positional arguments" << std::endl;
@@ -1077,7 +1094,7 @@ int main(int argc, char *argv[])
QStringList mergeDependencies;
QString mergeComponents;
if (!mergeFile.isEmpty()) {
- QStringList merge = readQmlTypes(mergeFile);
+ const QStringList merge = readQmlTypes(mergeFile);
if (!merge.isEmpty()) {
QRegularExpression re("(\\w+\\.*\\w*\\s*\\d+\\.\\d+)");
QRegularExpressionMatchIterator i = re.globalMatch(merge[1]);
@@ -1098,9 +1115,12 @@ int main(int argc, char *argv[])
calculateDependencies = !readDependenciesFile(dependenciesFile, &dependencies,
QStringList(pluginImportUri)) && calculateDependencies;
if (calculateDependencies)
- getDependencies(engine, pluginImportUri, pluginImportVersion, &dependencies);
+ getDependencies(engine, pluginImportUri, pluginImportVersion, &dependencies,
+ forceQtQuickDependency);
+
compactDependencies(&dependencies);
+
QString qtQmlImportString = QString::fromLatin1("import QtQml %1.%2")
.arg(qtQmlMajorVersion)
.arg(qtQmlMinorVersion);
@@ -1108,7 +1128,7 @@ int main(int argc, char *argv[])
// load the QtQml builtins and the dependencies
{
QByteArray code(qtQmlImportString.toUtf8());
- foreach (const QString &moduleToImport, dependencies) {
+ for (const QString &moduleToImport : qAsConst(dependencies)) {
code.append("\nimport ");
code.append(moduleToImport.toUtf8());
}
@@ -1116,8 +1136,9 @@ int main(int argc, char *argv[])
QQmlComponent c(&engine);
c.setData(code, QUrl::fromLocalFile(pluginImportPath + "/loaddependencies.qml"));
c.create();
- if (!c.errors().isEmpty()) {
- foreach (const QQmlError &error, c.errors())
+ const auto errors = c.errors();
+ if (!errors.isEmpty()) {
+ for (const QQmlError &error : errors)
std::cerr << qPrintable( error.toString() ) << std::endl;
return EXIT_IMPORTERROR;
}
@@ -1138,7 +1159,7 @@ int main(int argc, char *argv[])
QSet<const QMetaObject *> metas;
if (action == Builtins) {
- foreach (const QMetaObject *m, defaultReachable) {
+ for (const QMetaObject *m : qAsConst(defaultReachable)) {
if (m->className() == QLatin1String("Qt")) {
metas.insert(m);
break;
@@ -1146,7 +1167,7 @@ int main(int argc, char *argv[])
}
} else if (pluginImportUri == QLatin1String("QtQml")) {
bool ok = false;
- const uint major = pluginImportVersion.split('.')[0].toUInt(&ok, 10);
+ const uint major = pluginImportVersion.splitRef('.').at(0).toUInt(&ok, 10);
if (!ok) {
std::cerr << "Malformed version string \""<< qPrintable(pluginImportVersion) << "\"."
<< std::endl;
@@ -1159,7 +1180,7 @@ int main(int argc, char *argv[])
return EXIT_INVALIDARGUMENTS;
}
metas = defaultReachable;
- foreach (const QMetaObject *m, defaultReachable) {
+ for (const QMetaObject *m : qAsConst(defaultReachable)) {
if (m->className() == QLatin1String("Qt")) {
metas.remove(m);
break;
@@ -1180,7 +1201,7 @@ int main(int argc, char *argv[])
QString::number(qtObjectType->minorVersion())).toUtf8();
}
// avoid importing dependencies?
- foreach (const QString &moduleToImport, dependencies) {
+ for (const QString &moduleToImport : qAsConst(dependencies)) {
importCode.append("\nimport ");
importCode.append(moduleToImport.toUtf8());
}
@@ -1202,8 +1223,9 @@ int main(int argc, char *argv[])
c.setData(code, QUrl::fromLocalFile(pluginImportPath + "/typelist.qml"));
c.create();
- if (!c.errors().isEmpty()) {
- foreach (const QQmlError &error, c.errors())
+ const auto errors = c.errors();
+ if (!errors.isEmpty()) {
+ for (const QQmlError &error : errors)
std::cerr << qPrintable( error.toString() ) << std::endl;
return EXIT_IMPORTERROR;
}
@@ -1215,9 +1237,9 @@ int main(int argc, char *argv[])
// Also eliminate meta objects with the same classname.
// This is required because extended objects seem not to share
// a single meta object instance.
- foreach (const QMetaObject *mo, defaultReachable)
+ for (const QMetaObject *mo : qAsConst(defaultReachable))
defaultReachableNames.insert(QByteArray(mo->className()));
- foreach (const QMetaObject *mo, candidates) {
+ for (const QMetaObject *mo : qAsConst(candidates)) {
if (!defaultReachableNames.contains(mo->className()))
metas.insert(mo);
}
@@ -1249,19 +1271,19 @@ int main(int argc, char *argv[])
compactDependencies(&dependencies);
QStringList quotedDependencies;
- foreach (const QString &dep, dependencies)
+ for (const QString &dep : qAsConst(dependencies))
quotedDependencies << enquote(dep);
qml.writeArrayBinding("dependencies", quotedDependencies);
// put the metaobjects into a map so they are always dumped in the same order
QMap<QString, const QMetaObject *> nameToMeta;
- foreach (const QMetaObject *meta, metas)
+ for (const QMetaObject *meta : qAsConst(metas))
nameToMeta.insert(convertToId(meta), meta);
Dumper dumper(&qml);
if (relocatable)
dumper.setRelocatableModuleUri(pluginImportUri);
- foreach (const QMetaObject *meta, nameToMeta) {
+ for (const QMetaObject *meta : qAsConst(nameToMeta)) {
dumper.dump(QQmlEnginePrivate::get(&engine), meta, uncreatableMetas.contains(meta), singletonMetas.contains(meta));
}
diff --git a/tools/qmlplugindump/qmlplugindump.pro b/tools/qmlplugindump/qmlplugindump.pro
index e45a7fad83..b38eea2554 100644
--- a/tools/qmlplugindump/qmlplugindump.pro
+++ b/tools/qmlplugindump/qmlplugindump.pro
@@ -17,7 +17,7 @@ macx {
# Prevent qmlplugindump from popping up in the dock when launched.
# We embed the Info.plist file, so the application doesn't need to
# be a bundle.
- QMAKE_LFLAGS += -sectcreate __TEXT __info_plist $$shell_quote($$PWD/Info.plist)
+ QMAKE_LFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,$$shell_quote($$PWD/Info.plist)
CONFIG -= app_bundle
}
diff --git a/tools/qmlplugindump/qmlstreamwriter.cpp b/tools/qmlplugindump/qmlstreamwriter.cpp
index dd3c188fe4..3632cee60d 100644
--- a/tools/qmlplugindump/qmlstreamwriter.cpp
+++ b/tools/qmlplugindump/qmlstreamwriter.cpp
@@ -179,7 +179,7 @@ void QmlStreamWriter::flushPotentialLinesWithNewlines()
{
if (m_maybeOneline)
m_stream->write("\n");
- foreach (const QByteArray &line, m_pendingLines) {
+ for (const QByteArray &line : qAsConst(m_pendingLines)) {
writeIndent();
m_stream->write(line);
m_stream->write("\n");
diff --git a/tools/qmlplugindump/qmltypereader.cpp b/tools/qmlplugindump/qmltypereader.cpp
index 67ba415388..9dfb6fc1e0 100644
--- a/tools/qmlplugindump/qmltypereader.cpp
+++ b/tools/qmlplugindump/qmltypereader.cpp
@@ -40,7 +40,7 @@
#include <iostream>
QStringList readQmlTypes(const QString &filename) {
- QRegularExpression re("import QtQuick.tooling 1.2.*Module {\\s*dependencies:\\[([^\\]]*)\\](.*)}",
+ QRegularExpression re("import QtQuick\\.tooling 1\\.2.*Module {\\s*dependencies:\\s*\\[([^\\]]*)\\](.*)}",
QRegularExpression::DotMatchesEverythingOption);
if (!QFileInfo(filename).exists()) {
std::cerr << "Non existing file: " << filename.toStdString() << std::endl;
diff --git a/tools/qmlprofiler/commandlistener.h b/tools/qmlprofiler/commandlistener.h
index c10b199daa..2a994bf449 100644
--- a/tools/qmlprofiler/commandlistener.h
+++ b/tools/qmlprofiler/commandlistener.h
@@ -33,7 +33,7 @@
class CommandListener : public QObject {
Q_OBJECT
-public slots:
+public:
void readCommand();
signals:
diff --git a/tools/qmlprofiler/main.cpp b/tools/qmlprofiler/main.cpp
index d3e2beb83f..c7cb979ff8 100644
--- a/tools/qmlprofiler/main.cpp
+++ b/tools/qmlprofiler/main.cpp
@@ -39,8 +39,10 @@ int main(int argc, char *argv[])
QThread listenerThread;
CommandListener listener;
listener.moveToThread(&listenerThread);
- QObject::connect(&listener, SIGNAL(command(QString)), &app, SLOT(userCommand(QString)));
- QObject::connect(&app, SIGNAL(readyForCommand()), &listener, SLOT(readCommand()));
+ QObject::connect(&listener, &CommandListener::command,
+ &app, &QmlProfilerApplication::userCommand);
+ QObject::connect(&app, &QmlProfilerApplication::readyForCommand,
+ &listener, &CommandListener::readCommand);
listenerThread.start();
int exitValue = app.exec();
listenerThread.quit();
diff --git a/tools/qmlprofiler/qmlprofilerapplication.cpp b/tools/qmlprofiler/qmlprofilerapplication.cpp
index b04ff7e558..033492b516 100644
--- a/tools/qmlprofiler/qmlprofilerapplication.cpp
+++ b/tools/qmlprofiler/qmlprofilerapplication.cpp
@@ -87,17 +87,21 @@ QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) :
m_connectionAttempts(0)
{
m_connectTimer.setInterval(1000);
- connect(&m_connectTimer, SIGNAL(timeout()), this, SLOT(tryToConnect()));
+ connect(&m_connectTimer, &QTimer::timeout, this, &QmlProfilerApplication::tryToConnect);
- connect(&m_connection, SIGNAL(connected()), this, SLOT(connected()));
+ connect(&m_connection, &QQmlDebugConnection::connected,
+ this, &QmlProfilerApplication::connected);
- connect(&m_qmlProfilerClient, SIGNAL(enabledChanged(bool)),
- this, SLOT(traceClientEnabledChanged(bool)));
- connect(&m_qmlProfilerClient, SIGNAL(recordingStarted()), this, SLOT(notifyTraceStarted()));
- connect(&m_qmlProfilerClient, SIGNAL(error(QString)), this, SLOT(logError(QString)));
+ connect(&m_qmlProfilerClient, &QmlProfilerClient::enabledChanged,
+ this, &QmlProfilerApplication::traceClientEnabledChanged);
+ connect(&m_qmlProfilerClient, &QmlProfilerClient::recordingStarted,
+ this, &QmlProfilerApplication::notifyTraceStarted);
+ connect(&m_qmlProfilerClient, &QmlProfilerClient::error,
+ this, &QmlProfilerApplication::logError);
- connect(&m_profilerData, SIGNAL(error(QString)), this, SLOT(logError(QString)));
- connect(&m_profilerData, SIGNAL(dataReady()), this, SLOT(traceFinished()));
+ connect(&m_profilerData, &QmlProfilerData::error, this, &QmlProfilerApplication::logError);
+ connect(&m_profilerData, &QmlProfilerData::dataReady,
+ this, &QmlProfilerApplication::traceFinished);
}
@@ -257,7 +261,7 @@ void QmlProfilerApplication::parseArguments()
int QmlProfilerApplication::exec()
{
- QTimer::singleShot(0, this, SLOT(run()));
+ QTimer::singleShot(0, this, &QmlProfilerApplication::run);
return QCoreApplication::exec();
}
@@ -270,8 +274,8 @@ quint64 QmlProfilerApplication::parseFeatures(const QStringList &featureList, co
bool exclude)
{
quint64 features = exclude ? std::numeric_limits<quint64>::max() : 0;
- QStringList givenFeatures = values.split(QLatin1Char(','));
- foreach (const QString &f, givenFeatures) {
+ const QStringList givenFeatures = values.split(QLatin1Char(','));
+ for (const QString &f : givenFeatures) {
int index = featureList.indexOf(f);
if (index < 0) {
logError(tr("Unknown feature '%1'").arg(f));
@@ -343,7 +347,7 @@ bool QmlProfilerApplication::checkOutputFile(PendingRequest pending)
void QmlProfilerApplication::userCommand(const QString &command)
{
- QStringList args = command.split(QChar::Space, QString::SkipEmptyParts);
+ auto args = command.splitRef(QChar::Space, QString::SkipEmptyParts);
if (args.isEmpty()) {
prompt();
return;
@@ -397,7 +401,7 @@ void QmlProfilerApplication::userCommand(const QString &command)
} else if (m_profilerData.isEmpty()) {
prompt(tr("No data was recorded so far."));
} else {
- m_interactiveOutputFile = args.length() > 0 ? args[0] : m_outputFile;
+ m_interactiveOutputFile = args.length() > 0 ? args.at(0).toString() : m_outputFile;
if (checkOutputFile(REQUEST_OUTPUT_FILE))
output();
}
@@ -414,7 +418,7 @@ void QmlProfilerApplication::userCommand(const QString &command)
if (!m_recording && m_profilerData.isEmpty()) {
prompt(tr("No data was recorded so far."));
} else {
- m_interactiveOutputFile = args.length() > 0 ? args[0] : m_outputFile;
+ m_interactiveOutputFile = args.length() > 0 ? args.at(0).toString() : m_outputFile;
if (checkOutputFile(REQUEST_FLUSH_FILE))
flush();
}
@@ -460,9 +464,9 @@ void QmlProfilerApplication::run()
arguments << m_programArguments;
m_process->setProcessChannelMode(QProcess::MergedChannels);
- connect(m_process, SIGNAL(readyRead()), this, SLOT(processHasOutput()));
- connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this,
- SLOT(processFinished()));
+ connect(m_process, &QIODevice::readyRead, this, &QmlProfilerApplication::processHasOutput);
+ connect(m_process, static_cast<void(QProcess::*)(int)>(&QProcess::finished),
+ this, [this](int){ processFinished(); });
logStatus(QString("Starting '%1 %2' ...").arg(m_programPath,
arguments.join(QLatin1Char(' '))));
m_process->start(m_programPath, arguments);
diff --git a/tools/qmlprofiler/qmlprofilerapplication.h b/tools/qmlprofiler/qmlprofilerapplication.h
index 04f9d43c87..13f0f041f0 100644
--- a/tools/qmlprofiler/qmlprofilerapplication.h
+++ b/tools/qmlprofiler/qmlprofilerapplication.h
@@ -58,16 +58,14 @@ public:
void parseArguments();
int exec();
bool isInteractive() const;
-
-signals:
- void readyForCommand();
-
-public slots:
void userCommand(const QString &command);
void notifyTraceStarted();
void outputData();
-private slots:
+signals:
+ void readyForCommand();
+
+private:
void run();
void tryToConnect();
void connected();
@@ -81,7 +79,6 @@ private slots:
void logError(const QString &error);
void logStatus(const QString &status);
-private:
quint64 parseFeatures(const QStringList &featureList, const QString &values, bool exclude);
bool checkOutputFile(PendingRequest pending);
void flush();
diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp
index 74fa44c1d6..668cb3ce2d 100644
--- a/tools/qmlprofiler/qmlprofilerdata.cpp
+++ b/tools/qmlprofiler/qmlprofilerdata.cpp
@@ -248,7 +248,7 @@ void QmlProfilerData::addQmlEvent(QQmlProfilerDefinitions::RangeType type,
eventHashStr = getHashStringForQmlEvent(eventLocation, type);
} else {
const QString filePath = QUrl(eventLocation.filename).path();
- displayName = filePath.mid(
+ displayName = filePath.midRef(
filePath.lastIndexOf(QLatin1Char('/')) + 1) +
QLatin1Char(':') + QString::number(eventLocation.line);
eventHashStr = getHashStringForQmlEvent(eventLocation, type);
@@ -327,8 +327,8 @@ void QmlProfilerData::addPixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventTy
QString filePath = QUrl(location).path();
- QString eventHashStr = filePath.mid(filePath.lastIndexOf(QLatin1Char('/')) + 1) +
- QStringLiteral(":") + QString::number(type);
+ const QString eventHashStr = filePath.midRef(filePath.lastIndexOf(QLatin1Char('/')) + 1)
+ + QLatin1Char(':') + QString::number(type);
QmlRangeEventData *newEvent;
if (d->eventDescriptions.contains(eventHashStr)) {
newEvent = d->eventDescriptions[eventHashStr];
@@ -403,23 +403,23 @@ void QmlProfilerData::computeQmlTime()
int level = minimumLevel;
for (int i = 0; i < d->startInstanceList.count(); i++) {
- qint64 st = d->startInstanceList[i].startTime;
+ qint64 st = d->startInstanceList.at(i).startTime;
- if (d->startInstanceList[i].data->rangeType == QQmlProfilerDefinitions::Painting) {
+ if (d->startInstanceList.at(i).data->rangeType == QQmlProfilerDefinitions::Painting) {
continue;
}
// general level
- if (endtimesPerLevel[level] > st) {
+ if (endtimesPerLevel.value(level) > st) {
level++;
} else {
while (level > minimumLevel && endtimesPerLevel[level-1] <= st)
level--;
}
- endtimesPerLevel[level] = st + d->startInstanceList[i].duration;
+ endtimesPerLevel[level] = st + d->startInstanceList.at(i).duration;
if (level == minimumLevel) {
- d->qmlMeasuredTime += d->startInstanceList[i].duration;
+ d->qmlMeasuredTime += d->startInstanceList.at(i).duration;
}
}
}
@@ -572,7 +572,7 @@ bool QmlProfilerData::save(const QString &filename)
stream.writeEndElement(); // eventData
stream.writeStartElement(QStringLiteral("profilerDataModel"));
- foreach (const QmlRangeEventStartInstance &event, d->startInstanceList) {
+ for (const QmlRangeEventStartInstance &event : qAsConst(d->startInstanceList)) {
stream.writeStartElement(QStringLiteral("range"));
stream.writeAttribute(QStringLiteral("startTime"), QString::number(event.startTime));
if (event.duration >= 0)
diff --git a/tools/qmlprofiler/qmlprofilerdata.h b/tools/qmlprofiler/qmlprofilerdata.h
index 2570513d93..00ef037071 100644
--- a/tools/qmlprofiler/qmlprofilerdata.h
+++ b/tools/qmlprofiler/qmlprofilerdata.h
@@ -58,12 +58,6 @@ public:
bool isEmpty() const;
-signals:
- void error(QString);
- void stateChanged();
- void dataReady();
-
-public slots:
void clear();
void setTraceEndTime(qint64 time);
void setTraceStartTime(qint64 time);
@@ -83,6 +77,11 @@ public slots:
void complete();
bool save(const QString &filename);
+signals:
+ void error(QString);
+ void stateChanged();
+ void dataReady();
+
private:
void sortStartTimes();
void computeQmlTime();
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index 1185a8e7ae..9e1002166d 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -175,10 +175,10 @@ QFileInfoList findQmlFiles(const QString &dirName)
QFileInfoList ret;
if (dir.exists()) {
- QFileInfoList fileInfos = dir.entryInfoList(QStringList() << "*.qml",
- QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
+ const QFileInfoList fileInfos = dir.entryInfoList(QStringList() << "*.qml",
+ QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
- foreach (QFileInfo fileInfo, fileInfos) {
+ for (const QFileInfo &fileInfo : fileInfos) {
if (fileInfo.isDir())
ret += findQmlFiles(fileInfo.filePath());
else if (fileInfo.fileName().length() > 0 && fileInfo.fileName().at(0).isLower())
@@ -196,9 +196,9 @@ static int displayOptionsDialog(Options *options)
QFormLayout *layout = new QFormLayout(&dialog);
QComboBox *qmlFileComboBox = new QComboBox(&dialog);
- QFileInfoList fileInfos = findQmlFiles(":/bundle") + findQmlFiles("./qmlscene-resources");
+ const QFileInfoList fileInfos = findQmlFiles(":/bundle") + findQmlFiles("./qmlscene-resources");
- foreach (QFileInfo fileInfo, fileInfos)
+ for (const QFileInfo &fileInfo : fileInfos)
qmlFileComboBox->addItem(fileInfo.dir().dirName() + QLatin1Char('/') + fileInfo.fileName(), QVariant::fromValue(fileInfo));
QCheckBox *originalCheckBox = new QCheckBox(&dialog);
@@ -319,8 +319,8 @@ static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
QObject *dummyData = comp.create();
if(comp.isError()) {
- QList<QQmlError> errors = comp.errors();
- foreach (const QQmlError &error, errors)
+ const QList<QQmlError> errors = comp.errors();
+ for (const QQmlError &error : errors)
fprintf(stderr, "%s\n", qPrintable(error.toString()));
}
@@ -457,7 +457,7 @@ int main(int argc, char ** argv)
options.applicationAttributes.append(Qt::AA_DisableHighDpiScaling);
}
- foreach (Qt::ApplicationAttribute a, options.applicationAttributes)
+ for (Qt::ApplicationAttribute a : qAsConst(options.applicationAttributes))
QCoreApplication::setAttribute(a);
#ifdef QT_WIDGETS_LIB
QApplication app(argc, argv);
@@ -564,6 +564,7 @@ int main(int argc, char ** argv)
loadDummyDataFiles(engine, fi.path());
}
QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
+ QObject::connect(&engine, &QQmlEngine::exit, QCoreApplication::instance(), &QCoreApplication::exit);
component->loadUrl(options.url);
while (component->isLoading())
QCoreApplication::processEvents();
diff --git a/tools/qmlscene/qmlscene.pro b/tools/qmlscene/qmlscene.pro
index 0411fd8e31..b1267612c5 100644
--- a/tools/qmlscene/qmlscene.pro
+++ b/tools/qmlscene/qmlscene.pro
@@ -4,6 +4,7 @@ CONFIG += no_import_scan
SOURCES += main.cpp
-DEFINES += QML_RUNTIME_TESTING QT_QML_DEBUG_NO_WARNING
+DEFINES += QML_RUNTIME_TESTING
+!contains(QT_CONFIG, no-qml-debug): DEFINES += QT_QML_DEBUG_NO_WARNING
load(qt_tool)
diff --git a/tools/tools.pro b/tools/tools.pro
index 18bfe28a8a..5f72588a7e 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -23,7 +23,7 @@ qmlimportscanner.CONFIG = host_build
qtHaveModule(widgets): SUBDIRS += qmleasing
}
qtHaveModule(qmltest): SUBDIRS += qmltestrunner
- contains(QT_CONFIG, private_tests): SUBDIRS += qmljs
+ qtConfig(private_tests): SUBDIRS += qmljs
}
qml.depends = qmlimportscanner