aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/quick/canvas/quadraticCurveTo/quadraticCurveTo.qml2
-rw-r--r--examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc121
-rw-r--r--examples/quick/demos/clocks/clocks.pro14
-rw-r--r--examples/quick/demos/clocks/clocks.qml6
-rw-r--r--examples/quick/demos/clocks/clocks.qrc15
-rw-r--r--examples/quick/demos/clocks/doc/src/clocks.qdoc12
-rw-r--r--examples/quick/demos/clocks/main.cpp41
-rw-r--r--examples/quick/demos/demos.pro2
-rw-r--r--examples/quick/demos/maroon/content/SoundEffect.qml3
-rw-r--r--examples/quick/demos/maroon/doc/src/maroon.qdoc10
-rw-r--r--examples/quick/demos/maroon/maroon.pro1
-rw-r--r--examples/quick/demos/photosurface/doc/src/photosurface.qdoc10
-rw-r--r--examples/quick/demos/photoviewer/doc/src/photoviewer.qdoc12
-rw-r--r--examples/quick/demos/rssnews/doc/src/rssnews.qdoc12
-rw-r--r--examples/quick/demos/samegame/doc/src/samegame.qdoc12
-rw-r--r--examples/quick/demos/stocqt/doc/src/stocqt.qdoc10
-rw-r--r--examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc18
-rw-r--r--examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc4
-rw-r--r--examples/quick/quick-accessibility/doc/src/accessibility.qdoc4
-rw-r--r--examples/quick/quick.pro1
-rw-r--r--examples/quick/quickwidgets/quickwidget/doc/images/qtquickwidgets-example.pngbin0 -> 11340 bytes
-rw-r--r--examples/quick/quickwidgets/quickwidget/doc/src/quickwidget.qdoc34
-rw-r--r--examples/quick/quickwidgets/quickwidget/main.cpp (renamed from examples/quickwidgets/quickwidget/main.cpp)7
-rw-r--r--examples/quick/quickwidgets/quickwidget/qtquickwidgets-example.pngbin0 -> 11340 bytes
-rw-r--r--examples/quick/quickwidgets/quickwidget/quickwidget.pro (renamed from examples/quickwidgets/quickwidget/quickwidget.pro)0
-rw-r--r--examples/quick/quickwidgets/quickwidget/quickwidget.qrc (renamed from examples/quickwidgets/quickwidget/quickwidget.qrc)0
-rw-r--r--examples/quick/quickwidgets/quickwidget/rotatingsquare.qml (renamed from examples/quickwidgets/quickwidget/rotatingsquare.qml)0
-rw-r--r--examples/quick/quickwidgets/quickwidgets.pro (renamed from examples/quickwidgets/quickwidgets.pro)0
-rw-r--r--examples/quick/scenegraph/graph/linenode.cpp22
-rw-r--r--examples/quick/scenegraph/graph/noisynode.cpp15
-rw-r--r--examples/quick/scenegraph/graph/noisynode.h3
-rw-r--r--examples/quick/scenegraph/textureinthread/main.qml4
-rw-r--r--examples/quick/scenegraph/textureinthread/threadrenderer.cpp75
-rw-r--r--examples/quick/scenegraph/textureinthread/threadrenderer.h4
-rw-r--r--examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro12
-rw-r--r--src/3rdparty/double-conversion/double-conversion.pri24
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARMv7.h2
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp4
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h6
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp1
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp41
-rw-r--r--src/imports/testlib/TestCase.qml2
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel.cpp8
-rw-r--r--src/particles/qquickcustomaffector.cpp6
-rw-r--r--src/particles/qquickcustomparticle.cpp17
-rw-r--r--src/particles/qquickimageparticle.cpp68
-rw-r--r--src/particles/qquickitemparticle.cpp2
-rw-r--r--src/particles/qquickparticleaffector.cpp8
-rw-r--r--src/particles/qquickparticleemitter.cpp6
-rw-r--r--src/particles/qquicktrailemitter.cpp7
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp27
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h5
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp12
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob.cpp14
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob_p.h1
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp28
-rw-r--r--src/qml/animations/qparallelanimationgroupjob_p.h1
-rw-r--r--src/qml/animations/qpauseanimationjob.cpp5
-rw-r--r--src/qml/animations/qpauseanimationjob_p.h1
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp15
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob_p.h1
-rw-r--r--src/qml/compiler/compiler.pri24
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp (renamed from src/qml/compiler/qqmlcodegenerator.cpp)703
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h (renamed from src/qml/compiler/qqmlcodegenerator_p.h)158
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp488
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h88
-rw-r--r--src/qml/compiler/qv4codegen.cpp64
-rw-r--r--src/qml/compiler/qv4codegen_p.h19
-rw-r--r--src/qml/compiler/qv4compileddata.cpp22
-rw-r--r--src/qml/compiler/qv4compileddata_p.h45
-rw-r--r--src/qml/compiler/qv4compiler.cpp106
-rw-r--r--src/qml/compiler/qv4compiler_p.h36
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp31
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h2
-rw-r--r--src/qml/compiler/qv4isel_p.cpp43
-rw-r--r--src/qml/compiler/qv4isel_p.h8
-rw-r--r--src/qml/compiler/qv4isel_util_p.h6
-rw-r--r--src/qml/compiler/qv4jsir.cpp203
-rw-r--r--src/qml/compiler/qv4jsir_p.h302
-rw-r--r--src/qml/compiler/qv4ssa.cpp736
-rw-r--r--src/qml/compiler/qv4ssa_p.h18
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter.cpp3
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp1
-rw-r--r--src/qml/debugger/qqmlprofiler.cpp55
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h140
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc3
-rw-r--r--src/qml/doc/src/javascript/expressions.qdoc14
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc10
-rw-r--r--src/qml/doc/src/qmllanguageref/qmlreference.qdoc14
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/basics.qdoc10
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc2
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/signals.qdoc2
-rw-r--r--src/qml/jit/qv4assembler.cpp4
-rw-r--r--src/qml/jit/qv4assembler_p.h28
-rw-r--r--src/qml/jit/qv4binop.cpp69
-rw-r--r--src/qml/jit/qv4isel_masm.cpp53
-rw-r--r--src/qml/jit/qv4isel_masm_p.h4
-rw-r--r--src/qml/jit/qv4regalloc.cpp127
-rw-r--r--src/qml/jsapi/qjsengine.cpp1
-rw-r--r--src/qml/jsapi/qjsvalue.cpp6
-rw-r--r--src/qml/jsruntime/jsruntime.pri24
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp16
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp27
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h4
-rw-r--r--src/qml/jsruntime/qv4context.cpp8
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4engine.cpp34
-rw-r--r--src/qml/jsruntime/qv4engine_p.h7
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp15
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h2
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h9
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h11
-rw-r--r--src/qml/jsruntime/qv4include.cpp4
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp39
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h9
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp198
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h14
-rw-r--r--src/qml/jsruntime/qv4managed_p.h25
-rw-r--r--src/qml/jsruntime/qv4math_p.h15
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp86
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h82
-rw-r--r--src/qml/jsruntime/qv4mm.cpp307
-rw-r--r--src/qml/jsruntime/qv4mm_p.h7
-rw-r--r--src/qml/jsruntime/qv4object.cpp36
-rw-r--r--src/qml/jsruntime/qv4object_p.h13
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp35
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h6
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp122
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h54
-rw-r--r--src/qml/jsruntime/qv4script.cpp60
-rw-r--r--src/qml/jsruntime/qv4script_p.h6
-rw-r--r--src/qml/jsruntime/qv4string.cpp17
-rw-r--r--src/qml/jsruntime/qv4string_p.h11
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4value.cpp10
-rw-r--r--src/qml/jsruntime/qv4value_inl_p.h7
-rw-r--r--src/qml/jsruntime/qv4value_p.h29
-rw-r--r--src/qml/parser/qqmljsglobal_p.h4
-rw-r--r--src/qml/parser/qqmljsmemorypool_p.h24
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp1
-rw-r--r--src/qml/qml/qml.pri14
-rw-r--r--src/qml/qml/qqml.h6
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h1
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.cpp4
-rw-r--r--src/qml/qml/qqmlbinding.cpp45
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp26
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h4
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp2
-rw-r--r--src/qml/qml/qqmlcompiler_p.h14
-rw-r--r--src/qml/qml/qqmlcomponent.cpp17
-rw-r--r--src/qml/qml/qqmlcomponent.h1
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h1
-rw-r--r--src/qml/qml/qqmlcontext.h1
-rw-r--r--src/qml/qml/qqmlcontext_p.h2
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp6
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp9
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h11
-rw-r--r--src/qml/qml/qqmldirparser.cpp38
-rw-r--r--src/qml/qml/qqmldirparser_p.h17
-rw-r--r--src/qml/qml/qqmlengine.cpp15
-rw-r--r--src/qml/qml/qqmlengine_p.h1
-rw-r--r--src/qml/qml/qqmlexpression.cpp36
-rw-r--r--src/qml/qml/qqmlexpression.h1
-rw-r--r--src/qml/qml/qqmlexpression_p.h2
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp10
-rw-r--r--src/qml/qml/qqmlfile.cpp11
-rw-r--r--src/qml/qml/qqmlfileselector.cpp6
-rw-r--r--src/qml/qml/qqmlimport.cpp36
-rw-r--r--src/qml/qml/qqmlimport_p.h3
-rw-r--r--src/qml/qml/qqmlincubator.cpp32
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp1
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp12
-rw-r--r--src/qml/qml/qqmllocale.cpp7
-rw-r--r--src/qml/qml/qqmlmetatype.cpp38
-rw-r--r--src/qml/qml/qqmlmetatype_p.h9
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp68
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h2
-rw-r--r--src/qml/qml/qqmlparserstatus.h1
-rw-r--r--src/qml/qml/qqmlplatform.cpp22
-rw-r--r--src/qml/qml/qqmlprivate.h31
-rw-r--r--src/qml/qml/qqmlproperty.cpp6
-rw-r--r--src/qml/qml/qqmlscript.cpp417
-rw-r--r--src/qml/qml/qqmlscript_p.h180
-rw-r--r--src/qml/qml/qqmlscriptstring.h1
-rw-r--r--src/qml/qml/qqmltypeloader.cpp466
-rw-r--r--src/qml/qml/qqmltypeloader_p.h68
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp14
-rw-r--r--src/qml/qml/v8/qv8engine.cpp6
-rw-r--r--src/qml/qtqmlglobal_p.h6
-rw-r--r--src/qml/types/qqmlbind.cpp4
-rw-r--r--src/qml/types/qqmlconnections.cpp29
-rw-r--r--src/qml/types/qqmlconnections_p.h4
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp4
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--src/qml/types/qqmllistmodel.cpp58
-rw-r--r--src/qml/types/qqmllistmodel_p.h6
-rw-r--r--src/qml/types/qquickworkerscript.cpp16
-rw-r--r--src/qmldevtools/qmldevtools.pro6
-rw-r--r--src/qmltest/quicktest.cpp40
-rw-r--r--src/quick/designer/designersupport.cpp5
-rw-r--r--src/quick/doc/images/visualize-batches.pngbin0 -> 666 bytes
-rw-r--r--src/quick/doc/images/visualize-clip.pngbin0 -> 9201 bytes
-rw-r--r--src/quick/doc/images/visualize-original.pngbin0 -> 4151 bytes
-rw-r--r--src/quick/doc/images/visualize-overdraw-1.pngbin0 -> 6872 bytes
-rw-r--r--src/quick/doc/images/visualize-overdraw-2.pngbin0 -> 5386 bytes
-rw-r--r--src/quick/doc/qtquick.qdocconf1
-rw-r--r--src/quick/doc/snippets/qml/xmlrole.qml9
-rw-r--r--src/quick/doc/snippets/qml/xmlrole.xml20
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc117
-rw-r--r--src/quick/doc/src/dynamicview-tutorial.qdoc4
-rw-r--r--src/quick/doc/src/examples.qdoc18
-rw-r--r--src/quick/doc/src/tutorial.qdoc4
-rw-r--r--src/quick/doc/src/whatsnew.qdoc9
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp46
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp15
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h5
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp2
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp58
-rw-r--r--src/quick/items/qquickdrag.cpp16
-rw-r--r--src/quick/items/qquickdroparea.cpp24
-rw-r--r--src/quick/items/qquickflickable.cpp46
-rw-r--r--src/quick/items/qquickframebufferobject.cpp4
-rw-r--r--src/quick/items/qquickgridview.cpp29
-rw-r--r--src/quick/items/qquickimage.cpp14
-rw-r--r--src/quick/items/qquickimagebase.cpp73
-rw-r--r--src/quick/items/qquickimagebase_p.h4
-rw-r--r--src/quick/items/qquickimagebase_p_p.h2
-rw-r--r--src/quick/items/qquickitem.cpp276
-rw-r--r--src/quick/items/qquickitemsmodule.cpp8
-rw-r--r--src/quick/items/qquickitemview.cpp12
-rw-r--r--src/quick/items/qquicklistview.cpp50
-rw-r--r--src/quick/items/qquickloader.cpp9
-rw-r--r--src/quick/items/qquickmousearea.cpp122
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp48
-rw-r--r--src/quick/items/qquickpathview.cpp44
-rw-r--r--src/quick/items/qquickpincharea.cpp155
-rw-r--r--src/quick/items/qquickrendercontrol.cpp32
-rw-r--r--src/quick/items/qquickrendercontrol_p.h2
-rw-r--r--src/quick/items/qquickrepeater.cpp14
-rw-r--r--src/quick/items/qquickscreen.cpp8
-rw-r--r--src/quick/items/qquicktext.cpp20
-rw-r--r--src/quick/items/qquicktextcontrol.cpp46
-rw-r--r--src/quick/items/qquicktextcontrol_p.h1
-rw-r--r--src/quick/items/qquicktextedit.cpp20
-rw-r--r--src/quick/items/qquicktextedit_p.h3
-rw-r--r--src/quick/items/qquicktextinput.cpp22
-rw-r--r--src/quick/items/qquicktextinput_p.h4
-rw-r--r--src/quick/items/qquickview.cpp10
-rw-r--r--src/quick/items/qquickview_p.h4
-rw-r--r--src/quick/items/qquickwindow.cpp63
-rw-r--r--src/quick/items/qquickwindowmodule.cpp31
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp17
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp3
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp11
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp19
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h2
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp41
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h3
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp6
-rw-r--r--src/quick/scenegraph/qsgdefaultimagenode.cpp19
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode.cpp20
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp48
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h12
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp20
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h1
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp8
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp21
-rw-r--r--src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp13
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.cpp6
-rw-r--r--src/quick/scenegraph/util/qsgsimpletexturenode.cpp2
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp18
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp29
-rw-r--r--src/quick/util/qquickanimation.cpp74
-rw-r--r--src/quick/util/qquickanimation_p_p.h14
-rw-r--r--src/quick/util/qquickglobal.cpp52
-rw-r--r--src/quick/util/qquickpath.cpp4
-rw-r--r--src/quick/util/qquickprofiler.cpp13
-rw-r--r--src/quick/util/qquickprofiler_p.h21
-rw-r--r--src/quick/util/qquickpropertychanges.cpp64
-rw-r--r--src/quick/util/qquickpropertychanges_p.h4
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp7
-rw-r--r--src/quick/util/qquicksmoothedanimation_p_p.h1
-rw-r--r--src/quick/util/qquickspringanimation.cpp10
-rw-r--r--src/quick/util/qquickstyledtext.cpp2
-rw-r--r--src/quick/util/qquicktimeline.cpp5
-rw-r--r--src/quick/util/qquicktimeline_p_p.h1
-rw-r--r--src/quickwidgets/qquickwidget.cpp131
-rw-r--r--src/quickwidgets/qquickwidget.h3
-rw-r--r--src/quickwidgets/qquickwidget_p.h3
-rw-r--r--src/src.pro2
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp69
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp132
-rw-r--r--tests/auto/qml/qml.pro2
-rw-r--r--tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/SubObject.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/Types.js3
-rw-r--r--tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importedScriptsAccessOnObjectWithInvalidContext.qml42
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp26
-rw-r--r--tests/auto/qml/qqmlincubator/data/objectDeleted.qml6
-rw-r--r--tests/auto/qml/qqmlincubator/testtypes.cpp20
-rw-r--r--tests/auto/qml/qqmlincubator/testtypes.h21
-rw-r--r--tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp63
-rw-r--r--tests/auto/qml/qqmllanguage/data/SubType.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/data/assignNullStrings.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/customParserProperties.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/idProperty.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/rootObjectInCreationNotForSubObjects.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/scriptString7.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/{subdir}/Test.qml2
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp43
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h75
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp135
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp58
-rw-r--r--tests/auto/qml/qqmllocale/tst_qqmllocale.cpp3
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml2
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro2
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test1.html1
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test2.html1
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp47
-rw-r--r--tests/auto/qml/qv4debugger/tst_qv4debugger.cpp10
-rw-r--r--tests/auto/qmldevtools/compile/tst_compile.cpp4
-rw-r--r--tests/auto/qmltest/animators/tst_mixed.qml179
-rw-r--r--tests/auto/qmltest/animators/tst_on.qml4
-rw-r--r--tests/auto/qmltest/listview/tst_listview.qml23
-rw-r--r--tests/auto/qmltest/pathview/tst_pathview.qml35
-rw-r--r--tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp2
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml1
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml32
-rw-r--r--tests/auto/quick/qquickgridview/data/boundZValues.qml46
-rw-r--r--tests/auto/quick/qquickgridview/data/constantZValues.qml46
-rw-r--r--tests/auto/quick/qquickgridview/data/defaultZValues.qml (renamed from tests/auto/quick/qquickgridview/data/initialZValues.qml)10
-rw-r--r--tests/auto/quick/qquickgridview/tst_qquickgridview.cpp22
-rw-r--r--tests/auto/quick/qquickimage/data/heart-highdpi@2x.pngbin0 -> 12577 bytes
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp50
-rw-r--r--tests/auto/quick/qquickitem/data/visualParentOwnershipWindow.qml15
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp63
-rw-r--r--tests/auto/quick/qquickitem2/data/activeFocusOnTab9.qml50
-rw-r--r--tests/auto/quick/qquickitem2/data/keysforward.qml84
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp209
-rw-r--r--tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp6
-rw-r--r--tests/auto/quick/qquicklistview/data/boundZValues.qml55
-rw-r--r--tests/auto/quick/qquicklistview/data/constantZValues.qml55
-rw-r--r--tests/auto/quick/qquicklistview/data/defaultZValues.qml49
-rw-r--r--tests/auto/quick/qquicklistview/data/initialZValues.qml35
-rw-r--r--tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml10
-rw-r--r--tests/auto/quick/qquicklistview/data/roundingErrors.qml130
-rw-r--r--tests/auto/quick/qquicklistview/qquicklistview.pro1
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp104
-rw-r--r--tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp22
-rw-r--r--tests/auto/quick/qquickstates/data/QTBUG-38492.qml16
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp16
-rw-r--r--tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp40
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp2
-rw-r--r--tests/auto/quick/qquicktextinput/qquicktextinput.pro2
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp3
-rw-r--r--tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp6
-rw-r--r--tests/auto/quick/qquickwindow/data/active.qml2
-rw-r--r--tests/auto/quick/qquickwindow/data/windoworder.qml42
-rw-r--r--tests/auto/quick/qquickwindow/qquickwindow.pro3
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp93
-rw-r--r--tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml9
-rw-r--r--tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp24
-rw-r--r--tests/auto/quick/scenegraph/data/render_bug37422.qml103
-rw-r--r--tests/auto/quick/scenegraph/tst_scenegraph.cpp3
-rw-r--r--tests/manual/highdpi/fillmodes.qml72
-rw-r--r--tests/manual/highdpi/heart-highdpi@2x.pngbin0 -> 20654 bytes
-rw-r--r--tests/manual/highdpi/heart-lowdpi.pngbin0 -> 15194 bytes
-rw-r--r--tests/manual/highdpi/heart.pngbin0 -> 15194 bytes
-rw-r--r--tests/manual/highdpi/heart@2x.pngbin0 -> 20654 bytes
-rw-r--r--tests/manual/highdpi/image.qml52
-rw-r--r--tests/manual/highdpi/image2.qml64
-rw-r--r--tests/manual/highdpi/imagesize.qml76
-rw-r--r--tests/manual/highdpi/mirror.qml57
-rw-r--r--tests/manual/highdpi/sourcesize.qml76
-rw-r--r--tests/testapplications/text/text.qml6
-rw-r--r--tests/testapplications/text/textedit.qml6
-rw-r--r--tests/testapplications/text/textinput.qml4
-rw-r--r--tools/qml/main.cpp14
-rw-r--r--tools/qmlbundle/main.cpp3
-rw-r--r--tools/qmlimportscanner/main.cpp58
-rw-r--r--tools/qmlplugindump/main.cpp130
-rw-r--r--tools/qmlplugindump/qmlplugindump.pro4
-rw-r--r--tools/qmlprofiler/qmlprofilerapplication.cpp2
-rw-r--r--tools/qmlprofiler/qmlprofilerclient.cpp5
-rw-r--r--tools/qmlprofiler/qmlprofilerclient.h2
-rw-r--r--tools/qmlprofiler/qmlprofilerdata.cpp35
-rw-r--r--tools/qmlprofiler/qmlprofilerdata.h2
-rw-r--r--tools/qmlscene/main.cpp21
-rw-r--r--tools/qmlscene/qmlscene.pro2
403 files changed, 8918 insertions, 4333 deletions
diff --git a/examples/quick/canvas/quadraticCurveTo/quadraticCurveTo.qml b/examples/quick/canvas/quadraticCurveTo/quadraticCurveTo.qml
index 69e703cca7..b9214b020b 100644
--- a/examples/quick/canvas/quadraticCurveTo/quadraticCurveTo.qml
+++ b/examples/quick/canvas/quadraticCurveTo/quadraticCurveTo.qml
@@ -118,7 +118,7 @@ Item {
// ![1]
ctx.fillStyle = "white";
- ctx.font = "Bold 17px";
+ ctx.font = "bold 17px sans-serif";
ctx.fillText("Qt Quick", 40, 70);
// ![1]
ctx.restore();
diff --git a/examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc b/examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc
index 7217c7d806..e72d048567 100644
--- a/examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc
+++ b/examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -29,9 +29,122 @@
\title Qt Quick Demo - Calqlatr
\ingroup qtquickdemos
\example demos/calqlatr
- \brief A simple calculator app, designed for portrait devices.
+ \brief A QML app designed for portrait devices that uses custom components,
+ animated with AnimationController, and JavaScript for the application logic.
\image qtquick-demo-calqlatr.png
- This app has the logic implemented in Javascipt and the appearance implemented in QML.
-*/
+ \e{Calqlatr} demonstrates various QML and \l{Qt Quick} features, such as
+ displaying custom components and using animation to move the components
+ around in the application view. The application logic is implemented in
+ JavaScript and the appearance is implemented in QML.
+
+ \include examples-run.qdocinc
+
+ \section1 Displaying Custom Components
+
+ In the Calqlatr application, we use the following custom types that are
+ each defined in a separate .qml file:
+
+ \list
+ \li Button.qml
+ \li Display.qml
+ \li NumberPad.qml
+ \li StyleLabel.qml
+ \endlist
+
+ To use the custom types, we add an import statement to the main QML file,
+ calqlatr.qml that imports the folder called \c content where the types are
+ located:
+
+ \code
+ import "content"
+ \endcode
+
+ We can then display custom components by adding the component types to
+ any QML file. For example, we use the NumberPad type in calqlatr.qml to
+ create the number pad of the calculator. We place the type inside an
+ \l{Item} QML type, which is the base type for all visual items in Qt Quick:
+
+ \quotefromfile demos/calqlatr/calqlatr.qml
+ \skipto Item
+ \printuntil }
+ \printuntil }
+
+ Further, we use the Button type in the NumberPad type to create the
+ calculator buttons. Button.qml specifies the basic properties for a
+ button that we can modify for each button instance in NumberPad.qml. For the
+ digit and separator buttons, we additionally specify the text property using
+ the property alias \c text that we define in Button.qml.
+
+ For the operator buttons, we also specify another color (green) using the
+ property alias \c color and set the operator property to \c true. We use
+ the operator property in functions that perform the calculations.
+
+ We place the buttons inside a \l{Grid} QML type to position them in a grid:
+
+ \quotefromfile demos/calqlatr/content/NumberPad.qml
+ \skipto Grid
+ \printuntil /^\}/
+
+ \section1 Animating Components
+
+ We use the Display type to display calculations. In Display.qml, we use
+ images to make the display component look like a slip of paper that contains
+ a grip. Users can drag the grip to move the display from left to right.
+ When users release the grip, the AnimationController QML type that we define
+ in the calqlatr.qml file finishes running the controlled animation in either
+ a forwards or a backwards direction. To run the animation, we call either
+ completeToEnd() or completeToBeginning(), depending on the direction. We do
+ this in the MouseArea's \c onReleased signal handler, where \c controller
+ is the id of our AnimationController:
+
+ \quotefromfile demos/calqlatr/calqlatr.qml
+ \skipto onPressed
+ \printuntil }
+
+ Unlike other QML animation types, AnimationController is not driven by
+ internal timers but by explicitly setting its progress property to a
+ value between \c 0.0 and \c 1.0.
+
+ Inside the AnimationController, we run two NumberAnimation instances in
+ parallel to move the number pad and the display components simultaneously to
+ the opposite sides of the view. In addition, we run a SequentialAnimation
+ instance to scale the number pad during the transition, giving the animation
+ some depth.
+
+ \quotefromfile demos/calqlatr/calqlatr.qml
+ \skipto AnimationController
+ \printuntil 1; easing.type
+ \printuntil }
+ \printuntil }
+ \printuntil }
+
+ We use the easing curve of the type \c Easing.InOutQuad to accelerate the
+ motion until halfway and then decelerate it.
+
+ \section1 Performing Calculations
+
+ The calculator.js file contains definitions for the functions to execute
+ when users press the digit and operator buttons. To use the functions, we
+ import calculator.js in the calqlatr.qml file as \c CalcEngine:
+
+ \code
+ import "content/calculator.js" as CalcEngine
+ \endcode
+
+ We can then declare the functions to execute depending on whether the
+ operator property for a button is set to \c true in NumberPad.qml:
+
+ \quotefromfile demos/calqlatr/calqlatr.qml
+ \skipto operatorPressed
+ \printuntil digitPressed
+
+ When users press a digit or operator, the text from the digit appears on the
+ display. When they press the equals operator (=), the appropriate
+ calculation is performed, and the results appear on the display.
+
+ \section1 List of Files
+
+ \sa {QML Applications}
+*/
diff --git a/examples/quick/demos/clocks/clocks.pro b/examples/quick/demos/clocks/clocks.pro
new file mode 100644
index 0000000000..21d3f7f971
--- /dev/null
+++ b/examples/quick/demos/clocks/clocks.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+
+QT += qml quick
+
+SOURCES += main.cpp
+RESOURCES += clocks.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/demos/clocks
+INSTALLS += target
+
+OTHER_FILES += \
+ clocks.qml \
+ content/Clock.qml \
+ content/*.png
diff --git a/examples/quick/demos/clocks/clocks.qml b/examples/quick/demos/clocks/clocks.qml
index ddf9e42ea2..d16e3c5442 100644
--- a/examples/quick/demos/clocks/clocks.qml
+++ b/examples/quick/demos/clocks/clocks.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the examples of the Qt Toolkit.
@@ -39,7 +39,7 @@
****************************************************************************/
import QtQuick 2.0
-import "content"
+import "content" as Content
Rectangle {
id: root
@@ -54,7 +54,7 @@ Rectangle {
snapMode: ListView.SnapOneItem
highlightRangeMode: ListView.ApplyRange
- delegate: Clock { city: cityName; shift: timeShift }
+ delegate: Content.Clock { city: cityName; shift: timeShift }
model: ListModel {
ListElement { cityName: "New York"; timeShift: -4 }
ListElement { cityName: "London"; timeShift: 0 }
diff --git a/examples/quick/demos/clocks/clocks.qrc b/examples/quick/demos/clocks/clocks.qrc
new file mode 100644
index 0000000000..eaff4729ae
--- /dev/null
+++ b/examples/quick/demos/clocks/clocks.qrc
@@ -0,0 +1,15 @@
+<RCC>
+ <qresource prefix="/demos/clocks">
+ <file>clocks.qml</file>
+ <file>content/arrow.png</file>
+ <file>content/background.png</file>
+ <file>content/center.png</file>
+ <file>content/clock-night.png</file>
+ <file>content/clock.png</file>
+ <file>content/Clock.qml</file>
+ <file>content/hour.png</file>
+ <file>content/minute.png</file>
+ <file>content/quit.png</file>
+ <file>content/second.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/demos/clocks/doc/src/clocks.qdoc b/examples/quick/demos/clocks/doc/src/clocks.qdoc
index b34f844cc6..b57894c5d3 100644
--- a/examples/quick/demos/clocks/doc/src/clocks.qdoc
+++ b/examples/quick/demos/clocks/doc/src/clocks.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -29,7 +29,13 @@
\title Qt Quick Demo - Clocks
\ingroup qtquickdemos
\example demos/clocks
- \brief An app that shows the current time in different cities.
+ \brief A QML application that shows the current time in different cities.
\image qtquick-demo-clocks-small.png
-*/
+ \e Clocks demonstrates various QML and \l{Qt Quick} features such as
+ displaying custom components.
+
+ \include examples-run.qdocinc
+
+ \sa {QML Applications}
+*/
diff --git a/examples/quick/demos/clocks/main.cpp b/examples/quick/demos/clocks/main.cpp
new file mode 100644
index 0000000000..f6b7f87d38
--- /dev/null
+++ b/examples/quick/demos/clocks/main.cpp
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "../../shared/shared.h"
+DECLARATIVE_EXAMPLE_MAIN(demos/clocks/clocks)
diff --git a/examples/quick/demos/demos.pro b/examples/quick/demos/demos.pro
index 867dfa5a07..ac15cc3c1f 100644
--- a/examples/quick/demos/demos.pro
+++ b/examples/quick/demos/demos.pro
@@ -1,12 +1,12 @@
TEMPLATE = subdirs
SUBDIRS = samegame \
calqlatr \
+ clocks \
tweetsearch \
maroon \
photosurface \
stocqt
EXAMPLE_FILES = \
- clocks \
photoviewer \
rssnews
diff --git a/examples/quick/demos/maroon/content/SoundEffect.qml b/examples/quick/demos/maroon/content/SoundEffect.qml
index 05e8e94ab5..ef5e3febac 100644
--- a/examples/quick/demos/maroon/content/SoundEffect.qml
+++ b/examples/quick/demos/maroon/content/SoundEffect.qml
@@ -42,12 +42,11 @@ import QtQuick 2.0
//Proxies a SoundEffect if QtMultimedia is installed
Item {
id: container
- property QtObject effect: Qt.createQmlObject("import QtMultimedia 5.0; SoundEffect{ source: '" + container.source + "' }", container);
+ property QtObject effect: Qt.createQmlObject("import QtMultimedia 5.0; SoundEffect{ source: '" + container.source + "'; muted: !Qt.application.active }", container);
property url source: ""
onSourceChanged: if (effect != null) effect.source = source;
function play() {
if (effect != null)
effect.play();
}
-
}
diff --git a/examples/quick/demos/maroon/doc/src/maroon.qdoc b/examples/quick/demos/maroon/doc/src/maroon.qdoc
index c18b6bc874..59f6397dcf 100644
--- a/examples/quick/demos/maroon/doc/src/maroon.qdoc
+++ b/examples/quick/demos/maroon/doc/src/maroon.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -32,5 +32,11 @@
\brief A cute game designed for touchscreens.
\image qtquick-demo-maroon-med-1.png
\image qtquick-demo-maroon-med-2.png
-*/
+ \e{Maroon in Trouble} demonstrates various QML and \l{Qt Quick} features
+ such as displaying custom components and playing sound effects.
+
+ \include examples-run.qdocinc
+
+ \sa {QML Applications}
+*/
diff --git a/examples/quick/demos/maroon/maroon.pro b/examples/quick/demos/maroon/maroon.pro
index 6ca0a2bf16..ada16d047a 100644
--- a/examples/quick/demos/maroon/maroon.pro
+++ b/examples/quick/demos/maroon/maroon.pro
@@ -1,6 +1,7 @@
TEMPLATE = app
QT += qml quick
+qtHaveModule(multimedia): QT += multimedia
SOURCES += main.cpp
RESOURCES += maroon.qrc
diff --git a/examples/quick/demos/photosurface/doc/src/photosurface.qdoc b/examples/quick/demos/photosurface/doc/src/photosurface.qdoc
index 48f8e8a14b..d56b34365d 100644
--- a/examples/quick/demos/photosurface/doc/src/photosurface.qdoc
+++ b/examples/quick/demos/photosurface/doc/src/photosurface.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -32,6 +32,10 @@
\brief A touch-based app for shuffling photos around a virtual surface.
\image qtquick-demo-photosurface-small.png
- This example demonstrates how to handle dragging, rotation and
- pinch zooming within the same item using a PinchArea containing a MouseArea.
+ \e{Photo Surface} demonstrates how to handle dragging, rotation and pinch
+ zooming within the same item using a \l PinchArea containing a \l MouseArea.
+
+ \include examples-run.qdocinc
+
+ \sa {QML Applications}
*/
diff --git a/examples/quick/demos/photoviewer/doc/src/photoviewer.qdoc b/examples/quick/demos/photoviewer/doc/src/photoviewer.qdoc
index b0f1368a1c..29c432be3c 100644
--- a/examples/quick/demos/photoviewer/doc/src/photoviewer.qdoc
+++ b/examples/quick/demos/photoviewer/doc/src/photoviewer.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -29,7 +29,13 @@
\title Qt Quick Demo - Photo Viewer
\ingroup qtquickdemos
\example demos/photoviewer
- \brief An online photo viewer that displays Flickr feeds.
+ \brief A photo viewer that displays Flickr feeds.
\image qtquick-demo-photoviewer-small.png
-*/
+ \e{Photo Viewer} demonstrates various QML and \l{Qt Quick} features such as
+ displaying custom components.
+
+ \include examples-run.qdocinc
+
+ \sa {QML Applications}
+*/
diff --git a/examples/quick/demos/rssnews/doc/src/rssnews.qdoc b/examples/quick/demos/rssnews/doc/src/rssnews.qdoc
index 019b54d609..12c7c0d19b 100644
--- a/examples/quick/demos/rssnews/doc/src/rssnews.qdoc
+++ b/examples/quick/demos/rssnews/doc/src/rssnews.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -29,7 +29,13 @@
\title Qt Quick Demo - RSS News
\ingroup qtquickdemos
\example demos/rssnews
- \brief An RSS news reader.
+ \brief A QML RSS news reader.
\image qtquick-demo-rssnews-small.png
-*/
+ \e{RSS News} demonstrates various QML and \l{Qt Quick} features such as
+ loading XML data and displaying custom components.
+
+ \include examples-run.qdocinc
+
+ \sa {QML Applications}
+*/
diff --git a/examples/quick/demos/samegame/doc/src/samegame.qdoc b/examples/quick/demos/samegame/doc/src/samegame.qdoc
index 70042d73f0..acae8d728f 100644
--- a/examples/quick/demos/samegame/doc/src/samegame.qdoc
+++ b/examples/quick/demos/samegame/doc/src/samegame.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -30,7 +30,15 @@
\ingroup qtquickdemos
\example demos/samegame
\brief A QML implementation of the popular puzzle game by Kuniaki Moribe.
+
+ \e{Same Game} demonstrates a QML game with custom types and logic written in
+ JavaScript. The game uses various \l{Qt Quick} features such as
+ particles, animation, and loading images.
+
\image qtquick-demo-samegame-med-1.png
\image qtquick-demo-samegame-med-2.png
-*/
+ \include examples-run.qdocinc
+
+ \sa {QML Applications}
+*/
diff --git a/examples/quick/demos/stocqt/doc/src/stocqt.qdoc b/examples/quick/demos/stocqt/doc/src/stocqt.qdoc
index 7001bfb395..5f090e84f9 100644
--- a/examples/quick/demos/stocqt/doc/src/stocqt.qdoc
+++ b/examples/quick/demos/stocqt/doc/src/stocqt.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -31,5 +31,11 @@
\example demos/stocqt
\brief A configurable stock chart for the NASDAQ-100.
\image qtquick-demo-stocqt.png
-*/
+ \e{StocQt} demonstrates various QML and \l{Qt Quick} features such as
+ displaying custom components and downloading data from the internet.
+
+ \include examples-run.qdocinc
+
+ \sa {QML Applications}
+*/
diff --git a/examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc b/examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc
index a56ed0d7e9..41c6c09dea 100644
--- a/examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc
+++ b/examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -33,22 +33,20 @@
\image qtquick-demo-tweetsearch-med-1.png
\image qtquick-demo-tweetsearch-med-2.png
- \section1 Demo Introduction
-
- The Tweet Search demo searches items posted to Twitter service
- using a number of query parameters. Search can be done for tweets
- from a specified user, a hashtag or a search phrase.
+ \e{Tweet Search} is a QML application that searches items posted to Twitter
+ service using a number of query parameters. Search can be done for tweets
+ from a specified user, a hashtag, or a search phrase.
The search result is a list of items showing the contents of the
tweet as well as the name and image of the user who posted it.
Hashtags, names and links in the content are clickable. Clicking
on the image will flip the item to reveal more information.
- \section1 Running the Demo
+ \include examples-run.qdocinc
Tweet Search uses Twitter API v1.1 for running seaches.
- \section2 Authentication
+ \section1 Request Authentication
Each request must be authenticated on behalf of the application.
For demonstration purposes, the application uses a hard-coded
@@ -67,7 +65,7 @@
Rebuild and run the demo.
- \section2 JSON Parsing
+ \section1 JSON Parsing
Search results are returned in JSON (JavaScript Object Notation)
format. \c TweetsModel uses an \l XMLHTTPRequest object to send
@@ -76,4 +74,6 @@
representing a tweet is then added to a \l ListModel:
\snippet demos/tweetsearch/content/TweetsModel.qml requesting
+
+ \sa {QML Applications}
*/
diff --git a/examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc b/examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc
index a8ba96a10a..cdf4cadf82 100644
--- a/examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc
+++ b/examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc
@@ -78,9 +78,9 @@
\snippet customitems/painteditem/textballoon.cpp 1
We start with setting the pen and brush on the item to define the look of
- the item. After that we start drawing. Note that the \l {QQuickPaintedItem::}{boundingRect()}
+ the item. After that we start drawing. Note that the \l {QQuickPaintedItem::}{contentsBoundingRect()}
item is called to draw depending on the size of the item. The rectangle
- returned by the \l {QQuickPaintedItem::}{boundingRect()} function is the size
+ returned by the \l {QQuickPaintedItem::}{contentsBoundingRect()} function is the size
of the item as defined in the QML file.
\section1 textballoons.qml file
diff --git a/examples/quick/quick-accessibility/doc/src/accessibility.qdoc b/examples/quick/quick-accessibility/doc/src/accessibility.qdoc
index 2a2af1f159..5ad60d1c0f 100644
--- a/examples/quick/quick-accessibility/doc/src/accessibility.qdoc
+++ b/examples/quick/quick-accessibility/doc/src/accessibility.qdoc
@@ -33,8 +33,8 @@
Types in this example are augmented with meta-data for accessiblity systems.
For example, the button identifies itself and its functionality to the accessibility system:
- \snippet accessibility/content/Button.qml button
+ \snippet quick-accessibility/content/Button.qml button
As do Text types inside the example:
- \snippet accessibility/accessibility.qml text
+ \snippet quick-accessibility/accessibility.qml text
*/
diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro
index 1f96111b04..421f95a162 100644
--- a/examples/quick/quick.pro
+++ b/examples/quick/quick.pro
@@ -27,6 +27,7 @@ SUBDIRS = quick-accessibility \
# Widget dependent examples
qtHaveModule(widgets) {
SUBDIRS += embeddedinwidgets
+ qtHaveModule(quickwidgets): SUBDIRS += quickwidgets
}
EXAMPLE_FILES = \
diff --git a/examples/quick/quickwidgets/quickwidget/doc/images/qtquickwidgets-example.png b/examples/quick/quickwidgets/quickwidget/doc/images/qtquickwidgets-example.png
new file mode 100644
index 0000000000..cc4f52082f
--- /dev/null
+++ b/examples/quick/quickwidgets/quickwidget/doc/images/qtquickwidgets-example.png
Binary files differ
diff --git a/examples/quick/quickwidgets/quickwidget/doc/src/quickwidget.qdoc b/examples/quick/quickwidgets/quickwidget/doc/src/quickwidget.qdoc
new file mode 100644
index 0000000000..8a89371039
--- /dev/null
+++ b/examples/quick/quickwidgets/quickwidget/doc/src/quickwidget.qdoc
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \title Qt Quick Widgets Example
+ \example quickwidgets/quickwidget
+ \brief Demonstrates how to mix QML with a Qt Widgets application using the QQuickWidget class.
+ \image qtquickwidgets-example.png
+*/
+
diff --git a/examples/quickwidgets/quickwidget/main.cpp b/examples/quick/quickwidgets/quickwidget/main.cpp
index c1304347ec..61c54735cf 100644
--- a/examples/quickwidgets/quickwidget/main.cpp
+++ b/examples/quick/quickwidgets/quickwidget/main.cpp
@@ -58,6 +58,13 @@ private:
MainWindow::MainWindow()
: m_quickWidget(new QQuickWidget)
{
+ if (QCoreApplication::arguments().contains(QStringLiteral("--coreprofile"))) {
+ QSurfaceFormat format;
+ format.setVersion(4, 4);
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ m_quickWidget->setFormat(format);
+ }
+
QMdiArea *centralWidget = new QMdiArea;
QLCDNumber *lcd = new QLCDNumber;
diff --git a/examples/quick/quickwidgets/quickwidget/qtquickwidgets-example.png b/examples/quick/quickwidgets/quickwidget/qtquickwidgets-example.png
new file mode 100644
index 0000000000..cc4f52082f
--- /dev/null
+++ b/examples/quick/quickwidgets/quickwidget/qtquickwidgets-example.png
Binary files differ
diff --git a/examples/quickwidgets/quickwidget/quickwidget.pro b/examples/quick/quickwidgets/quickwidget/quickwidget.pro
index 1aca22082e..1aca22082e 100644
--- a/examples/quickwidgets/quickwidget/quickwidget.pro
+++ b/examples/quick/quickwidgets/quickwidget/quickwidget.pro
diff --git a/examples/quickwidgets/quickwidget/quickwidget.qrc b/examples/quick/quickwidgets/quickwidget/quickwidget.qrc
index c073b7b80d..c073b7b80d 100644
--- a/examples/quickwidgets/quickwidget/quickwidget.qrc
+++ b/examples/quick/quickwidgets/quickwidget/quickwidget.qrc
diff --git a/examples/quickwidgets/quickwidget/rotatingsquare.qml b/examples/quick/quickwidgets/quickwidget/rotatingsquare.qml
index a5becfba38..a5becfba38 100644
--- a/examples/quickwidgets/quickwidget/rotatingsquare.qml
+++ b/examples/quick/quickwidgets/quickwidget/rotatingsquare.qml
diff --git a/examples/quickwidgets/quickwidgets.pro b/examples/quick/quickwidgets/quickwidgets.pro
index 07192b6696..07192b6696 100644
--- a/examples/quickwidgets/quickwidgets.pro
+++ b/examples/quick/quickwidgets/quickwidgets.pro
diff --git a/examples/quick/scenegraph/graph/linenode.cpp b/examples/quick/scenegraph/graph/linenode.cpp
index 015aa4f0ee..0c63129ea8 100644
--- a/examples/quick/scenegraph/graph/linenode.cpp
+++ b/examples/quick/scenegraph/graph/linenode.cpp
@@ -40,8 +40,6 @@
#include "linenode.h"
-#include <QtCore/QResource>
-
#include <QtGui/QColor>
#include <QtQuick/QSGSimpleMaterial>
@@ -58,14 +56,10 @@ class LineShader : public QSGSimpleMaterialShader<LineMaterial>
QSG_DECLARE_SIMPLE_SHADER(LineShader, LineMaterial)
public:
- LineShader()
- : vsh(readResource(":/scenegraph/graph/shaders/line.vsh")),
- fsh(readResource(":/scenegraph/graph/shaders/line.fsh"))
- {}
-
- const char *vertexShader() const { return vsh.constData(); }
-
- const char *fragmentShader() const { return fsh.constData(); }
+ LineShader() {
+ setShaderSourceFile(QOpenGLShader::Vertex, ":/scenegraph/graph/shaders/line.vsh");
+ setShaderSourceFile(QOpenGLShader::Fragment, ":/scenegraph/graph/shaders/line.fsh");
+ }
QList<QByteArray> attributes() const { return QList<QByteArray>() << "pos" << "t"; }
@@ -81,15 +75,7 @@ public:
id_color = program()->uniformLocation("color");
}
- static QByteArray readResource(const char *path) {
- QResource r(path);
- Q_ASSERT(r.isValid());
- return QByteArray((const char *)r.data(), r.size());
- }
-
private:
- QByteArray vsh;
- QByteArray fsh;
int id_color;
int id_spread;
int id_size;
diff --git a/examples/quick/scenegraph/graph/noisynode.cpp b/examples/quick/scenegraph/graph/noisynode.cpp
index 1fc87a2b97..7b2a843409 100644
--- a/examples/quick/scenegraph/graph/noisynode.cpp
+++ b/examples/quick/scenegraph/graph/noisynode.cpp
@@ -40,8 +40,6 @@
#include "noisynode.h"
-#include <QtCore/QResource>
-
#include <QtQuick/QSGSimpleMaterialShader>
#include <QtQuick/QSGTexture>
#include <QtQuick/QQuickWindow>
@@ -63,16 +61,9 @@ class NoisyShader : public QSGSimpleMaterialShader<NoisyMaterial>
QSG_DECLARE_SIMPLE_SHADER(NoisyShader, NoisyMaterial)
public:
- const char *vertexShader() const {
- QResource r(":/scenegraph/graph/shaders/noisy.vsh");
- Q_ASSERT(r.isValid());
- return (const char *) r.data();
- }
-
- const char *fragmentShader() const {
- QResource r(":/scenegraph/graph/shaders/noisy.fsh");
- Q_ASSERT(r.isValid());
- return (const char *) r.data();
+ NoisyShader() {
+ setShaderSourceFile(QOpenGLShader::Vertex, ":/scenegraph/graph/shaders/noisy.vsh");
+ setShaderSourceFile(QOpenGLShader::Fragment, ":/scenegraph/graph/shaders/noisy.fsh");
}
QList<QByteArray> attributes() const { return QList<QByteArray>() << "aVertex" << "aTexCoord"; }
diff --git a/examples/quick/scenegraph/graph/noisynode.h b/examples/quick/scenegraph/graph/noisynode.h
index b5a291330f..348efc66d2 100644
--- a/examples/quick/scenegraph/graph/noisynode.h
+++ b/examples/quick/scenegraph/graph/noisynode.h
@@ -42,8 +42,7 @@
#define NOISYNODE_H
#include <QSGGeometryNode>
-
-class QQuickWindow;
+#include <QQuickWindow>
class NoisyNode : public QSGGeometryNode
{
diff --git a/examples/quick/scenegraph/textureinthread/main.qml b/examples/quick/scenegraph/textureinthread/main.qml
index 4493ec46fd..52501ebd49 100644
--- a/examples/quick/scenegraph/textureinthread/main.qml
+++ b/examples/quick/scenegraph/textureinthread/main.qml
@@ -85,6 +85,10 @@ Item {
Scale { id: scale; },
Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 }
]
+
+ Behavior on opacity { NumberAnimation { duration: 500 } }
+ opacity: 0
+ Component.onCompleted: renderer.opacity = 1;
}
// Just to show something interesting
diff --git a/examples/quick/scenegraph/textureinthread/threadrenderer.cpp b/examples/quick/scenegraph/textureinthread/threadrenderer.cpp
index 072b4b9f0b..7ae47108f1 100644
--- a/examples/quick/scenegraph/textureinthread/threadrenderer.cpp
+++ b/examples/quick/scenegraph/textureinthread/threadrenderer.cpp
@@ -63,38 +63,24 @@ class RenderThread : public QThread
{
Q_OBJECT
public:
- RenderThread(const QSize &size, QOpenGLContext *context)
- : m_renderFbo(0)
+ RenderThread(const QSize &size)
+ : surface(0)
+ , context(0)
+ , m_renderFbo(0)
, m_displayFbo(0)
, m_logoRenderer(0)
- , m_fakeSurface(0)
, m_size(size)
{
ThreadRenderer::threads << this;
-
- // Set up the QOpenGLContext to use for rendering in this thread. It is sharing
- // memory space with the GL context of the scene graph. This constructor is called
- // during updatePaintNode, so we are currently on the scene graph thread with the
- // scene graph's OpenGL context current.
- m_context = new QOpenGLContext();
- m_context->setShareContext(context);
- m_context->setFormat(context->format());
- m_context->create();
- m_context->moveToThread(this);
-
- // We need a non-visible surface to make current in the other thread
- // and QWindows must be created and managed on the GUI thread.
- m_fakeSurface = new QOffscreenSurface();
- m_fakeSurface->setFormat(context->format());
- m_fakeSurface->create();
}
- void setSurface(QOffscreenSurface *surface) { m_fakeSurface = surface; }
+ QOffscreenSurface *surface;
+ QOpenGLContext *context;
public slots:
void renderNext()
{
- m_context->makeCurrent(m_fakeSurface);
+ context->makeCurrent(surface);
if (!m_renderFbo) {
// Initialize the buffers and renderer
@@ -124,15 +110,15 @@ public slots:
void shutDown()
{
- m_context->makeCurrent(m_fakeSurface);
+ context->makeCurrent(surface);
delete m_renderFbo;
delete m_displayFbo;
delete m_logoRenderer;
- m_context->doneCurrent();
- delete m_context;
+ context->doneCurrent();
+ delete context;
// schedule this to be deleted only after we're done cleaning up
- m_fakeSurface->deleteLater();
+ surface->deleteLater();
// Stop event processing, move the thread to GUI and make sure it is deleted.
exit();
@@ -147,9 +133,6 @@ private:
QOpenGLFramebufferObject *m_displayFbo;
LogoRenderer *m_logoRenderer;
-
- QOffscreenSurface *m_fakeSurface;
- QOpenGLContext *m_context;
QSize m_size;
};
@@ -226,26 +209,48 @@ private:
QQuickWindow *m_window;
};
-
-
ThreadRenderer::ThreadRenderer()
: m_renderThread(0)
{
setFlag(ItemHasContents, true);
+ m_renderThread = new RenderThread(QSize(512, 512));
+}
+
+void ThreadRenderer::ready()
+{
+ m_renderThread->surface = new QOffscreenSurface();
+ m_renderThread->surface->setFormat(m_renderThread->context->format());
+ m_renderThread->surface->create();
+
+ m_renderThread->moveToThread(m_renderThread);
+
+ connect(window(), SIGNAL(sceneGraphInvalidated()), m_renderThread, SLOT(shutDown()), Qt::QueuedConnection);
+
+ m_renderThread->start();
+ update();
}
QSGNode *ThreadRenderer::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
TextureNode *node = static_cast<TextureNode *>(oldNode);
- if (!m_renderThread) {
+ if (!m_renderThread->context) {
QOpenGLContext *current = window()->openglContext();
+ // Some GL implementations requres that the currently bound context is
+ // made non-current before we set up sharing, so we doneCurrent here
+ // and makeCurrent down below while setting up our own context.
current->doneCurrent();
- m_renderThread = new RenderThread(QSize(512, 512), current);
+
+ m_renderThread->context = new QOpenGLContext();
+ m_renderThread->context->setFormat(current->format());
+ m_renderThread->context->setShareContext(current);
+ m_renderThread->context->create();
+ m_renderThread->context->moveToThread(m_renderThread);
+
current->makeCurrent(window());
- m_renderThread->moveToThread(m_renderThread);
- m_renderThread->start();
- connect(window(), SIGNAL(sceneGraphInvalidated()), m_renderThread, SLOT(shutDown()), Qt::QueuedConnection);
+
+ QMetaObject::invokeMethod(this, "ready");
+ return 0;
}
if (!node) {
diff --git a/examples/quick/scenegraph/textureinthread/threadrenderer.h b/examples/quick/scenegraph/textureinthread/threadrenderer.h
index 7f720cb45a..3b0c153deb 100644
--- a/examples/quick/scenegraph/textureinthread/threadrenderer.h
+++ b/examples/quick/scenegraph/textureinthread/threadrenderer.h
@@ -54,10 +54,12 @@ public:
static QList<QThread *> threads;
+public Q_SLOTS:
+ void ready();
+
protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
-
private:
RenderThread *m_renderThread;
};
diff --git a/examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro b/examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro
index 0886f37b1f..e88e8f670c 100644
--- a/examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro
+++ b/examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro
@@ -20,14 +20,6 @@ SOURCES += \
OTHER_FILES += qmldir
-copyfile = $$PWD/qmldir
-copydest = $$DESTDIR
-
-# On Windows, use backslashes as directory separators
-win32: {
- copyfile ~= s,/,\\,g
- copydest ~= s,/,\\,g
-}
-
# Copy the qmldir file to the same folder as the plugin binary
-QMAKE_POST_LINK += $$QMAKE_COPY $$quote($$copyfile) $$quote($$copydest) $$escape_expand(\\n\\t)
+QMAKE_POST_LINK += $$QMAKE_COPY $$shell_quote($$shell_path($$PWD/qmldir)) \
+ $$shell_quote($$shell_path($$DESTDIR)) $$escape_expand(\\n\\t)
diff --git a/src/3rdparty/double-conversion/double-conversion.pri b/src/3rdparty/double-conversion/double-conversion.pri
index 4ad5f9f7a7..1597aca33e 100644
--- a/src/3rdparty/double-conversion/double-conversion.pri
+++ b/src/3rdparty/double-conversion/double-conversion.pri
@@ -1,4 +1,24 @@
INCLUDEPATH += $$PWD
VPATH += $$PWD
-SOURCES += $$PWD/*.cc
-HEADERS += $$PWD/*.h
+SOURCES += \
+ $$PWD/bignum.cc \
+ $$PWD/bignum-dtoa.cc \
+ $$PWD/cached-powers.cc \
+ $$PWD/diy-fp.cc \
+ $$PWD/double-conversion.cc \
+ $$PWD/fast-dtoa.cc \
+ $$PWD/fixed-dtoa.cc \
+ $$PWD/strtod.cc
+
+HEADERS += \
+ $$PWD/bignum-dtoa.h \
+ $$PWD/bignum.h \
+ $$PWD/cached-powers.h \
+ $$PWD/diy-fp.h \
+ $$PWD/double-conversion.h \
+ $$PWD/fast-dtoa.h \
+ $$PWD/fixed-dtoa.h \
+ $$PWD/ieee.h \
+ $$PWD/strtod.h \
+ $$PWD/utils.h
+
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
index 9a8dc1f358..f492cc8c94 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
@@ -39,7 +39,7 @@ class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> {
// - dTR is likely used more than aTR, and we'll get better instruction
// encoding if it's in the low 8 registers.
static const RegisterID dataTempRegister = ARMRegisters::ip;
- static const RegisterID addressTempRegister = ARMRegisters::r3;
+ static const RegisterID addressTempRegister = ARMRegisters::r10;
static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7;
inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
index 81063e2b11..ae7b0859ed 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
@@ -49,7 +49,7 @@ const char* const ARMv7DOpcode::s_optionName[8] = {
};
const char* const ARMv7DOpcode::s_shiftNames[4] = {
- "lsl", "lsr", "asl", "ror"
+ "lsl", "lsr", "asr", "ror"
};
const char* const ARMv7DOpcode::s_specialRegisterNames[3] = { "sp", "lr", "pc" };
@@ -944,7 +944,7 @@ const char* ARMv7DOpcodeDataProcessingShiftedReg::format()
appendSeparator();
appendRegisterName(rm());
appendSeparator();
- appendUnsignedImmediate(immediate5());
+ appendImmShift(type(), immediate5());
return m_formatBuffer;
}
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
index ca5f955ba1..5bcb6b15b9 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
@@ -69,6 +69,7 @@ protected:
static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; }
static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; }
+ static bool isRightShift(unsigned shiftValue) { return shiftValue == 1 || shiftValue == 2; }
bool inITBlock() { return m_ITConditionIndex < m_ITBlocksize; }
bool startingITBlock() { return m_ITConditionIndex == m_ITBlocksize + 1; }
@@ -514,7 +515,10 @@ protected:
const char* opName() { return shiftName(op()); }
unsigned op() { return (m_opcode >> 12) & 0x3; }
- unsigned immediate5() { return (m_opcode >> 6) & 0x1f; }
+ unsigned immediate5() {
+ unsigned imm = (m_opcode >> 6) & 0x1f;
+ return isRightShift(op()) && imm == 0 ? 32 : imm;
+ }
};
class ARMv7DOpcodeMiscAddSubSP : public ARMv7D16BitOpcode {
diff --git a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
index f851087eb2..7ed9f539e5 100644
--- a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
+++ b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
@@ -38,6 +38,7 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool, bool, bool)
void* result = _aligned_malloc(bytes, 16);
if (!result)
CRASH();
+ memset(result, 0, bytes);
return result;
}
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index f8d43f0594..1f28d8009e 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -158,35 +158,28 @@ void QQuickFolderListModelPrivate::_q_directoryUpdated(const QString &directory,
Q_UNUSED(directory);
QModelIndex parent;
- if (data.size() > list.size()) {
- //File(s) removed. Since I do not know how many
- //or where I need to update the whole list from the first item.
- data = list;
- q->beginRemoveRows(parent, fromIndex, toIndex);
- q->endRemoveRows();
- if (list.size() > 0) {
- q->beginInsertRows(parent, fromIndex, list.size()-1);
- q->endInsertRows();
- }
- emit q->rowCountChanged();
- } else if (data.size() < list.size()) {
- //qDebug() << "File added. FromIndex: " << fromIndex << " toIndex: " << toIndex << " list size: " << list.size();
- //File(s) added. Calculate how many and insert
- //from the first changed one.
- toIndex = fromIndex + (list.size() - data.size()-1);
- q->beginInsertRows(parent, fromIndex, toIndex);
- q->endInsertRows();
- data = list;
- emit q->rowCountChanged();
+ if (data.size() == list.size()) {
QModelIndex modelIndexFrom = q->createIndex(fromIndex, 0);
QModelIndex modelIndexTo = q->createIndex(toIndex, 0);
+ data = list;
emit q->dataChanged(modelIndexFrom, modelIndexTo);
} else {
- //qDebug() << "File has been updated";
- QModelIndex modelIndexFrom = q->createIndex(fromIndex, 0);
- QModelIndex modelIndexTo = q->createIndex(toIndex, 0);
+ // File(s) inserted or removed. Since I do not know how many
+ // or where, I need to update the whole list from the first item.
+ // This is a little pessimistic, but optimizing it would require
+ // more information in the signal from FileInfoThread.
+ if (data.size() > 0) {
+ q->beginRemoveRows(parent, 0, data.size() - 1);
+ q->endRemoveRows();
+ }
data = list;
- emit q->dataChanged(modelIndexFrom, modelIndexTo);
+ if (list.size() > 0) {
+ if (toIndex > list.size() - 1)
+ toIndex = list.size() - 1;
+ q->beginInsertRows(parent, 0, data.size() - 1);
+ q->endInsertRows();
+ }
+ emit q->rowCountChanged();
}
}
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index 71c87224d7..37addd1d7d 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -1323,10 +1323,10 @@ Item {
} else {
qtest_runFunction(prop, null, isBenchmark)
}
- qtest_results.finishTestFunction()
// wait(0) will call processEvents() so objects marked for deletion
// in the test function will be deleted.
wait(0)
+ qtest_results.finishTestFunction()
qtest_results.skipped = false
}
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
index 0b9be3105b..d5be42c06d 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
@@ -132,13 +132,17 @@ typedef QPair<int, int> QQuickXmlListRange;
For example, if there is an XML document like this:
- \quotefile qml/xmlrole.qml
+ \quotefile qml/xmlrole.xml
Here are some valid XPath expressions for XmlRole queries on this document:
\snippet qml/xmlrole.qml 0
\dots 4
\snippet qml/xmlrole.qml 1
+ Accessing the model data for the above roles from a delegate:
+
+ \snippet qml/xmlrole.qml 2
+
See the \l{http://www.w3.org/TR/xpath20/}{W3C XPath 2.0 specification} for more information.
*/
@@ -539,7 +543,7 @@ class QQuickXmlListModelPrivate : public QAbstractItemModelPrivate
Q_DECLARE_PUBLIC(QQuickXmlListModel)
public:
QQuickXmlListModelPrivate()
- : isComponentComplete(true), size(-1), highestRole(Qt::UserRole)
+ : isComponentComplete(true), size(0), highestRole(Qt::UserRole)
, reply(0), status(QQuickXmlListModel::Null), progress(0.0)
, queryId(-1), roleObjects(), redirectCount(0) {}
diff --git a/src/particles/qquickcustomaffector.cpp b/src/particles/qquickcustomaffector.cpp
index 890d415e3f..192f1676fd 100644
--- a/src/particles/qquickcustomaffector.cpp
+++ b/src/particles/qquickcustomaffector.cpp
@@ -49,9 +49,9 @@ QT_BEGIN_NAMESPACE
//TODO: Move docs (and inheritence) to real base when docs can propagate. Currently this pretends to be the base class!
/*!
- \qmlsignal QtQuick.Particles::Affector::onAffectParticles(Array particles, real dt)
+ \qmlsignal QtQuick.Particles::Affector::affectParticles(Array particles, real dt)
- This handler is called when particles are selected to be affected. particles contains
+ This signal is emitted when particles are selected to be affected. particles contains
an array of particle objects which can be directly manipulated.
dt is the time since the last time it was affected. Use dt to normalize
@@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE
Note that JavaScript is slower to execute, so it is not recommended to use this in
high-volume particle systems.
+
+ The corresponding handler is \c onAffectParticles.
*/
/*!
diff --git a/src/particles/qquickcustomparticle.cpp b/src/particles/qquickcustomparticle.cpp
index a3b41d0eb2..d3e5e4133f 100644
--- a/src/particles/qquickcustomparticle.cpp
+++ b/src/particles/qquickcustomparticle.cpp
@@ -269,6 +269,8 @@ QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffec
return 0;
if (m_dirtyProgram) {
+ const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
+
QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(rootNode->material());
Q_ASSERT(material);
@@ -276,17 +278,16 @@ QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffec
QSGShaderSourceBuilder builder;
if (s.sourceCode[Key::FragmentShader].isEmpty()) {
builder.appendSourceFile(QStringLiteral(":/particles/shaders/customparticle.frag"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
s.sourceCode[Key::FragmentShader] = builder.source();
builder.clear();
}
builder.appendSourceFile(QStringLiteral(":/particles/shaders/customparticletemplate.vert"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
if (s.sourceCode[Key::VertexShader].isEmpty())
builder.appendSourceFile(QStringLiteral(":/particles/shaders/customparticle.vert"));
s.sourceCode[Key::VertexShader] = builder.source() + s.sourceCode[Key::VertexShader];
@@ -310,12 +311,10 @@ QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffec
QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
{
-#ifdef QT_OPENGL_ES_2
- if (m_count * 4 > 0xffff) {
+ if (QOpenGLContext::currentContext()->isOpenGLES() && m_count * 4 > 0xffff) {
printf("CustomParticle: Too many particles... \n");
return 0;
}
-#endif
if (m_count <= 0) {
printf("CustomParticle: Too few particles... \n");
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index e5845f4c62..5efa7b4cca 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -100,15 +100,15 @@ public:
TabledMaterial()
{
QSGShaderSourceBuilder builder;
+ const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert"));
builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
builder.addDefinition(QByteArrayLiteral("TABLE"));
builder.addDefinition(QByteArrayLiteral("DEFORM"));
builder.addDefinition(QByteArrayLiteral("COLOR"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
m_vertex_code = builder.source();
builder.clear();
@@ -118,9 +118,9 @@ public:
builder.addDefinition(QByteArrayLiteral("TABLE"));
builder.addDefinition(QByteArrayLiteral("DEFORM"));
builder.addDefinition(QByteArrayLiteral("COLOR"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
@@ -178,14 +178,15 @@ public:
DeformableMaterial()
{
QSGShaderSourceBuilder builder;
+ const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert"));
builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
builder.addDefinition(QByteArrayLiteral("DEFORM"));
builder.addDefinition(QByteArrayLiteral("COLOR"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_vertex_code = builder.source();
builder.clear();
@@ -193,9 +194,9 @@ public:
builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
builder.addDefinition(QByteArrayLiteral("DEFORM"));
builder.addDefinition(QByteArrayLiteral("COLOR"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
@@ -242,6 +243,7 @@ public:
SpriteMaterial()
{
QSGShaderSourceBuilder builder;
+ const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert"));
builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
@@ -249,9 +251,9 @@ public:
builder.addDefinition(QByteArrayLiteral("TABLE"));
builder.addDefinition(QByteArrayLiteral("DEFORM"));
builder.addDefinition(QByteArrayLiteral("COLOR"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_vertex_code = builder.source();
builder.clear();
@@ -261,9 +263,9 @@ public:
builder.addDefinition(QByteArrayLiteral("TABLE"));
builder.addDefinition(QByteArrayLiteral("DEFORM"));
builder.addDefinition(QByteArrayLiteral("COLOR"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
@@ -323,22 +325,23 @@ public:
ColoredMaterial()
{
QSGShaderSourceBuilder builder;
+ const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert"));
builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
builder.addDefinition(QByteArrayLiteral("COLOR"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_vertex_code = builder.source();
builder.clear();
builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag"));
builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
builder.addDefinition(QByteArrayLiteral("COLOR"));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
@@ -400,20 +403,21 @@ public:
SimpleMaterial()
{
QSGShaderSourceBuilder builder;
+ const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert"));
builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_vertex_code = builder.source();
builder.clear();
builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag"));
builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
-#if defined(QT_OPENGL_ES_2)
- builder.removeVersion();
-#endif
+ if (isES)
+ builder.removeVersion();
+
m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
@@ -1227,12 +1231,10 @@ void QQuickImageParticle::buildParticleNodes(QSGNode** passThrough)
void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
{
-#ifdef QT_OPENGL_ES_2
- if (m_count * 4 > 0xffff) {
+ if (QOpenGLContext::currentContext()->isOpenGLES() && m_count * 4 > 0xffff) {
printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
return;
}
-#endif
if (count() <= 0)
return;
diff --git a/src/particles/qquickitemparticle.cpp b/src/particles/qquickitemparticle.cpp
index 53aa9a9926..0fe0b2ae0b 100644
--- a/src/particles/qquickitemparticle.cpp
+++ b/src/particles/qquickitemparticle.cpp
@@ -101,7 +101,7 @@ QT_BEGIN_NAMESPACE
*/
QQuickItemParticle::QQuickItemParticle(QQuickItem *parent) :
- QQuickParticlePainter(parent), m_fade(true), m_delegate(0)
+ QQuickParticlePainter(parent), m_fade(true), m_lastT(0), m_activeCount(0), m_delegate(0)
{
setFlag(QQuickItem::ItemHasContents);
clock = new Clock(this);
diff --git a/src/particles/qquickparticleaffector.cpp b/src/particles/qquickparticleaffector.cpp
index 7c72c27b74..261894402b 100644
--- a/src/particles/qquickparticleaffector.cpp
+++ b/src/particles/qquickparticleaffector.cpp
@@ -115,12 +115,12 @@ QT_BEGIN_NAMESPACE
non-rectangular area.
*/
/*!
- \qmlsignal QtQuick.Particles::Affector::onAffected(real x, real y)
+ \qmlsignal QtQuick.Particles::Affector::affected(real x, real y)
- This handler is called when a particle is selected to be affected. It will not be called
+ This signal is emitted when a particle is selected to be affected. It will not be emitted
if a particle is considered by the Affector but not actually altered in any way.
- In the special case where an Affector has no possible effect (e.g. Affector {}), affected
+ In the special case where an Affector has no possible effect (e.g. Affector {}), this signal
will be emitted for all particles being considered if you connect to it. This allows you to
execute arbitrary code in response to particles (use the Affector::onAffectParticles
signal handler if you want to execute code which affects the particles
@@ -128,6 +128,8 @@ QT_BEGIN_NAMESPACE
signal with a high-volume particle system.
x,y is the particle's current position.
+
+ The corresponding handler is \c onAffected.
*/
QQuickParticleAffector::QQuickParticleAffector(QQuickItem *parent) :
QQuickItem(parent), m_needsReset(false), m_ignoresTime(false), m_onceOff(false), m_enabled(true)
diff --git a/src/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp
index 41c64306a2..7c3df09341 100644
--- a/src/particles/qquickparticleemitter.cpp
+++ b/src/particles/qquickparticleemitter.cpp
@@ -189,13 +189,15 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlsignal QtQuick.Particles::Emitter::onEmitParticles(Array particles)
+ \qmlsignal QtQuick.Particles::Emitter::emitParticles(Array particles)
- This handler is called when particles are emitted. particles is a JavaScript
+ This signal is emitted when particles are emitted. particles is a JavaScript
array of Particle objects. You can modify particle attributes directly within the handler.
Note that JavaScript is slower to execute, so it is not recommended to use this in
high-volume particle systems.
+
+ The corresponding handler is \c onEmitParticles.
*/
/*! \qmlmethod QtQuick.Particles::Emitter::burst(int count)
diff --git a/src/particles/qquicktrailemitter.cpp b/src/particles/qquicktrailemitter.cpp
index cbc738fba5..e68e851d43 100644
--- a/src/particles/qquicktrailemitter.cpp
+++ b/src/particles/qquicktrailemitter.cpp
@@ -119,12 +119,11 @@ QQuickTrailEmitter::QQuickTrailEmitter(QQuickItem *parent) :
\qmlproperty real QtQuick.Particles::TrailEmitter::emitRatePerParticle
*/
/*!
- \qmlsignal QtQuick.Particles::TrailEmitter::onEmitFollowParticles(Array particles, Particle followed)
+ \qmlsignal QtQuick.Particles::TrailEmitter::emitFollowParticles(Array particles, Particle followed)
- This handler is called when particles are emitted from the \a followed particle. \a particles contains an array of particle objects which can be directly manipulated.
-
- If you use this signal handler, emitParticles will not be emitted.
+ This signal is emitted when particles are emitted from the \a followed particle. \a particles contains an array of particle objects which can be directly manipulated.
+ The corresponding handler is \c onEmitFollowParticles. If you use this signal handler, emitParticles will not be emitted.
*/
bool QQuickTrailEmitter::isEmitFollowConnected()
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index 7fd72d97d2..991b1fad5c 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -45,6 +45,7 @@
#include "private/qanimationgroupjob_p.h"
#include "private/qanimationjobutil_p.h"
#include "private/qqmlengine_p.h"
+#include "private/qqmlglobal_p.h"
#define DEFAULT_TIMER_INTERVAL 16
@@ -54,6 +55,8 @@ QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QThreadStorage<QQmlAnimationTimer *>, animationTimer)
#endif
+DEFINE_BOOL_CONFIG_OPTION(animationTickDump, QML_ANIMATION_TICK_DUMP);
+
QAnimationJobChangeListener::~QAnimationJobChangeListener()
{
}
@@ -115,6 +118,11 @@ void QQmlAnimationTimer::updateAnimationsTime(qint64 delta)
+ (animation->direction() == QAbstractAnimationJob::Forward ? delta : -delta);
animation->setCurrentTime(elapsed);
}
+ if (animationTickDump()) {
+ qDebug() << "***** Dumping Animation Tree ***** ( tick:" << lastTick << "delta:" << delta << ")";
+ for (int i = 0; i < animations.count(); ++i)
+ qDebug() << animations.at(i);
+ }
insideTick = false;
currentAnimationIdx = 0;
}
@@ -153,7 +161,8 @@ void QQmlAnimationTimer::startAnimations()
void QQmlAnimationTimer::stopTimer()
{
stopTimerPending = false;
- if (animations.isEmpty() && !startAnimationPending) {
+ bool pendingStart = startAnimationPending && animationsToStart.size() > 0;
+ if (animations.isEmpty() && !pendingStart) {
QUnifiedTimer::resumeAnimationTimer(this);
QUnifiedTimer::stopAnimationTimer(this);
// invalidate the start reference time
@@ -371,6 +380,7 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
{
// this ensures that the value is updated now that the animation is running
if (oldState == Stopped) {
+ m_currentLoop = 0;
if (isTopLevel) {
// currentTime needs to be updated if pauseTimer is active
RETURN_IF_DELETED(QQmlAnimationTimer::ensureTimerUpdate());
@@ -646,6 +656,21 @@ void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeLis
}
}
+void QAbstractAnimationJob::debugAnimation(QDebug d) const
+{
+ d << "AbstractAnimationJob(" << hex << (void *) this << dec << ")" << "duration:" << duration();
+}
+
+QDebug operator<<(QDebug d, const QAbstractAnimationJob *job)
+{
+ if (!job) {
+ d << "AbstractAnimationJob(null)";
+ return d;
+ }
+ job->debugAnimation(d);
+ return d;
+}
+
QT_END_NAMESPACE
//#include "moc_qabstractanimation2_p.cpp"
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index e8745c8c92..c905fca0d7 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -123,6 +123,8 @@ protected:
virtual void updateDirection(QAbstractAnimationJob::Direction direction);
virtual void topLevelAnimationLoopChanged() {}
+ virtual void debugAnimation(QDebug d) const;
+
void fireTopLevelAnimationLoopChanged();
void setState(QAbstractAnimationJob::State state);
@@ -169,6 +171,7 @@ protected:
friend class QQmlAnimationTimer;
friend class QAnimationGroupJob;
+ friend QDebug operator<<(QDebug, const QAbstractAnimationJob *job);
};
class Q_QML_PRIVATE_EXPORT QAnimationJobChangeListener
@@ -237,6 +240,8 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractAnimationJob::ChangeTypes)
+QDebug operator<<(QDebug, const QAbstractAnimationJob *job);
+
QT_END_NAMESPACE
#endif // QABSTRACTANIMATIONJOB_P_H
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
index afdf07639b..a8b1b28e3e 100644
--- a/src/qml/animations/qanimationgroupjob.cpp
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -167,4 +167,16 @@ void QAnimationGroupJob::animationRemoved(QAbstractAnimationJob* anim, QAbstract
}
}
+void QAnimationGroupJob::debugChildren(QDebug d) const
+{
+ int indentLevel = 1;
+ const QAnimationGroupJob *group = this;
+ while ((group = group->m_group))
+ ++indentLevel;
+
+ QByteArray ind(indentLevel, ' ');
+ for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling())
+ d << "\n" << ind.constData() << child;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index 0f62194656..45bf32fd36 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -76,6 +76,8 @@ protected:
int uncontrolledAnimationFinishTime(QAbstractAnimationJob *anim) const { return anim->m_uncontrolledFinishTime; }
void setUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim, int time);
+ void debugChildren(QDebug d) const;
+
private:
//definition
QAbstractAnimationJob *m_firstChild;
diff --git a/src/qml/animations/qcontinuinganimationgroupjob.cpp b/src/qml/animations/qcontinuinganimationgroupjob.cpp
index eb54b6e9aa..432ed8c692 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob.cpp
+++ b/src/qml/animations/qcontinuinganimationgroupjob.cpp
@@ -55,8 +55,7 @@ QContinuingAnimationGroupJob::~QContinuingAnimationGroupJob()
void QContinuingAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
{
- if (!firstChild())
- return;
+ Q_ASSERT(firstChild());
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
if (animation->state() == state()) {
@@ -81,6 +80,10 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
animation->pause();
break;
case Running:
+ if (!firstChild()) {
+ stop();
+ return;
+ }
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
resetUncontrolledAnimationFinishTime(animation);
animation->setDirection(m_direction);
@@ -118,5 +121,12 @@ void QContinuingAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
stop();
}
+void QContinuingAnimationGroupJob::debugAnimation(QDebug d) const
+{
+ d << "ContinuingAnimationGroupJob(" << hex << (void *) this << dec << ")";
+
+ debugChildren(d);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/animations/qcontinuinganimationgroupjob_p.h b/src/qml/animations/qcontinuinganimationgroupjob_p.h
index 7578ab9709..c84ff3ca10 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob_p.h
+++ b/src/qml/animations/qcontinuinganimationgroupjob_p.h
@@ -60,6 +60,7 @@ protected:
void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
void updateDirection(QAbstractAnimationJob::Direction direction);
void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+ void debugAnimation(QDebug d) const;
};
QT_END_NAMESPACE
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
index 85a8527c6b..818988b310 100644
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -61,13 +61,8 @@ int QParallelAnimationGroupJob::duration() const
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
int currentDuration = animation->totalDuration();
- //this takes care of the case where a parallel animation group has controlled and uncontrolled
- //animations, and the uncontrolled stop before the controlled
- if (currentDuration == -1)
- currentDuration = uncontrolledAnimationFinishTime(animation);
if (currentDuration == -1)
return -1; // Undetermined length
-
ret = qMax(ret, currentDuration);
}
@@ -82,6 +77,16 @@ void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
if (m_currentLoop > m_previousLoop) {
// simulate completion of the loop
int dura = duration();
+ if (dura < 0) {
+ // For an uncontrolled parallel group, we need to simulate the end of running animations.
+ // As uncontrolled animation finish time is already reset for this next loop, we pick the
+ // longest of the known stop times.
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ int currentDuration = animation->totalDuration();
+ if (currentDuration >= 0)
+ dura = qMax(dura, currentDuration);
+ }
+ }
if (dura > 0) {
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
if (!animation->isStopped())
@@ -137,8 +142,10 @@ void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newSta
break;
case Running:
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
- if (oldState == Stopped)
+ if (oldState == Stopped) {
animation->stop();
+ m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
+ }
resetUncontrolledAnimationFinishTime(animation);
animation->setDirection(m_direction);
if (shouldAnimationStart(animation, oldState == Stopped))
@@ -223,7 +230,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
maxDuration = qMax(maxDuration, job->totalDuration());
}
- setUncontrolledAnimationFinishTime(this, qMax(maxDuration, currentTime()));
+ setUncontrolledAnimationFinishTime(this, qMax(maxDuration + m_currentLoopStartTime, currentTime()));
if (!running
&& ((m_direction == Forward && m_currentLoop == m_loopCount -1)
@@ -232,5 +239,12 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
}
}
+void QParallelAnimationGroupJob::debugAnimation(QDebug d) const
+{
+ d << "ParallelAnimationGroupJob(" << hex << (void *) this << dec << ")";
+
+ debugChildren(d);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/animations/qparallelanimationgroupjob_p.h b/src/qml/animations/qparallelanimationgroupjob_p.h
index 8e29402f33..8cad1c993f 100644
--- a/src/qml/animations/qparallelanimationgroupjob_p.h
+++ b/src/qml/animations/qparallelanimationgroupjob_p.h
@@ -60,6 +60,7 @@ protected:
void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
void updateDirection(QAbstractAnimationJob::Direction direction);
void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+ void debugAnimation(QDebug d) const;
private:
bool shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const;
diff --git a/src/qml/animations/qpauseanimationjob.cpp b/src/qml/animations/qpauseanimationjob.cpp
index b6b081d39d..f185b12750 100644
--- a/src/qml/animations/qpauseanimationjob.cpp
+++ b/src/qml/animations/qpauseanimationjob.cpp
@@ -68,4 +68,9 @@ void QPauseAnimationJob::updateCurrentTime(int)
{
}
+void QPauseAnimationJob::debugAnimation(QDebug d) const
+{
+ d << "PauseAnimationJob(" << hex << (void *) this << dec << ")" << "duration:" << m_duration;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/animations/qpauseanimationjob_p.h b/src/qml/animations/qpauseanimationjob_p.h
index f84143d9bf..a2ec71f373 100644
--- a/src/qml/animations/qpauseanimationjob_p.h
+++ b/src/qml/animations/qpauseanimationjob_p.h
@@ -58,6 +58,7 @@ public:
protected:
void updateCurrentTime(int);
+ void debugAnimation(QDebug d) const;
private:
//definition
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index ec9b2ba906..cfc53d552a 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -75,8 +75,12 @@ bool QSequentialAnimationGroupJob::atEnd() const
int QSequentialAnimationGroupJob::animationActualTotalDuration(QAbstractAnimationJob *anim) const
{
int ret = anim->totalDuration();
- if (ret == -1)
- ret = uncontrolledAnimationFinishTime(anim); //we can try the actual duration there
+ if (ret == -1) {
+ int done = uncontrolledAnimationFinishTime(anim);
+ // If the animation has reached the end, use the uncontrolledFinished value.
+ if (done >= 0 && (anim->loopCount() - 1 == anim->currentLoop() || anim->state() == Stopped))
+ return done;
+ }
return ret;
}
@@ -413,4 +417,11 @@ void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim,
m_totalCurrentTime = m_currentTime + m_loopCount * duration();
}
+void QSequentialAnimationGroupJob::debugAnimation(QDebug d) const
+{
+ d << "SequentialAnimationGroupJob(" << hex << (void *) this << dec << ")" << "currentAnimation:" << (void *)m_currentAnimation;
+
+ debugChildren(d);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/animations/qsequentialanimationgroupjob_p.h b/src/qml/animations/qsequentialanimationgroupjob_p.h
index 18dc6fcc7b..7d4b933bd5 100644
--- a/src/qml/animations/qsequentialanimationgroupjob_p.h
+++ b/src/qml/animations/qsequentialanimationgroupjob_p.h
@@ -63,6 +63,7 @@ protected:
void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
void updateDirection(QAbstractAnimationJob::Direction direction);
void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+ void debugAnimation(QDebug d) const;
private:
struct AnimationIndex
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 24379ca5f3..585fef7603 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -7,21 +7,31 @@ HEADERS += \
$$PWD/qv4codegen_p.h \
$$PWD/qv4isel_p.h \
$$PWD/qv4jsir_p.h \
- $$PWD/qv4instr_moth_p.h \
- $$PWD/qv4isel_moth_p.h \
$$PWD/qv4isel_util_p.h \
$$PWD/qv4ssa_p.h \
- $$PWD/qqmlcodegenerator_p.h \
+ $$PWD/qqmlirbuilder_p.h \
$$PWD/qqmltypecompiler_p.h
SOURCES += \
$$PWD/qv4compileddata.cpp \
$$PWD/qv4compiler.cpp \
$$PWD/qv4codegen.cpp \
- $$PWD/qv4instr_moth.cpp \
- $$PWD/qv4isel_moth.cpp \
$$PWD/qv4isel_p.cpp \
$$PWD/qv4jsir.cpp \
$$PWD/qv4ssa.cpp \
- $$PWD/qqmlcodegenerator.cpp \
- $$PWD/qqmltypecompiler.cpp
+ $$PWD/qqmlirbuilder.cpp
+
+!qmldevtools_build {
+
+HEADERS += \
+ $$PWD/qqmltypecompiler_p.h \
+ $$PWD/qv4isel_moth_p.h \
+ $$PWD/qv4instr_moth_p.h
+
+
+SOURCES += \
+ $$PWD/qqmltypecompiler.cpp \
+ $$PWD/qv4instr_moth.cpp \
+ $$PWD/qv4isel_moth.cpp
+
+}
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 45373c6d11..28a4e23a37 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -39,15 +39,21 @@
**
****************************************************************************/
-#include "qqmlcodegenerator_p.h"
+#include "qqmlirbuilder_p.h"
+#include <private/qv4value_inl_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljslexer_p.h>
-#include <private/qqmlcompiler_p.h>
-#include <private/qqmlglobal_p.h>
#include <QCoreApplication>
+#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
#undef CONST
#endif
@@ -56,9 +62,11 @@ QT_USE_NAMESPACE
static const quint32 emptyStringIndex = 0;
+#ifndef V4_BOOTSTRAP
DEFINE_BOOL_CONFIG_OPTION(lookupHints, QML_LOOKUP_HINTS);
+#endif // V4_BOOTSTRAP
-using namespace QtQml;
+using namespace QmlIR;
#define COMPILE_EXCEPTION(location, desc) \
{ \
@@ -66,7 +74,7 @@ using namespace QtQml;
return false; \
}
-void QmlObject::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &loc)
+void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &loc)
{
inheritedTypeNameIndex = typeNameIndex;
@@ -75,7 +83,7 @@ void QmlObject::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const
idIndex = id;
indexOfDefaultProperty = -1;
- properties = pool->New<PoolList<QmlProperty> >();
+ properties = pool->New<PoolList<Property> >();
qmlSignals = pool->New<PoolList<Signal> >();
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
@@ -84,16 +92,7 @@ void QmlObject::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const
declarationsOverride = 0;
}
-void QmlObject::dump(DebugStream &out)
-{
- out << inheritedTypeNameIndex << " {" << endl;
- out.indent++;
-
- out.indent--;
- out << "}" << endl;
-}
-
-QString QmlObject::sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
+QString Object::sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
{
QSet<int> functionNames;
for (Function *f = functions->first; f; f = f->next) {
@@ -104,7 +103,7 @@ QString QmlObject::sanityCheckFunctionNames(const QSet<QString> &illegalNames, Q
return tr("Duplicate method name");
functionNames.insert(f->nameIndex);
- for (QtQml::Signal *s = qmlSignals->first; s; s = s->next) {
+ for (QmlIR::Signal *s = qmlSignals->first; s; s = s->next) {
if (s->nameIndex == f->nameIndex)
return tr("Duplicate method name");
}
@@ -118,9 +117,9 @@ QString QmlObject::sanityCheckFunctionNames(const QSet<QString> &illegalNames, Q
return QString(); // no error
}
-QString QmlObject::appendSignal(Signal *signal)
+QString Object::appendSignal(Signal *signal)
{
- QmlObject *target = declarationsOverride;
+ Object *target = declarationsOverride;
if (!target)
target = this;
@@ -133,13 +132,13 @@ QString QmlObject::appendSignal(Signal *signal)
return QString(); // no error
}
-QString QmlObject::appendProperty(QmlProperty *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation)
+QString Object::appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation)
{
- QmlObject *target = declarationsOverride;
+ Object *target = declarationsOverride;
if (!target)
target = this;
- for (QmlProperty *p = target->properties->first; p; p = p->next)
+ for (Property *p = target->properties->first; p; p = p->next)
if (p->nameIndex == prop->nameIndex)
return tr("Duplicate property name");
@@ -157,15 +156,15 @@ QString QmlObject::appendProperty(QmlProperty *prop, const QString &propertyName
return QString(); // no error
}
-void QmlObject::appendFunction(QtQml::Function *f)
+void Object::appendFunction(QmlIR::Function *f)
{
- QmlObject *target = declarationsOverride;
+ Object *target = declarationsOverride;
if (!target)
target = this;
target->functions->append(f);
}
-QString QmlObject::appendBinding(Binding *b, bool isListBinding)
+QString Object::appendBinding(Binding *b, bool isListBinding)
{
const bool bindingToDefaultProperty = (b->propertyNameIndex == 0);
if (!isListBinding && !bindingToDefaultProperty
@@ -183,7 +182,7 @@ QString QmlObject::appendBinding(Binding *b, bool isListBinding)
return QString(); // no error
}
-Binding *QmlObject::findBinding(quint32 nameIndex) const
+Binding *Object::findBinding(quint32 nameIndex) const
{
for (Binding *b = bindings->first; b; b = b->next)
if (b->propertyNameIndex == nameIndex)
@@ -191,22 +190,367 @@ Binding *QmlObject::findBinding(quint32 nameIndex) const
return 0;
}
-void QmlObject::insertSorted(Binding *b)
+void Object::insertSorted(Binding *b)
{
Binding *insertionPoint = bindings->findSortedInsertionPoint<QV4::CompiledData::Location, QV4::CompiledData::Binding, &QV4::CompiledData::Binding::valueLocation>(b);
bindings->insertAfter(insertionPoint, b);
}
-QStringList Signal::parameterStringList(const QStringList &stringPool) const
+QString Object::bindingAsString(Document *doc, int scriptIndex) const
+{
+ CompiledFunctionOrExpression *foe = functionsAndExpressions->slowAt(scriptIndex);
+ QQmlJS::AST::Node *node = foe->node;
+ if (QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(node))
+ node = exprStmt->expression;
+ QQmlJS::AST::SourceLocation start = node->firstSourceLocation();
+ QQmlJS::AST::SourceLocation end = node->lastSourceLocation();
+ return doc->code.mid(start.offset, end.offset + end.length - start.offset);
+}
+
+QStringList Signal::parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const
{
QStringList result;
result.reserve(parameters->count);
for (SignalParameter *param = parameters->first; param; param = param->next)
- result << stringPool.at(param->nameIndex);
+ result << stringPool->stringForIndex(param->nameIndex);
return result;
}
-QQmlCodeGenerator::QQmlCodeGenerator(const QSet<QString> &illegalNames)
+static void replaceWithSpace(QString &str, int idx, int n)
+{
+ QChar *data = str.data() + idx;
+ const QChar space(QLatin1Char(' '));
+ for (int ii = 0; ii < n; ++ii)
+ *data++ = space;
+}
+
+#define CHECK_LINE if (l.tokenStartLine() != startLine) return;
+#define CHECK_TOKEN(t) if (token != QQmlJSGrammar:: t) return;
+
+static const int uriTokens[] = {
+ QQmlJSGrammar::T_IDENTIFIER,
+ QQmlJSGrammar::T_PROPERTY,
+ QQmlJSGrammar::T_SIGNAL,
+ QQmlJSGrammar::T_READONLY,
+ QQmlJSGrammar::T_ON,
+ QQmlJSGrammar::T_BREAK,
+ QQmlJSGrammar::T_CASE,
+ QQmlJSGrammar::T_CATCH,
+ QQmlJSGrammar::T_CONTINUE,
+ QQmlJSGrammar::T_DEFAULT,
+ QQmlJSGrammar::T_DELETE,
+ QQmlJSGrammar::T_DO,
+ QQmlJSGrammar::T_ELSE,
+ QQmlJSGrammar::T_FALSE,
+ QQmlJSGrammar::T_FINALLY,
+ QQmlJSGrammar::T_FOR,
+ QQmlJSGrammar::T_FUNCTION,
+ QQmlJSGrammar::T_IF,
+ QQmlJSGrammar::T_IN,
+ QQmlJSGrammar::T_INSTANCEOF,
+ QQmlJSGrammar::T_NEW,
+ QQmlJSGrammar::T_NULL,
+ QQmlJSGrammar::T_RETURN,
+ QQmlJSGrammar::T_SWITCH,
+ QQmlJSGrammar::T_THIS,
+ QQmlJSGrammar::T_THROW,
+ QQmlJSGrammar::T_TRUE,
+ QQmlJSGrammar::T_TRY,
+ QQmlJSGrammar::T_TYPEOF,
+ QQmlJSGrammar::T_VAR,
+ QQmlJSGrammar::T_VOID,
+ QQmlJSGrammar::T_WHILE,
+ QQmlJSGrammar::T_CONST,
+ QQmlJSGrammar::T_DEBUGGER,
+ QQmlJSGrammar::T_RESERVED_WORD,
+ QQmlJSGrammar::T_WITH,
+
+ QQmlJSGrammar::EOF_SYMBOL
+};
+static inline bool isUriToken(int token)
+{
+ const int *current = uriTokens;
+ while (*current != QQmlJSGrammar::EOF_SYMBOL) {
+ if (*current == token)
+ return true;
+ ++current;
+ }
+ return false;
+}
+
+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.needsCreation = true;
+ 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::extractScriptMetaData(QString &script, QQmlJS::DiagnosticMessage *error)
+{
+ Q_ASSERT(error);
+
+ const QString js(QLatin1String(".js"));
+ const QString library(QLatin1String("library"));
+
+ QQmlJS::MemoryPool *pool = jsParserEngine.pool();
+
+ QQmlJS::Lexer l(0);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QQmlJSGrammar::T_DOT)
+ return;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.tokenStartLine();
+ int startColumn = l.tokenStartColumn();
+
+ error->loc.startLine = startLine + 1; // 0-based, adjust to be 1-based
+
+ token = l.lex();
+
+ CHECK_LINE;
+
+ if (token == QQmlJSGrammar::T_IMPORT) {
+
+ // .import <URI> <Version> as <Identifier>
+ // .import <file.js> as <Identifier>
+
+ token = l.lex();
+
+ CHECK_LINE;
+ QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
+
+ if (token == QQmlJSGrammar::T_STRING_LITERAL) {
+
+ QString file = l.tokenText();
+
+ if (!file.endsWith(js)) {
+ error->message = QCoreApplication::translate("QQmlParser","Imported file must be a script");
+ error->loc.startColumn = l.tokenStartColumn();
+ return;
+ }
+
+ bool invalidImport = false;
+
+ token = l.lex();
+
+ if ((token != QQmlJSGrammar::T_AS) || (l.tokenStartLine() != startLine)) {
+ invalidImport = true;
+ } else {
+ token = l.lex();
+
+ if ((token != QQmlJSGrammar::T_IDENTIFIER) || (l.tokenStartLine() != startLine))
+ invalidImport = true;
+ }
+
+
+ if (invalidImport) {
+ error->message = QCoreApplication::translate("QQmlParser","File import requires a qualifier");
+ error->loc.startColumn = l.tokenStartColumn();
+ return;
+ }
+
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ QString importId = script.mid(l.tokenOffset(), l.tokenLength());
+
+ token = l.lex();
+
+ if (!importId.at(0).isUpper() || (l.tokenStartLine() == startLine)) {
+ error->message = QCoreApplication::translate("QQmlParser","Invalid import qualifier");
+ error->loc.startColumn = l.tokenStartColumn();
+ return;
+ }
+
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+
+ import->type = QV4::CompiledData::Import::ImportScript;
+ import->uriIndex = registerString(file);
+ import->qualifierIndex = registerString(importId);
+ import->location.line = startLine;
+ import->location.column = startColumn;
+ imports << import;
+ } else {
+ // URI
+ QString uri;
+
+ while (true) {
+ if (!isUriToken(token)) {
+ error->message = QCoreApplication::translate("QQmlParser","Invalid module URI");
+ error->loc.startColumn = l.tokenStartColumn();
+ return;
+ }
+
+ uri.append(l.tokenText());
+
+ token = l.lex();
+ CHECK_LINE;
+ if (token != QQmlJSGrammar::T_DOT)
+ break;
+
+ uri.append(QLatin1Char('.'));
+
+ token = l.lex();
+ CHECK_LINE;
+ }
+
+ if (token != QQmlJSGrammar::T_NUMERIC_LITERAL) {
+ error->message = QCoreApplication::translate("QQmlParser","Module import requires a version");
+ error->loc.startColumn = l.tokenStartColumn();
+ return;
+ }
+
+ int vmaj, vmin;
+ IRBuilder::extractVersion(QStringRef(&script, l.tokenOffset(), l.tokenLength()),
+ &vmaj, &vmin);
+
+ bool invalidImport = false;
+
+ token = l.lex();
+
+ if ((token != QQmlJSGrammar::T_AS) || (l.tokenStartLine() != startLine)) {
+ invalidImport = true;
+ } else {
+ token = l.lex();
+
+ if ((token != QQmlJSGrammar::T_IDENTIFIER) || (l.tokenStartLine() != startLine))
+ invalidImport = true;
+ }
+
+
+ if (invalidImport) {
+ error->message = QCoreApplication::translate("QQmlParser","Module import requires a qualifier");
+ error->loc.startColumn = l.tokenStartColumn();
+ return;
+ }
+
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ QString importId = script.mid(l.tokenOffset(), l.tokenLength());
+
+ token = l.lex();
+
+ if (!importId.at(0).isUpper() || (l.tokenStartLine() == startLine)) {
+ error->message = QCoreApplication::translate("QQmlParser","Invalid import qualifier");
+ error->loc.startColumn = l.tokenStartColumn();
+ return;
+ }
+
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+
+ import->type = QV4::CompiledData::Import::ImportLibrary;
+ import->uriIndex = registerString(uri);
+ import->majorVersion = vmaj;
+ import->minorVersion = vmin;
+ import->qualifierIndex = registerString(importId);
+ import->location.line = startLine;
+ import->location.column = startColumn;
+ imports << import;
+ }
+ } else if (token == QQmlJSGrammar::T_PRAGMA) {
+ token = l.lex();
+
+ CHECK_TOKEN(T_IDENTIFIER);
+ CHECK_LINE;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ if (pragmaValue == library) {
+ unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary;
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ } else {
+ return;
+ }
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return;
+
+ } else {
+ return;
+ }
+ }
+ return;
+}
+
+void Document::removeScriptPragmas(QString &script)
+{
+ const QString pragma(QLatin1String("pragma"));
+ const QString library(QLatin1String("library"));
+
+ QQmlJS::Lexer l(0);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QQmlJSGrammar::T_DOT)
+ return;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.tokenStartLine();
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_PRAGMA ||
+ l.tokenStartLine() != startLine ||
+ script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
+ return;
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER ||
+ l.tokenStartLine() != startLine)
+ return;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return;
+
+ if (pragmaValue == library) {
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ } else {
+ return;
+ }
+ }
+}
+
+Document::Document(bool debugMode)
+ : jsModule(debugMode)
+ , program(0)
+ , jsGenerator(&jsModule, sizeof(QV4::CompiledData::QmlUnit))
+ , unitFlags(0)
+ , javaScriptCompilationUnit(0)
+{
+}
+
+IRBuilder::IRBuilder(const QSet<QString> &illegalNames)
: illegalNames(illegalNames)
, _object(0)
, _propertyDeclaration(0)
@@ -214,7 +558,7 @@ QQmlCodeGenerator::QQmlCodeGenerator(const QSet<QString> &illegalNames)
{
}
-bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, const QString &urlString, ParsedQML *output)
+bool IRBuilder::generateFromQml(const QString &code, const QString &url, const QString &urlString, Document *output)
{
this->url = url;
QQmlJS::AST::UiProgram *program = 0;
@@ -248,7 +592,6 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
- qSwap(_typeReferences, output->typeReferences);
this->pool = output->jsParserEngine.pool();
this->jsGenerator = &output->jsGenerator;
@@ -259,7 +602,6 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
accept(program->headers);
if (program->members->next) {
- QQmlError error;
QQmlJS::AST::SourceLocation loc = program->members->next->firstSourceLocation();
recordError(loc, QCoreApplication::translate("QQmlParser", "Unexpected object definition"));
return false;
@@ -267,17 +609,15 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
QQmlJS::AST::UiObjectDefinition *rootObject = QQmlJS::AST::cast<QQmlJS::AST::UiObjectDefinition*>(program->members->member);
Q_ASSERT(rootObject);
- if (defineQMLObject(&output->indexOfRootObject, rootObject))
- collectTypeReferences();
+ defineQMLObject(&output->indexOfRootObject, rootObject);
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
- qSwap(_typeReferences, output->typeReferences);
return errors.isEmpty();
}
-bool QQmlCodeGenerator::isSignalPropertyName(const QString &name)
+bool IRBuilder::isSignalPropertyName(const QString &name)
{
if (name.length() < 3) return false;
if (!name.startsWith(QStringLiteral("on"))) return false;
@@ -291,18 +631,18 @@ bool QQmlCodeGenerator::isSignalPropertyName(const QString &name)
return false; // consists solely of underscores - invalid.
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiArrayMemberList *ast)
+bool IRBuilder::visit(QQmlJS::AST::UiArrayMemberList *ast)
{
return QQmlJS::AST::Visitor::visit(ast);
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiProgram *)
+bool IRBuilder::visit(QQmlJS::AST::UiProgram *)
{
Q_ASSERT(!"should not happen");
return false;
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiObjectDefinition *node)
+bool IRBuilder::visit(QQmlJS::AST::UiObjectDefinition *node)
{
// The grammar can't distinguish between two different definitions here:
// Item { ... }
@@ -331,7 +671,7 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiObjectDefinition *node)
return false;
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiObjectBinding *node)
+bool IRBuilder::visit(QQmlJS::AST::UiObjectBinding *node)
{
int idx = 0;
if (!defineQMLObject(&idx, node->qualifiedTypeNameId, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer))
@@ -340,16 +680,16 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiObjectBinding *node)
return false;
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiScriptBinding *node)
+bool IRBuilder::visit(QQmlJS::AST::UiScriptBinding *node)
{
appendBinding(node->qualifiedId, node->statement);
return false;
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiArrayBinding *node)
+bool IRBuilder::visit(QQmlJS::AST::UiArrayBinding *node)
{
const QQmlJS::AST::SourceLocation qualifiedNameLocation = node->qualifiedId->identifierToken;
- QmlObject *object = 0;
+ Object *object = 0;
QQmlJS::AST::UiQualifiedId *name = node->qualifiedId;
if (!resolveQualifiedId(&name, &object))
return false;
@@ -383,37 +723,37 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiArrayBinding *node)
return false;
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiHeaderItemList *list)
+bool IRBuilder::visit(QQmlJS::AST::UiHeaderItemList *list)
{
return QQmlJS::AST::Visitor::visit(list);
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiObjectInitializer *ast)
+bool IRBuilder::visit(QQmlJS::AST::UiObjectInitializer *ast)
{
return QQmlJS::AST::Visitor::visit(ast);
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiObjectMemberList *ast)
+bool IRBuilder::visit(QQmlJS::AST::UiObjectMemberList *ast)
{
return QQmlJS::AST::Visitor::visit(ast);
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiParameterList *ast)
+bool IRBuilder::visit(QQmlJS::AST::UiParameterList *ast)
{
return QQmlJS::AST::Visitor::visit(ast);
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiQualifiedId *id)
+bool IRBuilder::visit(QQmlJS::AST::UiQualifiedId *id)
{
return QQmlJS::AST::Visitor::visit(id);
}
-void QQmlCodeGenerator::accept(QQmlJS::AST::Node *node)
+void IRBuilder::accept(QQmlJS::AST::Node *node)
{
QQmlJS::AST::Node::acceptChild(node, this);
}
-bool QQmlCodeGenerator::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, QmlObject *declarationsOverride)
+bool IRBuilder::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride)
{
if (QQmlJS::AST::UiQualifiedId *lastName = qualifiedTypeNameId) {
while (lastName->next)
@@ -424,7 +764,7 @@ bool QQmlCodeGenerator::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifi
}
}
- QmlObject *obj = New<QmlObject>();
+ Object *obj = New<Object>();
_objects.append(obj);
*objectIndex = _objects.size() - 1;
qSwap(_object, obj);
@@ -433,7 +773,7 @@ bool QQmlCodeGenerator::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifi
_object->declarationsOverride = declarationsOverride;
// A new object is also a boundary for property declarations.
- QmlProperty *declaration = 0;
+ Property *declaration = 0;
qSwap(_propertyDeclaration, declaration);
accept(initializer);
@@ -455,7 +795,7 @@ bool QQmlCodeGenerator::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifi
return true;
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiImport *node)
+bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
{
QString uri;
QV4::CompiledData::Import *import = New<QV4::CompiledData::Import>();
@@ -491,10 +831,10 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiImport *node)
// Check for script qualifier clashes
bool isScript = import->type == QV4::CompiledData::Import::ImportScript;
for (int ii = 0; ii < _imports.count(); ++ii) {
- QV4::CompiledData::Import *other = _imports.at(ii);
+ const QV4::CompiledData::Import *other = _imports.at(ii);
bool otherIsScript = other->type == QV4::CompiledData::Import::ImportScript;
- if ((isScript || otherIsScript) && qualifier == jsGenerator->strings.at(other->qualifierIndex)) {
+ if ((isScript || otherIsScript) && qualifier == jsGenerator->stringForIndex(other->qualifierIndex)) {
recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Script import qualifiers must be unique."));
return false;
}
@@ -527,7 +867,7 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiImport *node)
return false;
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiPragma *node)
+bool IRBuilder::visit(QQmlJS::AST::UiPragma *node)
{
Pragma *pragma = New<Pragma>();
@@ -571,7 +911,7 @@ static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
return QStringList();
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiPublicMember *node)
+bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
{
static const struct TypeNameToType {
const char *name;
@@ -630,8 +970,7 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiPublicMember *node)
const TypeNameToType *type = 0;
for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
const TypeNameToType *t = propTypeNameToTypes + typeIndex;
- if (t->nameLength == size_t(memberType.length()) &&
- QHashedString::compare(memberType.constData(), t->name, static_cast<int>(t->nameLength))) {
+ if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
type = t;
break;
}
@@ -682,16 +1021,14 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiPublicMember *node)
bool typeFound = false;
QV4::CompiledData::Property::Type type;
- if ((unsigned)memberType.length() == strlen("alias") &&
- QHashedString::compare(memberType.constData(), "alias", static_cast<int>(strlen("alias")))) {
+ if (memberType == QLatin1String("alias")) {
type = QV4::CompiledData::Property::Alias;
typeFound = true;
}
for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
const TypeNameToType *t = propTypeNameToTypes + ii;
- if (t->nameLength == size_t(memberType.length()) &&
- QHashedString::compare(memberType.constData(), t->name, static_cast<int>(t->nameLength))) {
+ if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
type = t->type;
typeFound = true;
}
@@ -702,8 +1039,7 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiPublicMember *node)
if (typeModifier.isEmpty()) {
type = QV4::CompiledData::Property::Custom;
- } else if ((unsigned)typeModifier.length() == strlen("list") &&
- QHashedString::compare(typeModifier.constData(), "list", static_cast<int>(strlen("list")))) {
+ } else if (typeModifier == QLatin1String("list")) {
type = QV4::CompiledData::Property::CustomList;
} else {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
@@ -720,7 +1056,7 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiPublicMember *node)
return false;
}
- QmlProperty *property = New<QmlProperty>();
+ Property *property = New<Property>();
property->flags = 0;
if (node->isReadonlyMember)
property->flags |= QV4::CompiledData::Property::IsReadOnly;
@@ -809,7 +1145,7 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiPublicMember *node)
return false;
}
-bool QQmlCodeGenerator::visit(QQmlJS::AST::UiSourceElement *node)
+bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
{
if (QQmlJS::AST::FunctionDeclaration *funDecl = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration *>(node->sourceElement)) {
CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
@@ -832,7 +1168,7 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiSourceElement *node)
return false;
}
-QString QQmlCodeGenerator::asString(QQmlJS::AST::UiQualifiedId *node)
+QString IRBuilder::asString(QQmlJS::AST::UiQualifiedId *node)
{
QString s;
@@ -846,7 +1182,7 @@ QString QQmlCodeGenerator::asString(QQmlJS::AST::UiQualifiedId *node)
return s;
}
-QStringRef QQmlCodeGenerator::asStringRef(QQmlJS::AST::Node *node)
+QStringRef IRBuilder::asStringRef(QQmlJS::AST::Node *node)
{
if (!node)
return QStringRef();
@@ -854,7 +1190,7 @@ QStringRef QQmlCodeGenerator::asStringRef(QQmlJS::AST::Node *node)
return textRefAt(node->firstSourceLocation(), node->lastSourceLocation());
}
-void QQmlCodeGenerator::extractVersion(QStringRef string, int *maj, int *min)
+void IRBuilder::extractVersion(QStringRef string, int *maj, int *min)
{
*maj = -1; *min = -1;
@@ -872,12 +1208,12 @@ void QQmlCodeGenerator::extractVersion(QStringRef string, int *maj, int *min)
}
}
-QStringRef QQmlCodeGenerator::textRefAt(const QQmlJS::AST::SourceLocation &first, const QQmlJS::AST::SourceLocation &last) const
+QStringRef IRBuilder::textRefAt(const QQmlJS::AST::SourceLocation &first, const QQmlJS::AST::SourceLocation &last) const
{
return QStringRef(&sourceCode, first.offset, last.offset + last.length - first.offset);
}
-void QQmlCodeGenerator::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement)
+void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement)
{
QQmlJS::AST::SourceLocation loc = statement->firstSourceLocation();
binding->valueLocation.line = loc.startLine;
@@ -922,29 +1258,31 @@ void QQmlCodeGenerator::setBindingValue(QV4::CompiledData::Binding *binding, QQm
expr->disableAcceleratedLookups = false;
const int index = bindingsTarget()->functionsAndExpressions->append(expr);
binding->value.compiledScriptIndex = index;
-
- QQmlJS::AST::Node *nodeForString = statement;
- if (exprStmt)
- nodeForString = exprStmt->expression;
- binding->stringIndex = registerString(asStringRef(nodeForString).toString());
+ // We don't need to store the binding script as string, except for script strings
+ // and types with custom parsers. Those will be added later in the compilation phase.
+ binding->stringIndex = emptyStringIndex;
}
}
-void QQmlCodeGenerator::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value)
+void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value)
{
const QQmlJS::AST::SourceLocation qualifiedNameLocation = name->identifierToken;
- QmlObject *object = 0;
+ Object *object = 0;
if (!resolveQualifiedId(&name, &object))
return;
+ if (_object == object && name->name == QStringLiteral("id")) {
+ setId(name->identifierToken, value);
+ return;
+ }
qSwap(_object, object);
appendBinding(qualifiedNameLocation, name->identifierToken, registerString(name->name.toString()), value);
qSwap(_object, object);
}
-void QQmlCodeGenerator::appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment)
+void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment)
{
const QQmlJS::AST::SourceLocation qualifiedNameLocation = name->identifierToken;
- QmlObject *object = 0;
+ Object *object = 0;
if (!resolveQualifiedId(&name, &object, isOnAssignment))
return;
qSwap(_object, object);
@@ -952,13 +1290,8 @@ void QQmlCodeGenerator::appendBinding(QQmlJS::AST::UiQualifiedId *name, int obje
qSwap(_object, object);
}
-void QQmlCodeGenerator::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value)
+void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value)
{
- if (stringAt(propertyNameIndex) == QStringLiteral("id")) {
- setId(nameLocation, value);
- return;
- }
-
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->location.line = nameLocation.startLine;
@@ -971,7 +1304,7 @@ void QQmlCodeGenerator::appendBinding(const QQmlJS::AST::SourceLocation &qualifi
}
}
-void QQmlCodeGenerator::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment)
+void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment)
{
if (stringAt(propertyNameIndex) == QStringLiteral("id")) {
recordError(nameLocation, tr("Invalid component id specification"));
@@ -983,7 +1316,7 @@ void QQmlCodeGenerator::appendBinding(const QQmlJS::AST::SourceLocation &qualifi
binding->location.line = nameLocation.startLine;
binding->location.column = nameLocation.startColumn;
- const QmlObject *obj = _objects.at(objectIndex);
+ const Object *obj = _objects.at(objectIndex);
binding->valueLocation = obj->location;
binding->flags = 0;
@@ -1009,14 +1342,14 @@ void QQmlCodeGenerator::appendBinding(const QQmlJS::AST::SourceLocation &qualifi
}
}
-QmlObject *QQmlCodeGenerator::bindingsTarget() const
+Object *IRBuilder::bindingsTarget() const
{
if (_propertyDeclaration && _object->declarationsOverride)
return _object->declarationsOverride;
return _object;
}
-bool QQmlCodeGenerator::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value)
+bool IRBuilder::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value)
{
QQmlJS::AST::SourceLocation loc = value->firstSourceLocation();
QStringRef str;
@@ -1064,7 +1397,7 @@ bool QQmlCodeGenerator::setId(const QQmlJS::AST::SourceLocation &idLocation, QQm
return true;
}
-bool QQmlCodeGenerator::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, QmlObject **object, bool onAssignment)
+bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, Object **object, bool onAssignment)
{
QQmlJS::AST::UiQualifiedId *qualifiedIdElement = *nameToResolve;
@@ -1074,7 +1407,7 @@ bool QQmlCodeGenerator::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToRe
// 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 (QV4::CompiledData::Import* import, _imports)
+ foreach (const QV4::CompiledData::Import* import, _imports)
if (import->qualifierIndex != emptyStringIndex
&& stringAt(import->qualifierIndex) == currentName) {
qualifiedIdElement = qualifiedIdElement->next;
@@ -1143,55 +1476,15 @@ bool QQmlCodeGenerator::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToRe
return true;
}
-void QQmlCodeGenerator::recordError(const QQmlJS::AST::SourceLocation &location, const QString &description)
+void IRBuilder::recordError(const QQmlJS::AST::SourceLocation &location, const QString &description)
{
- QQmlError error;
- error.setUrl(url);
- error.setLine(location.startLine);
- error.setColumn(location.startColumn);
- error.setDescription(description);
+ QQmlJS::DiagnosticMessage error;
+ error.loc = location;
+ error.message = description;
errors << error;
}
-void QQmlCodeGenerator::collectTypeReferences()
-{
- foreach (QmlObject *obj, _objects) {
- if (obj->inheritedTypeNameIndex != emptyStringIndex) {
- QV4::CompiledData::TypeReference &r = _typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
- r.needsCreation = true;
- r.errorWhenNotFound = true;
- }
-
- for (const QmlProperty *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.needsCreation = true;
- 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);
- }
- }
-}
-
-QQmlScript::LocationSpan QQmlCodeGenerator::location(QQmlJS::AST::SourceLocation start, QQmlJS::AST::SourceLocation end)
-{
- QQmlScript::LocationSpan rv;
- rv.start.line = start.startLine;
- rv.start.column = start.startColumn;
- rv.end.line = end.startLine;
- rv.end.column = end.startColumn + end.length - 1;
- rv.range.offset = start.offset;
- rv.range.length = end.offset + end.length - start.offset;
- return rv;
-}
-
-bool QQmlCodeGenerator::isStatementNodeScript(QQmlJS::AST::Statement *statement)
+bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
{
if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement)) {
QQmlJS::AST::ExpressionNode *expr = stmt->expression;
@@ -1216,19 +1509,19 @@ bool QQmlCodeGenerator::isStatementNodeScript(QQmlJS::AST::Statement *statement)
return true;
}
-QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
+QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(Document &output)
{
- jsUnitGenerator = &output.jsGenerator;
- int unitSize = 0;
- QV4::CompiledData::Unit *jsUnit = jsUnitGenerator->generateUnit(&unitSize);
+ QV4::CompiledData::CompilationUnit *compilationUnit = output.javaScriptCompilationUnit;
+ QV4::CompiledData::Unit *jsUnit = compilationUnit->createUnitData(&output);
+ const uint unitSize = jsUnit->unitSize;
const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count();
const int objectOffsetTableSize = output.objects.count() * sizeof(quint32);
- QHash<QmlObject*, quint32> objectOffsets;
+ QHash<Object*, quint32> objectOffsets;
int objectsSize = 0;
- foreach (QmlObject *o, output.objects) {
+ foreach (Object *o, output.objects) {
objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize);
objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount());
@@ -1242,10 +1535,13 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize;
char *data = (char*)malloc(totalSize);
memcpy(data, jsUnit, unitSize);
- free(jsUnit);
+ if (jsUnit != compilationUnit->data)
+ free(jsUnit);
jsUnit = 0;
QV4::CompiledData::QmlUnit *qmlUnit = reinterpret_cast<QV4::CompiledData::QmlUnit *>(data);
+ qmlUnit->qmlUnitSize = totalSize;
+ qmlUnit->header.flags |= output.unitFlags;
qmlUnit->header.flags |= QV4::CompiledData::Unit::IsQml;
qmlUnit->offsetToImports = unitSize;
qmlUnit->nImports = output.imports.count();
@@ -1255,7 +1551,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
// write imports
char *importPtr = data + qmlUnit->offsetToImports;
- foreach (QV4::CompiledData::Import *imp, output.imports) {
+ foreach (const QV4::CompiledData::Import *imp, output.imports) {
QV4::CompiledData::Import *importToWrite = reinterpret_cast<QV4::CompiledData::Import*>(importPtr);
*importToWrite = *imp;
importPtr += sizeof(QV4::CompiledData::Import);
@@ -1264,7 +1560,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
// write objects
quint32 *objectTable = reinterpret_cast<quint32*>(data + qmlUnit->offsetToObjects);
char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize;
- foreach (QmlObject *o, output.objects) {
+ foreach (Object *o, output.objects) {
*objectTable++ = objectOffsets.value(o);
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
@@ -1297,7 +1593,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
*functionsTable++ = o->runtimeFunctionIndices->at(f->index);
char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
- for (const QmlProperty *p = o->firstProperty(); p; p = p->next) {
+ for (const Property *p = o->firstProperty(); p; p = p->next) {
QV4::CompiledData::Property *propertyToWrite = reinterpret_cast<QV4::CompiledData::Property*>(propertiesPtr);
*propertyToWrite = *p;
propertiesPtr += sizeof(QV4::CompiledData::Property);
@@ -1346,7 +1642,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
return qmlUnit;
}
-char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, BindingFilter filter) const
+char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const
{
for (const Binding *b = o->firstBinding(); b; b = b->next) {
if (!(b->*(filter))())
@@ -1360,13 +1656,8 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, BindingFil
return bindingPtr;
}
-int QmlUnitGenerator::getStringId(const QString &str) const
-{
- return jsUnitGenerator->getStringId(str);
-}
-
-JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, IR::Module *jsModule, QQmlJS::Engine *jsEngine,
- QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QStringList &stringPool)
+JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine,
+ QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool)
: QQmlJS::Codegen(/*strict mode*/false)
, sourceCode(sourceCode)
, jsEngine(jsEngine)
@@ -1434,7 +1725,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
if (function)
name = function->name.toString();
else if (qmlFunction.nameIndex != 0)
- name = stringPool.value(qmlFunction.nameIndex);
+ name = stringPool->stringForIndex(qmlFunction.nameIndex);
else
name = QStringLiteral("%qml-expression-entry");
@@ -1468,6 +1759,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
return runtimeFunctionIndices;
}
+#ifndef V4_BOOTSTRAP
QQmlPropertyData *JSCodeGen::lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup)
{
if (propertyExistsButForceNameLookup)
@@ -1494,7 +1786,7 @@ QQmlPropertyData *JSCodeGen::lookupQmlCompliantProperty(QQmlPropertyCache *cache
return pd;
}
-static void initMetaObjectResolver(IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
enum MetaObjectResolverFlags {
AllPropertiesAreFinal = 0x1,
@@ -1503,11 +1795,11 @@ enum MetaObjectResolverFlags {
ResolveTypeInformationOnly = 0x8
};
-static void initMetaObjectResolver(IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
-static IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, IR::MemberExpressionResolver *resolver, IR::Member *member)
+static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member)
{
- IR::Type result = IR::VarType;
+ QV4::IR::Type result = QV4::IR::VarType;
QQmlType *type = static_cast<QQmlType*>(resolver->data);
@@ -1517,7 +1809,7 @@ static IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, IR::MemberExpressio
if (ok) {
member->setEnumValue(value);
resolver->clear();
- return IR::SInt32Type;
+ return QV4::IR::SInt32Type;
}
}
@@ -1540,7 +1832,7 @@ static IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, IR::MemberExpressio
return result;
}
-static void initQmlTypeResolver(IR::MemberExpressionResolver *resolver, QQmlType *qmlType)
+static void initQmlTypeResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlType *qmlType)
{
resolver->resolveMember = &resolveQmlType;
resolver->data = qmlType;
@@ -1548,9 +1840,9 @@ static void initQmlTypeResolver(IR::MemberExpressionResolver *resolver, QQmlType
resolver->flags = 0;
}
-static IR::Type resolveImportNamespace(QQmlEnginePrivate *, IR::MemberExpressionResolver *resolver, IR::Member *member)
+static QV4::IR::Type resolveImportNamespace(QQmlEnginePrivate *, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member)
{
- IR::Type result = IR::VarType;
+ QV4::IR::Type result = QV4::IR::VarType;
QQmlTypeNameCache *typeNamespace = static_cast<QQmlTypeNameCache*>(resolver->extraData);
void *importNamespace = resolver->data;
@@ -1559,14 +1851,14 @@ static IR::Type resolveImportNamespace(QQmlEnginePrivate *, IR::MemberExpression
member->freeOfSideEffects = true;
if (r.scriptIndex != -1) {
// TODO: remember the index and replace with subscript later.
- result = IR::VarType;
+ result = QV4::IR::VarType;
} else if (r.type) {
// TODO: Propagate singleton information, so that it is loaded
// through the singleton getter in the run-time. Until then we
// can't accelerate access :(
if (!r.type->isSingleton()) {
initQmlTypeResolver(resolver, r.type);
- return IR::QObjectType;
+ return QV4::IR::QObjectType;
}
} else {
Q_ASSERT(false); // How can this happen?
@@ -1577,7 +1869,7 @@ static IR::Type resolveImportNamespace(QQmlEnginePrivate *, IR::MemberExpression
return result;
}
-static void initImportNamespaceResolver(IR::MemberExpressionResolver *resolver, QQmlTypeNameCache *imports, const void *importNamespace)
+static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlTypeNameCache *imports, const void *importNamespace)
{
resolver->resolveMember = &resolveImportNamespace;
resolver->data = const_cast<void*>(importNamespace);
@@ -1585,9 +1877,9 @@ static void initImportNamespaceResolver(IR::MemberExpressionResolver *resolver,
resolver->flags = 0;
}
-static IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, IR::MemberExpressionResolver *resolver, IR::Member *member)
+static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member)
{
- IR::Type result = IR::VarType;
+ QV4::IR::Type result = QV4::IR::VarType;
QQmlPropertyCache *metaObject = static_cast<QQmlPropertyCache*>(resolver->data);
if (member->name->constData()->isUpper() && (resolver->flags & LookupsIncludeEnums)) {
@@ -1600,7 +1892,7 @@ static IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, IR::Memb
if (ok) {
member->setEnumValue(value);
resolver->clear();
- return IR::SInt32Type;
+ return QV4::IR::SInt32Type;
}
}
}
@@ -1633,24 +1925,24 @@ static IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, IR::Memb
// Enums cannot be mapped to IR types, they need to go through the run-time handling
// of accepting strings that will then be converted to the right values.
if (property->isEnum())
- return IR::VarType;
+ return QV4::IR::VarType;
switch (property->propType) {
- case QMetaType::Bool: result = IR::BoolType; break;
- case QMetaType::Int: result = IR::SInt32Type; break;
- case QMetaType::Double: result = IR::DoubleType; break;
- case QMetaType::QString: result = IR::StringType; break;
+ 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)) {
initMetaObjectResolver(resolver, cache);
- return IR::QObjectType;
+ return QV4::IR::QObjectType;
}
} else if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(property->propType)) {
if (QQmlPropertyCache *cache = qmlEngine->cache(valueType->metaObject())) {
initMetaObjectResolver(resolver, cache);
resolver->flags |= ResolveTypeInformationOnly;
- return IR::QObjectType;
+ return QV4::IR::QObjectType;
}
}
break;
@@ -1661,7 +1953,7 @@ static IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, IR::Memb
return result;
}
-static void initMetaObjectResolver(IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject)
+static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject)
{
resolver->resolveMember = &resolveMetaObjectProperty;
resolver->data = metaObject;
@@ -1669,6 +1961,8 @@ static void initMetaObjectResolver(IR::MemberExpressionResolver *resolver, QQmlP
resolver->isQObjectResolver = true;
}
+#endif // V4_BOOTSTRAP
+
void JSCodeGen::beginFunctionBodyHook()
{
_contextObjectTemp = _block->newTemp();
@@ -1676,25 +1970,27 @@ void JSCodeGen::beginFunctionBodyHook()
_importedScriptsTemp = _block->newTemp();
_idArrayTemp = _block->newTemp();
- IR::Temp *temp = _block->TEMP(_contextObjectTemp);
+#ifndef V4_BOOTSTRAP
+ QV4::IR::Temp *temp = _block->TEMP(_contextObjectTemp);
initMetaObjectResolver(&temp->memberResolver, _contextObject);
- move(temp, _block->NAME(IR::Name::builtin_qml_context_object, 0, 0));
+ move(temp, _block->NAME(QV4::IR::Name::builtin_qml_context_object, 0, 0));
temp = _block->TEMP(_scopeObjectTemp);
initMetaObjectResolver(&temp->memberResolver, _scopeObject);
- move(temp, _block->NAME(IR::Name::builtin_qml_scope_object, 0, 0));
+ move(temp, _block->NAME(QV4::IR::Name::builtin_qml_scope_object, 0, 0));
- move(_block->TEMP(_importedScriptsTemp), _block->NAME(IR::Name::builtin_qml_imported_scripts_object, 0, 0));
- move(_block->TEMP(_idArrayTemp), _block->NAME(IR::Name::builtin_qml_id_array, 0, 0));
+ move(_block->TEMP(_importedScriptsTemp), _block->NAME(QV4::IR::Name::builtin_qml_imported_scripts_object, 0, 0));
+ move(_block->TEMP(_idArrayTemp), _block->NAME(QV4::IR::Name::builtin_qml_id_array, 0, 0));
+#endif
}
-IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
+QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
{
- if (_disableAcceleratedLookups)
- return 0;
-
Q_UNUSED(line)
Q_UNUSED(col)
+#ifndef V4_BOOTSTRAP
+ if (_disableAcceleratedLookups)
+ return 0;
// Implement QML lookup semantics in the current file context.
//
// Note: We do not check if properties of the qml scope object or context object
@@ -1710,8 +2006,8 @@ IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
foreach (const IdMapping &mapping, _idObjects)
if (name == mapping.name) {
_function->idObjectDependencies.insert(mapping.idIndex);
- IR::Expr *s = subscript(_block->TEMP(_idArrayTemp), _block->CONST(IR::SInt32Type, mapping.idIndex));
- IR::Temp *result = _block->TEMP(_block->newTemp());
+ QV4::IR::Expr *s = subscript(_block->TEMP(_idArrayTemp), _block->CONST(QV4::IR::SInt32Type, mapping.idIndex));
+ QV4::IR::Temp *result = _block->TEMP(_block->newTemp());
_block->MOVE(result, s);
result = _block->TEMP(result->index);
if (mapping.type) {
@@ -1726,13 +2022,13 @@ IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
QQmlTypeNameCache::Result r = imports->query(name);
if (r.isValid()) {
if (r.scriptIndex != -1) {
- return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(IR::SInt32Type, r.scriptIndex));
+ return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(QV4::IR::SInt32Type, r.scriptIndex));
} else if (r.type) {
- IR::Name *typeName = _block->NAME(name, line, col);
+ QV4::IR::Name *typeName = _block->NAME(name, line, col);
// Make sure the run-time loads this through the more efficient singleton getter.
typeName->qmlSingleton = r.type->isCompositeSingleton();
typeName->freeOfSideEffects = true;
- IR::Temp *result = _block->TEMP(_block->newTemp());
+ QV4::IR::Temp *result = _block->TEMP(_block->newTemp());
_block->MOVE(result, typeName);
result = _block->TEMP(result->index);
@@ -1740,9 +2036,9 @@ IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
return result;
} else {
Q_ASSERT(r.importNamespace);
- IR::Name *namespaceName = _block->NAME(name, line, col);
+ QV4::IR::Name *namespaceName = _block->NAME(name, line, col);
namespaceName->freeOfSideEffects = true;
- IR::Temp *result = _block->TEMP(_block->newTemp());
+ QV4::IR::Temp *result = _block->TEMP(_block->newTemp());
initImportNamespaceResolver(&result->memberResolver, imports, r.importNamespace);
_block->MOVE(result, namespaceName);
@@ -1757,9 +2053,9 @@ IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
if (propertyExistsButForceNameLookup)
return 0;
if (pd) {
- IR::Temp *base = _block->TEMP(_scopeObjectTemp);
+ QV4::IR::Temp *base = _block->TEMP(_scopeObjectTemp);
initMetaObjectResolver(&base->memberResolver, _scopeObject);
- return _block->MEMBER(base, _function->newString(name), pd, IR::Member::MemberOfQmlScopeObject);
+ return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlScopeObject);
}
}
@@ -1769,16 +2065,21 @@ IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
if (propertyExistsButForceNameLookup)
return 0;
if (pd) {
- IR::Temp *base = _block->TEMP(_contextObjectTemp);
+ QV4::IR::Temp *base = _block->TEMP(_contextObjectTemp);
initMetaObjectResolver(&base->memberResolver, _contextObject);
- return _block->MEMBER(base, _function->newString(name), pd, IR::Member::MemberOfQmlContextObject);
+ return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlContextObject);
}
}
+#else
+ Q_UNUSED(name)
+#endif // V4_BOOTSTRAP
// fall back to name lookup at run-time.
return 0;
}
+#ifndef V4_BOOTSTRAP
+
QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, QObject *object, QQmlContextData *context)
{
if (notInRevision) *notInRevision = false;
@@ -1825,3 +2126,5 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis
return 0;
}
+
+#endif // V4_BOOTSTRAP
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 583f8e1ed5..3438af425c 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -38,12 +38,11 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QQMLCODEGENERATOR_P_H
-#define QQMLCODEGENERATOR_P_H
+#ifndef QQMLIRBUILDER_P_H
+#define QQMLIRBUILDER_P_H
#include <private/qqmljsast_p.h>
#include <private/qqmlpool_p.h>
-#include <private/qqmlscript_p.h>
#include <private/qqmljsengine_p.h>
#include <private/qv4compiler_p.h>
#include <private/qv4compileddata_p.h>
@@ -53,32 +52,20 @@
#include <QTextStream>
#include <QCoreApplication>
+#ifndef V4_BOOTSTRAP
+#include <private/qqmlpropertycache_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
+class QQmlPropertyCache;
+class QQmlContextData;
class QQmlTypeNameCache;
-namespace QtQml {
-
-using namespace QV4;
+namespace QmlIR {
-struct DebugStream
-{
- DebugStream(QTextStream &stream)
- : stream(stream)
- , indent(0)
- {}
-
- template <typename T>
- QTextStream &operator<<(const T &value)
- {
- return stream << QByteArray(indent * 4, ' ') << value;
- }
-
- QTextStream &noindent() { return stream; }
-
- QTextStream &stream;
- int indent;
-};
+struct Document;
+struct IRLoader;
template <typename T>
struct PoolList
@@ -206,7 +193,7 @@ public:
}
};
-struct QmlObject;
+struct Object;
struct SignalParameter : public QV4::CompiledData::Parameter
{
@@ -219,14 +206,14 @@ struct Signal
QV4::CompiledData::Location location;
PoolList<SignalParameter> *parameters;
- QStringList parameterStringList(const QStringList &stringPool) const;
+ QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const;
Signal *next;
};
-struct QmlProperty : public QV4::CompiledData::Property
+struct Property : public QV4::CompiledData::Property
{
- QmlProperty *next;
+ Property *next;
};
struct Binding : public QV4::CompiledData::Binding
@@ -244,7 +231,7 @@ struct Function
Function *next;
};
-struct CompiledFunctionOrExpression
+struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
{
CompiledFunctionOrExpression()
: node(0)
@@ -264,9 +251,9 @@ struct CompiledFunctionOrExpression
CompiledFunctionOrExpression *next;
};
-struct QmlObject
+struct Q_QML_PRIVATE_EXPORT Object
{
- Q_DECLARE_TR_FUNCTIONS(QmlObject)
+ Q_DECLARE_TR_FUNCTIONS(Object)
public:
quint32 inheritedTypeNameIndex;
quint32 idIndex;
@@ -275,7 +262,7 @@ public:
QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty;
- const QmlProperty *firstProperty() const { return properties->first; }
+ const Property *firstProperty() const { return properties->first; }
int propertyCount() const { return properties->count; }
const Signal *firstSignal() const { return qmlSignals->first; }
int signalCount() const { return qmlSignals->count; }
@@ -286,34 +273,35 @@ public:
// If set, then declarations for this object (and init bindings for these) should go into the
// specified object. Used for declarations inside group properties.
- QmlObject *declarationsOverride;
+ Object *declarationsOverride;
void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation());
- void dump(DebugStream &out);
-
QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
QString appendSignal(Signal *signal);
- QString appendProperty(QmlProperty *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
- void appendFunction(QtQml::Function *f);
+ QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
+ void appendFunction(QmlIR::Function *f);
QString appendBinding(Binding *b, bool isListBinding);
Binding *findBinding(quint32 nameIndex) const;
Binding *unlinkBinding(Binding *before, Binding *binding) { return bindings->unlink(before, binding); }
void insertSorted(Binding *b);
+ QString bindingAsString(Document *doc, int scriptIndex) const;
PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
FixedPoolArray<int> *runtimeFunctionIndices;
private:
- PoolList<QmlProperty> *properties;
+ friend struct IRLoader;
+
+ PoolList<Property> *properties;
PoolList<Signal> *qmlSignals;
PoolList<Binding> *bindings;
PoolList<Function> *functions;
};
-struct Pragma
+struct Q_QML_PRIVATE_EXPORT Pragma
{
enum PragmaType {
PragmaSingleton = 0x1
@@ -323,34 +311,39 @@ struct Pragma
QV4::CompiledData::Location location;
};
-struct ParsedQML
+struct Q_QML_PRIVATE_EXPORT Document
{
- ParsedQML(bool debugMode)
- : jsModule(debugMode)
- , jsGenerator(&jsModule, sizeof(QV4::CompiledData::QmlUnit))
- {}
+ Document(bool debugMode);
QString code;
QQmlJS::Engine jsParserEngine;
QV4::IR::Module jsModule;
- QList<QV4::CompiledData::Import*> imports;
+ QList<const QV4::CompiledData::Import *> imports;
QList<Pragma*> pragmas;
QQmlJS::AST::UiProgram *program;
int indexOfRootObject;
- QList<QmlObject*> objects;
+ QList<Object*> objects;
QV4::Compiler::JSUnitGenerator jsGenerator;
+ quint32 unitFlags;
+
+ QV4::CompiledData::CompilationUnit *javaScriptCompilationUnit;
+ QHash<int, QStringList> extraSignalParameters;
QV4::CompiledData::TypeReferenceMap typeReferences;
+ void collectTypeReferences();
- QString stringAt(int index) const { return jsGenerator.strings.value(index); }
+ int registerString(const QString &str) { return jsGenerator.registerString(str); }
+ QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
+
+ void extractScriptMetaData(QString &script, QQmlJS::DiagnosticMessage *error);
+ static void removeScriptPragmas(QString &script);
};
-// Doesn't really generate code per-se, but more the data structure
-struct Q_QML_EXPORT QQmlCodeGenerator : public QQmlJS::AST::Visitor
+struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
{
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
public:
- QQmlCodeGenerator(const QSet<QString> &illegalNames);
- bool generateFromQml(const QString &code, const QUrl &url, const QString &urlString, ParsedQML *output);
+ IRBuilder(const QSet<QString> &illegalNames);
+ bool generateFromQml(const QString &code, const QString &url, const QString &urlString, Document *output);
static bool isSignalPropertyName(const QString &name);
@@ -376,8 +369,8 @@ public:
void accept(QQmlJS::AST::Node *node);
// returns index in _objects
- bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, QmlObject *declarationsOverride = 0);
- bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiObjectDefinition *node, QmlObject *declarationsOverride = 0)
+ bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride = 0);
+ bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiObjectDefinition *node, Object *declarationsOverride = 0)
{ return defineQMLObject(objectIndex, node->qualifiedTypeNameId, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer, declarationsOverride); }
static QString asString(QQmlJS::AST::UiQualifiedId *node);
@@ -387,10 +380,6 @@ public:
{ return QStringRef(&sourceCode, loc.offset, loc.length); }
QStringRef textRefAt(const QQmlJS::AST::SourceLocation &first,
const QQmlJS::AST::SourceLocation &last) const;
- static QQmlScript::LocationSpan location(QQmlJS::AST::UiQualifiedId *id)
- {
- return location(id->identifierToken, id->identifierToken);
- }
void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement);
@@ -399,65 +388,53 @@ public:
void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value);
void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
- QmlObject *bindingsTarget() const;
+ Object *bindingsTarget() const;
bool setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value);
// resolves qualified name (font.pixelSize for example) and returns the last name along
// with the object any right-hand-side of a binding should apply to.
- bool resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, QmlObject **object, bool onAssignment = false);
+ bool resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, Object **object, bool onAssignment = false);
void recordError(const QQmlJS::AST::SourceLocation &location, const QString &description);
- void collectTypeReferences();
-
- static QQmlScript::LocationSpan location(QQmlJS::AST::SourceLocation start, QQmlJS::AST::SourceLocation end);
-
quint32 registerString(const QString &str) const { return jsGenerator->registerString(str); }
template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
- QString stringAt(int index) const { return jsGenerator->strings.at(index); }
+ QString stringAt(int index) const { return jsGenerator->stringForIndex(index); }
static bool isStatementNodeScript(QQmlJS::AST::Statement *statement);
- QList<QQmlError> errors;
+ QList<QQmlJS::DiagnosticMessage> errors;
QSet<QString> illegalNames;
- QList<QV4::CompiledData::Import*> _imports;
+ QList<const QV4::CompiledData::Import *> _imports;
QList<Pragma*> _pragmas;
- QList<QmlObject*> _objects;
+ QList<Object*> _objects;
QV4::CompiledData::TypeReferenceMap _typeReferences;
- QmlObject *_object;
- QmlProperty *_propertyDeclaration;
+ Object *_object;
+ Property *_propertyDeclaration;
QQmlJS::MemoryPool *pool;
QString sourceCode;
- QUrl url;
+ QString url;
QV4::Compiler::JSUnitGenerator *jsGenerator;
};
-struct Q_QML_EXPORT QmlUnitGenerator
+struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
{
- QmlUnitGenerator()
- : jsUnitGenerator(0)
- {
- }
-
- QV4::CompiledData::QmlUnit *generate(ParsedQML &output);
+ QV4::CompiledData::QmlUnit *generate(Document &output);
private:
typedef bool (Binding::*BindingFilter)() const;
- char *writeBindings(char *bindingPtr, QmlObject *o, BindingFilter filter) const;
-
- int getStringId(const QString &str) const;
-
- QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
+ char *writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const;
};
-struct PropertyResolver
+#ifndef V4_BOOTSTRAP
+struct Q_QML_EXPORT PropertyResolver
{
PropertyResolver(QQmlPropertyCache *cache)
: cache(cache)
@@ -475,12 +452,13 @@ struct PropertyResolver
QQmlPropertyCache *cache;
};
+#endif
-struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
+struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QQmlJS::Codegen
{
- JSCodeGen(const QString &fileName, const QString &sourceCode, IR::Module *jsModule,
+ JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule,
QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports,
- const QStringList &stringPool);
+ const QV4::Compiler::StringTableGenerator *stringPool);
struct IdMapping
{
@@ -498,7 +476,7 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
protected:
virtual void beginFunctionBodyHook();
- virtual IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
+ virtual QV4::IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
private:
QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup = 0);
@@ -507,7 +485,7 @@ private:
QQmlJS::Engine *jsEngine; // needed for memory pool
QQmlJS::AST::UiProgram *qmlRoot;
QQmlTypeNameCache *imports;
- const QStringList &stringPool;
+ const QV4::Compiler::StringTableGenerator *stringPool;
bool _disableAcceleratedLookups;
ObjectIdMapping _idObjects;
@@ -519,8 +497,8 @@ private:
int _idArrayTemp;
};
-} // namespace QtQml
+} // namespace QmlIR
QT_END_NAMESPACE
-#endif // QQMLCODEGENERATOR_P_H
+#endif // QQMLIRBUILDER_P_H
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 0920b447d8..ede150c67b 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -41,7 +41,7 @@
#include "qqmltypecompiler_p.h"
-#include <private/qqmlcompiler_p.h>
+#include <private/qqmlirbuilder_p.h>
#include <private/qqmlobjectcreator_p.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlvmemetaobject_p.h>
@@ -57,11 +57,11 @@
QT_BEGIN_NAMESPACE
-QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QtQml::ParsedQML *parsedQML)
+QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QmlIR::Document *parsedQML)
: engine(engine)
, compiledData(compiledData)
, typeData(typeData)
- , parsedQML(parsedQML)
+ , document(parsedQML)
{
}
@@ -77,7 +77,6 @@ bool QQmlTypeCompiler::compile()
compiledData->importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
typeData->imports().populateCache(compiledData->importCache);
- compiledData->importCache->addref();
const QHash<int, QQmlTypeData::TypeReference> &resolvedTypes = typeData->resolvedTypeRefs();
for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
@@ -141,8 +140,8 @@ bool QQmlTypeCompiler::compile()
customParsers.insert(it.key(), customParser);
}
- compiledData->datas.reserve(parsedQML->objects.count());
- compiledData->propertyCaches.reserve(parsedQML->objects.count());
+ compiledData->metaObjects.reserve(document->objects.count());
+ compiledData->propertyCaches.reserve(document->objects.count());
{
QQmlPropertyCacheCreator propertyCacheBuilder(this);
@@ -168,6 +167,11 @@ bool QQmlTypeCompiler::compile()
}
{
+ QQmlCustomParserScriptIndexer cpi(this);
+ cpi.annotateBindingsWithScriptStrings();
+ }
+
+ {
QQmlAliasAnnotator annotator(this);
annotator.annotateBindingsToAliases();
}
@@ -203,37 +207,39 @@ bool QQmlTypeCompiler::compile()
}
// Compile JS binding expressions and signal handlers
- {
- QtQml::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, compiledData->importCache, parsedQML->jsGenerator.strings);
+ if (!document->javaScriptCompilationUnit) {
+ {
+ // We can compile script strings ahead of time, but they must be compiled
+ // without type optimizations as their scope is always entirely dynamic.
+ QQmlScriptStringScanner sss(this);
+ sss.scan();
+ }
+
+ QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, compiledData->importCache, &document->jsGenerator.stringTable);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
return false;
- }
- {
QQmlJavaScriptBindingExpressionSimplificationPass pass(this);
pass.reduceTranslationBindings();
- }
- QV4::ExecutionEngine *v4 = engine->v4engine();
-
- QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(engine, v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator));
- isel->setUseFastLookups(false);
- QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false);
+ QV4::ExecutionEngine *v4 = engine->v4engine();
+ QScopedPointer<QV4::EvalInstructionSelection> isel(v4->iselFactory->create(engine, v4->executableAllocator, &document->jsModule, &document->jsGenerator));
+ isel->setUseFastLookups(false);
+ document->javaScriptCompilationUnit = isel->compile(/*generated unit data*/false);
+ }
// Generate QML compiled type data structures
- QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML);
+ QmlIR::QmlUnitGenerator qmlGenerator;
+ QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*document);
- if (jsUnit) {
- Q_ASSERT(!jsUnit->data);
- Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
- // The js unit owns the data and will free the qml unit.
- jsUnit->data = &qmlUnit->header;
- }
+ Q_ASSERT(document->javaScriptCompilationUnit);
+ Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
+ // The js unit owns the data and will free the qml unit.
+ document->javaScriptCompilationUnit->data = &qmlUnit->header;
- compiledData->compilationUnit = jsUnit;
+ compiledData->compilationUnit = document->javaScriptCompilationUnit;
if (compiledData->compilationUnit)
compiledData->compilationUnit->ref();
compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData
@@ -284,6 +290,8 @@ bool QQmlTypeCompiler::compile()
compiledData->totalParserStatusCount = parserStatusCount;
compiledData->totalObjectCount = objectCount;
+ Q_ASSERT(compiledData->propertyCaches.count() == static_cast<int>(compiledData->qmlUnit->nObjects));
+
return errors.isEmpty();
}
@@ -296,17 +304,17 @@ void QQmlTypeCompiler::recordError(const QQmlError &error)
QString QQmlTypeCompiler::stringAt(int idx) const
{
- return parsedQML->stringAt(idx);
+ return document->stringAt(idx);
}
int QQmlTypeCompiler::registerString(const QString &str)
{
- return parsedQML->jsGenerator.registerString(str);
+ return document->jsGenerator.registerString(str);
}
QV4::IR::Module *QQmlTypeCompiler::jsIRModule() const
{
- return &parsedQML->jsModule;
+ return &document->jsModule;
}
const QV4::CompiledData::QmlUnit *QQmlTypeCompiler::qmlUnit() const
@@ -324,22 +332,23 @@ QHash<int, QQmlCompiledData::TypeReference*> *QQmlTypeCompiler::resolvedTypes()
return &compiledData->resolvedTypes;
}
-QList<QmlObject *> *QQmlTypeCompiler::qmlObjects()
+QList<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects()
{
- return &parsedQML->objects;
+ return &document->objects;
}
int QQmlTypeCompiler::rootObjectIndex() const
{
- return parsedQML->indexOfRootObject;
+ return document->indexOfRootObject;
}
void QQmlTypeCompiler::setPropertyCaches(const QVector<QQmlPropertyCache *> &caches)
{
- Q_ASSERT(compiledData->propertyCaches.isEmpty());
compiledData->propertyCaches = caches;
- Q_ASSERT(caches.count() >= parsedQML->indexOfRootObject);
- compiledData->rootPropertyCache = caches.at(parsedQML->indexOfRootObject);
+ Q_ASSERT(caches.count() >= document->indexOfRootObject);
+ if (compiledData->rootPropertyCache)
+ compiledData->rootPropertyCache->release();
+ compiledData->rootPropertyCache = caches.at(document->indexOfRootObject);
compiledData->rootPropertyCache->addref();
}
@@ -350,13 +359,13 @@ const QVector<QQmlPropertyCache *> &QQmlTypeCompiler::propertyCaches() const
void QQmlTypeCompiler::setVMEMetaObjects(const QVector<QByteArray> &metaObjects)
{
- Q_ASSERT(compiledData->datas.isEmpty());
- compiledData->datas = metaObjects;
+ Q_ASSERT(compiledData->metaObjects.isEmpty());
+ compiledData->metaObjects = metaObjects;
}
QVector<QByteArray> *QQmlTypeCompiler::vmeMetaObjects() const
{
- return &compiledData->datas;
+ return &compiledData->metaObjects;
}
QHash<int, int> *QQmlTypeCompiler::objectIndexToIdForRoot()
@@ -376,17 +385,17 @@ QHash<int, QQmlCompiledData::CustomParserData> *QQmlTypeCompiler::customParserDa
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
{
- return parsedQML->jsParserEngine.pool();
+ return document->jsParserEngine.pool();
}
QStringRef QQmlTypeCompiler::newStringRef(const QString &string)
{
- return parsedQML->jsParserEngine.newStringRef(string);
+ return document->jsParserEngine.newStringRef(string);
}
-const QStringList &QQmlTypeCompiler::stringPool() const
+const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
{
- return parsedQML->jsGenerator.strings;
+ return &document->jsGenerator.stringTable;
}
void QQmlTypeCompiler::setCustomParserBindings(const QVector<int> &bindings)
@@ -399,6 +408,11 @@ void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray>
compiledData->deferredBindingsPerObject = deferredBindingsPerObject;
}
+QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
+{
+ return object->bindingAsString(document, scriptIndex);
+}
+
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
: compiler(typeCompiler)
{
@@ -449,7 +463,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjects()
bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding)
{
- const QmlObject *obj = qmlObjects.at(objectIndex);
+ const QmlIR::Object *obj = qmlObjects.at(objectIndex);
QQmlPropertyCache *baseTypeCache = 0;
QQmlPropertyData *instantiatingProperty = 0;
@@ -460,7 +474,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
bool notInRevision = false;
- instantiatingProperty = PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
+ instantiatingProperty = QmlIR::PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
if (instantiatingProperty) {
if (instantiatingProperty->isQObject()) {
baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType);
@@ -474,7 +488,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
if (!needVMEMetaObject) {
- for (const QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ 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.
@@ -536,7 +550,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
}
if (propertyCaches.at(objectIndex)) {
- for (const QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next)
+ 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;
@@ -550,14 +564,14 @@ bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex)
{
if (!vmeMetaObjects.at(objectIndex).isEmpty())
return true;
- const QtQml::QmlObject *obj = qmlObjects.at(objectIndex);
+ 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 QtQml::QmlObject *obj, QQmlPropertyCache *baseTypeCache)
+bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache)
{
QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate),
obj->propertyCount(),
@@ -615,9 +629,9 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
int aliasCount = 0;
int varPropCount = 0;
- PropertyResolver resolver(baseTypeCache);
+ QmlIR::PropertyResolver resolver(baseTypeCache);
- for (const QtQml::QmlProperty *p = obj->firstProperty(); p; p = p->next) {
+ for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
if (p->type == QV4::CompiledData::Property::Alias)
aliasCount++;
else if (p->type == QV4::CompiledData::Property::Var)
@@ -670,7 +684,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
if (ii == NSS_Var && varPropCount == 0) continue;
else if (ii == NSS_Alias && aliasCount == 0) continue;
- for (const QtQml::QmlProperty *p = obj->firstProperty(); p; p = p->next) {
+ for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias ||
p->type == QV4::CompiledData::Property::Var)) ||
((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) ||
@@ -688,7 +702,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
}
// Dynamic signals
- for (const QtQml::Signal *s = obj->firstSignal(); s; s = s->next) {
+ for (const QmlIR::Signal *s = obj->firstSignal(); s; s = s->next) {
const int paramCount = s->parameters->count;
QList<QByteArray> names;
@@ -697,7 +711,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
if (paramCount) {
paramTypes[0] = paramCount;
- QtQml::SignalParameter *param = s->parameters->first;
+ 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) {
@@ -746,7 +760,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
// Dynamic slots
- for (const QtQml::Function *s = obj->firstFunction(); s; s = s->next) {
+ for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) {
QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration;
quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
@@ -774,7 +788,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
// Dynamic properties (except var and aliases)
int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
int propertyIdx = 0;
- for (const QtQml::QmlProperty *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
+ for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
if (p->type == QV4::CompiledData::Property::Alias ||
p->type == QV4::CompiledData::Property::Var)
@@ -850,7 +864,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
// Now do var properties
propertyIdx = 0;
- for (const QtQml::QmlProperty *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
+ for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
if (p->type != QV4::CompiledData::Property::Var)
continue;
@@ -876,7 +890,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm
((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
// Dynamic slot data - comes after the property data
- for (const QtQml::Function *s = obj->firstFunction(); s; s = s->next) {
+ for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) {
QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration;
int formalsCount = 0;
QQmlJS::AST::FormalParameterList *param = astFunction->formals;
@@ -911,7 +925,7 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations()
{
for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) {
- const QmlObject * const obj = qmlObjects.at(objectIndex);
+ const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
QQmlPropertyCache *cache = propertyCaches.at(objectIndex);
if (!cache)
continue;
@@ -926,16 +940,16 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
return true;
}
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(const QmlObject *obj, const QString &typeName, QQmlPropertyCache *propertyCache)
+bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache)
{
// map from signal name defined in qml itself to list of parameters
QHash<QString, QStringList> customSignals;
- for (Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
QString propertyName = stringAt(binding->propertyNameIndex);
// Attached property?
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- const QmlObject *attachedObj = qmlObjects.at(binding->value.objectIndex);
+ const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(binding->propertyNameIndex);
QQmlType *type = typeRef ? typeRef->type : 0;
const QMetaObject *attachedType = type ? type->attachedPropertiesType() : 0;
@@ -947,10 +961,10 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
continue;
}
- if (!QQmlCodeGenerator::isSignalPropertyName(propertyName))
+ if (!QmlIR::IRBuilder::isSignalPropertyName(propertyName))
continue;
- PropertyResolver resolver(propertyCache);
+ QmlIR::PropertyResolver resolver(propertyCache);
Q_ASSERT(propertyName.startsWith(QStringLiteral("on")));
propertyName.remove(0, 2);
@@ -1007,12 +1021,12 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
// build cache if necessary
if (customSignals.isEmpty()) {
- for (const Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
+ for (const QmlIR::Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
const QString &signalName = stringAt(signal->nameIndex);
customSignals.insert(signalName, signal->parameterStringList(compiler->stringPool()));
}
- for (const QmlProperty *property = obj->firstProperty(); property; property = property->next) {
+ for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
const QString propName = stringAt(property->nameIndex);
customSignals.insert(propName, QStringList());
}
@@ -1062,7 +1076,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
if (paramList)
paramList = paramList->finish();
- CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
+ QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
QQmlJS::AST::SourceElement *sourceElement = new (pool) QQmlJS::AST::StatementSourceElement(statement);
QQmlJS::AST::SourceElements *elements = new (pool) QQmlJS::AST::SourceElements(sourceElement);
@@ -1095,11 +1109,11 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
QQmlPropertyCache *propertyCache = propertyCaches.at(i);
if (!propertyCache)
continue;
- const QmlObject *obj = qmlObjects.at(i);
+ const QmlIR::Object *obj = qmlObjects.at(i);
- PropertyResolver resolver(propertyCache);
+ QmlIR::PropertyResolver resolver(propertyCache);
- for (QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
|| binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
continue;
@@ -1130,7 +1144,7 @@ struct StaticQtMetaObject : public QObject
{ return &staticQtMetaObject; }
};
-bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlObject *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, Binding *binding)
+bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding)
{
bool isIntProp = (prop->propType == QMetaType::Int) && !prop->isEnum();
if (!prop->isEnum() && !isIntProp)
@@ -1140,8 +1154,8 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlObject *obj, cons
COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
Q_ASSERT(binding->type = QV4::CompiledData::Binding::Type_Script);
- QString string = stringAt(binding->stringIndex);
- if (!string.at(0).isUpper())
+ const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
+ if (!string.constData()->isUpper())
return true;
int dot = string.indexOf(QLatin1Char('.'));
@@ -1230,6 +1244,35 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e
return -1;
}
+QQmlCustomParserScriptIndexer::QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
+ : QQmlCompilePass(typeCompiler)
+ , qmlObjects(*typeCompiler->qmlObjects())
+ , customParsers(typeCompiler->customParserCache())
+{
+}
+
+void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings()
+{
+ scanObjectRecursively(compiler->rootObjectIndex());
+}
+
+void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
+{
+ const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
+ if (!annotateScriptBindings)
+ annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
+ continue;
+ } else if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ continue;
+ if (!annotateScriptBindings)
+ continue;
+ const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
+ binding->stringIndex = compiler->registerString(script);
+ }
+}
QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
@@ -1245,12 +1288,12 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
if (!propertyCache)
continue;
- const QmlObject *obj = qmlObjects.at(i);
+ const QmlIR::Object *obj = qmlObjects.at(i);
- PropertyResolver resolver(propertyCache);
+ QmlIR::PropertyResolver resolver(propertyCache);
QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
- for (QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (!binding->isValueBinding())
continue;
bool notInRevision = false;
@@ -1261,6 +1304,45 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
}
}
+QQmlScriptStringScanner::QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
+ : QQmlCompilePass(typeCompiler)
+ , qmlObjects(*typeCompiler->qmlObjects())
+ , propertyCaches(typeCompiler->propertyCaches())
+{
+
+}
+
+void QQmlScriptStringScanner::scan()
+{
+ const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>();
+ for (int i = 0; i < qmlObjects.count(); ++i) {
+ QQmlPropertyCache *propertyCache = propertyCaches.at(i);
+ if (!propertyCache)
+ continue;
+
+ const QmlIR::Object *obj = qmlObjects.at(i);
+
+ QmlIR::PropertyResolver resolver(propertyCache);
+ QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ 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)
+ continue;
+
+ QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
+ if (foe)
+ foe->disableAcceleratedLookups = true;
+
+ QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
+ binding->stringIndex = compiler->registerString(script);
+ }
+ }
+}
+
QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, enginePrivate(typeCompiler->enginePrivate())
@@ -1277,19 +1359,19 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
{
}
-void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQml::QmlObject *obj, QQmlPropertyCache *propertyCache)
+void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache)
{
- PropertyResolver propertyResolver(propertyCache);
+ QmlIR::PropertyResolver propertyResolver(propertyCache);
QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
- for (QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object)
continue;
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
continue;
- const QtQml::QmlObject *targetObject = qmlObjects->at(binding->value.objectIndex);
+ const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
QQmlCompiledData::TypeReference *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
Q_ASSERT(tr);
if (QQmlType *targetType = tr->type) {
@@ -1324,8 +1406,9 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQm
static QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
Q_ASSERT(componentType);
- QtQml::QmlObject *syntheticComponent = pool->New<QtQml::QmlObject>();
+ QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
+ syntheticComponent->location = binding->valueLocation;
if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference;
@@ -1337,8 +1420,12 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQm
qmlObjects->append(syntheticComponent);
const int componentIndex = qmlObjects->count() - 1;
+ // Keep property caches symmetric
+ QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject);
+ componentCache->addref();
+ propertyCaches.append(componentCache);
- QtQml::Binding *syntheticBinding = pool->New<QtQml::Binding>();
+ QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
*syntheticBinding = *binding;
syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
@@ -1360,8 +1447,8 @@ bool QQmlComponentAndAliasResolver::resolve()
// on the left hand side is of QQmlComponent type.
const int objCountWithoutSynthesizedComponents = qmlObjects->count();
for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
- const QtQml::QmlObject *obj = qmlObjects->at(i);
- QQmlPropertyCache *cache = propertyCaches.value(i);
+ const QmlIR::Object *obj = qmlObjects->at(i);
+ QQmlPropertyCache *cache = propertyCaches.at(i);
if (obj->inheritedTypeNameIndex == 0 && !cache)
continue;
@@ -1374,7 +1461,8 @@ bool QQmlComponentAndAliasResolver::resolve()
isExplicitComponent = true;
}
if (!isExplicitComponent) {
- findAndRegisterImplicitComponents(obj, cache);
+ if (cache)
+ findAndRegisterImplicitComponents(obj, cache);
continue;
}
@@ -1390,9 +1478,9 @@ bool QQmlComponentAndAliasResolver::resolve()
if (obj->bindingCount() == 0)
COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
- const QtQml::Binding *rootBinding = obj->firstBinding();
+ const QmlIR::Binding *rootBinding = obj->firstBinding();
- for (const QtQml::Binding *b = rootBinding; b; b = b->next) {
+ for (const QmlIR::Binding *b = rootBinding; b; b = b->next) {
if (b->propertyNameIndex != 0)
COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
}
@@ -1406,8 +1494,8 @@ bool QQmlComponentAndAliasResolver::resolve()
std::sort(componentBoundaries.begin(), componentBoundaries.end());
for (int i = 0; i < componentRoots.count(); ++i) {
- const QtQml::QmlObject *component = qmlObjects->at(componentRoots.at(i));
- const QtQml::Binding *rootBinding = component->firstBinding();
+ const QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
+ const QmlIR::Binding *rootBinding = component->firstBinding();
_componentIndex = i;
_idToObjectIndex.clear();
@@ -1433,12 +1521,16 @@ bool QQmlComponentAndAliasResolver::resolve()
resolveAliases();
+ // Implicit component insertion may have added objects and thus we also need
+ // to extend the symmetric propertyCaches.
+ compiler->setPropertyCaches(propertyCaches);
+
return true;
}
bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
{
- const QtQml::QmlObject *obj = qmlObjects->at(objectIndex);
+ const QmlIR::Object *obj = qmlObjects->at(objectIndex);
if (obj->idIndex != 0) {
if (_idToObjectIndex.contains(obj->idIndex)) {
@@ -1449,14 +1541,14 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
_objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
}
- for (const QtQml::QmlProperty *property = obj->firstProperty(); property; property = property->next) {
+ for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
if (property->type == QV4::CompiledData::Property::Alias) {
_objectsWithAliases.append(objectIndex);
break;
}
}
- for (const QtQml::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object
&& binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
@@ -1476,16 +1568,16 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
bool QQmlComponentAndAliasResolver::resolveAliases()
{
foreach (int objectIndex, _objectsWithAliases) {
- const QtQml::QmlObject *obj = qmlObjects->at(objectIndex);
+ const QmlIR::Object *obj = qmlObjects->at(objectIndex);
- QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex);
+ QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
Q_ASSERT(propertyCache);
int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
int effectiveAliasIndex = 0;
- const QtQml::QmlProperty *p = obj->firstProperty();
+ const QmlIR::Property *p = obj->firstProperty();
for (int propertyIndex = 0; propertyIndex < obj->propertyCount(); ++propertyIndex, p = p->next) {
if (p->type != QV4::CompiledData::Property::Alias)
continue;
@@ -1522,7 +1614,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
quint32 propertyFlags = QQmlPropertyData::IsAlias;
if (property.isEmpty()) {
- const QtQml::QmlObject *targetObject = qmlObjects->at(targetObjectIndex);
+ const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
@@ -1534,9 +1626,9 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
flags |= QML_ALIAS_FLAG_PTR;
propertyFlags |= QQmlPropertyData::IsQObjectDerived;
} else {
- QQmlPropertyCache *targetCache = propertyCaches.value(targetObjectIndex);
+ QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
Q_ASSERT(targetCache);
- QtQml::PropertyResolver resolver(targetCache);
+ QmlIR::PropertyResolver resolver(targetCache);
QQmlPropertyData *targetProperty = resolver.property(property.toString());
if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
@@ -1647,17 +1739,6 @@ const QQmlImports &QQmlPropertyValidator::imports() const
return *compiler->imports();
}
-QQmlJS::AST::Node *QQmlPropertyValidator::astForBinding(int objectIndex, int scriptIndex) const
-{
- const QtQml::QmlObject *obj = compiler->qmlObjects()->at(objectIndex);
- // ####
- int reverseIndex = obj->runtimeFunctionIndices->indexOf(scriptIndex);
- if (reverseIndex == -1)
- return 0;
- QtQml::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(reverseIndex);
- return foe ? foe->node : 0;
-}
-
QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *)
{
const int id = customParserBindings.count();
@@ -1665,8 +1746,24 @@ QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::Comp
return id;
}
+QString QQmlPropertyValidator::bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const
+{
+ const QmlIR::Object *object = compiler->qmlObjects()->value(objectIndex);
+ if (!object)
+ return QString();
+ int reverseIndex = object->runtimeFunctionIndices->indexOf(binding->value.compiledScriptIndex);
+ if (reverseIndex == -1)
+ return QString();
+ return compiler->bindingAsString(object, reverseIndex);
+}
+
typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector;
+static bool compareNameIndices(const QV4::CompiledData::Binding *binding, quint32 name)
+{
+ return binding->propertyNameIndex < name;
+}
+
bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty)
{
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
@@ -1697,12 +1794,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
QList<const QV4::CompiledData::Binding*> customBindings;
- struct GroupPropertyFinder {
- bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const {
- return binding->propertyNameIndex < name;
- }
- };
-
// Collect group properties first for sanity checking
// vector values are sorted by property name string index.
GroupPropertyVector groupProperties;
@@ -1719,14 +1810,14 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
return false;
}
- GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, GroupPropertyFinder());
+ GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, compareNameIndices);
groupProperties.insert(pos, binding);
}
QBitArray customParserBindings(obj->nBindings);
QBitArray deferredBindings;
- PropertyResolver propertyResolver(propertyCache);
+ QmlIR::PropertyResolver propertyResolver(propertyCache);
QString defaultPropertyName;
QQmlPropertyData *defaultProperty = 0;
@@ -1750,16 +1841,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
customParserBindings.setBit(i);
continue;
}
- } else if (QQmlCodeGenerator::isSignalPropertyName(name)
+ } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
customBindings << binding;
customParserBindings.setBit(i);
continue;
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object
- || binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
- customBindings << binding;
- customParserBindings.setBit(i);
- continue;
}
}
@@ -1810,7 +1896,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
bool seenSubObjectWithId = false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object && !customParser) {
qSwap(_seenObjectWithId, seenSubObjectWithId);
const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::valueType(pd->propType));
qSwap(_seenObjectWithId, seenSubObjectWithId);
@@ -1837,7 +1923,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
}
if (pd) {
- GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, GroupPropertyFinder());
+ GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, compareNameIndices);
const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
if (!pd->isWritable()
@@ -1921,7 +2007,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
customParser->compiler = this;
QQmlCompiledData::CustomParserData data;
data.bindings = customParserBindings;
- data.compilationArtifact = customParser->compile(qmlUnit, objectIndex, customBindings);
+ data.compilationArtifact = customParser->compile(qmlUnit, customBindings);
customParser->compiler = 0;
customParserData->insert(objectIndex, data);
const QList<QQmlError> parserErrors = customParser->errors();
@@ -2272,7 +2358,7 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
} else if (property->isQList()) {
const int listType = enginePrivate->listType(property->propType);
if (!QQmlMetaType::isInterface(listType)) {
- QQmlPropertyCache *source = propertyCaches.value(binding->value.objectIndex);
+ QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
if (!canCoerce(listType, source)) {
recordError(binding->valueLocation, tr("Cannot assign object to list"));
return false;
@@ -2297,7 +2383,7 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
bool isAssignable = false;
// Determine isAssignable value
if (propertyMetaObject) {
- QQmlPropertyCache *c = propertyCaches.value(binding->value.objectIndex);
+ QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
while (c && !isAssignable) {
isAssignable |= c == propertyMetaObject;
c = c->parent();
@@ -2312,7 +2398,7 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
return true;
}
-QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QtQml::JSCodeGen *v4CodeGen)
+QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
: QQmlCompilePass(typeCompiler)
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
, resolvedTypes(*typeCompiler->resolvedTypes())
@@ -2338,14 +2424,14 @@ bool QQmlJSCodeGenerator::generateCodeForComponents()
bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, int> &objectIndexToId)
{
if (isComponent(contextObject)) {
- const QtQml::QmlObject *component = qmlObjects.at(contextObject);
+ const QmlIR::Object *component = qmlObjects.at(contextObject);
Q_ASSERT(component->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = component->firstBinding();
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
contextObject = componentBinding->value.objectIndex;
}
- JSCodeGen::ObjectIdMapping idMapping;
+ QmlIR::JSCodeGen::ObjectIdMapping idMapping;
if (!objectIndexToId.isEmpty()) {
idMapping.reserve(objectIndexToId.count());
@@ -2353,8 +2439,8 @@ bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, i
idIt != end; ++idIt) {
const int objectIndex = idIt.key();
- JSCodeGen::IdMapping m;
- const QtQml::QmlObject *obj = qmlObjects.at(objectIndex);
+ QmlIR::JSCodeGen::IdMapping m;
+ const QmlIR::Object *obj = qmlObjects.at(objectIndex);
m.name = stringAt(obj->idIndex);
m.idIndex = idIt.value();
m.type = propertyCaches.at(objectIndex);
@@ -2379,20 +2465,20 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
if (isComponent(objectIndex))
return true;
- QtQml::QmlObject *object = qmlObjects.at(objectIndex);
+ QmlIR::Object *object = qmlObjects.at(objectIndex);
if (object->functionsAndExpressions->count > 0) {
QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex);
v4CodeGen->beginObjectScope(scopeObject);
- QList<QtQml::CompiledFunctionOrExpression> functionsToCompile;
- for (QtQml::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) {
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) {
const bool haveCustomParser = customParsers.contains(object->inheritedTypeNameIndex);
if (haveCustomParser)
foe->disableAcceleratedLookups = true;
functionsToCompile << *foe;
}
const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
- QList<QQmlError> jsErrors = v4CodeGen->errors();
+ QList<QQmlError> jsErrors = v4CodeGen->qmlErrors();
if (!jsErrors.isEmpty()) {
foreach (const QQmlError &e, jsErrors)
compiler->recordError(e);
@@ -2400,11 +2486,11 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
}
QQmlJS::MemoryPool *pool = compiler->memoryPool();
- object->runtimeFunctionIndices = pool->New<QtQml::FixedPoolArray<int> >();
+ object->runtimeFunctionIndices = pool->New<QmlIR::FixedPoolArray<int> >();
object->runtimeFunctionIndices->init(pool, runtimeFunctionIndices);
}
- for (const QtQml::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
+ for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
if (binding->type < QV4::CompiledData::Binding::Type_Object)
continue;
@@ -2438,14 +2524,14 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
if (!propertyCache)
return;
- QmlObject *object = qmlObjects.at(objectIndex);
+ QmlIR::Object *object = qmlObjects.at(objectIndex);
QString defaultProperty = object->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
- Binding *bindingsToReinsert = 0;
- Binding *tail = 0;
+ QmlIR::Binding *bindingsToReinsert = 0;
+ QmlIR::Binding *tail = 0;
- Binding *previousBinding = 0;
- Binding *binding = object->firstBinding();
+ QmlIR::Binding *previousBinding = 0;
+ QmlIR::Binding *binding = object->firstBinding();
while (binding) {
if (binding->propertyNameIndex == 0 || stringAt(binding->propertyNameIndex) != defaultProperty) {
previousBinding = binding;
@@ -2453,7 +2539,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
continue;
}
- Binding *toReinsert = binding;
+ QmlIR::Binding *toReinsert = binding;
binding = object->unlinkBinding(previousBinding, binding);
if (!tail) {
@@ -2468,7 +2554,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
binding = bindingsToReinsert;
while (binding) {
- Binding *toReinsert = binding;
+ QmlIR::Binding *toReinsert = binding;
binding = binding->next;
object->insertSorted(toReinsert);
}
@@ -2477,7 +2563,6 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, qmlObjects(*typeCompiler->qmlObjects())
- , customParsers(typeCompiler->customParserCache())
, jsModule(typeCompiler->jsIRModule())
{
@@ -2495,13 +2580,9 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBinding
void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex)
{
- const QmlObject *obj = qmlObjects.at(objectIndex);
- // Don't feed QV4::CompiledData::Binding::Type_Translation into custom parsers.
- const bool allowTranslations = !customParsers.contains(obj->inheritedTypeNameIndex);
- if (!allowTranslations)
- return;
+ const QmlIR::Object *obj = qmlObjects.at(objectIndex);
- for (Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Script)
continue;
@@ -2515,17 +2596,17 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBinding
}
}
-void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(IR::Move *move)
+void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move)
{
- IR::Temp *target = move->target->asTemp();
- if (!target || target->kind != IR::Temp::VirtualRegister) {
+ QV4::IR::Temp *target = move->target->asTemp();
+ if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
discard();
return;
}
- if (IR::Call *call = move->source->asCall()) {
- if (IR::Name *n = call->base->asName()) {
- if (n->builtin == IR::Name::builtin_invalid) {
+ if (QV4::IR::Call *call = move->source->asCall()) {
+ if (QV4::IR::Name *n = call->base->asName()) {
+ if (n->builtin == QV4::IR::Name::builtin_invalid) {
visitFunctionCall(n->id, call->args, target);
return;
}
@@ -2534,11 +2615,11 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(IR::Move *move
return;
}
- if (IR::Name *n = move->source->asName()) {
- if (n->builtin == IR::Name::builtin_qml_id_array
- || n->builtin == IR::Name::builtin_qml_imported_scripts_object
- || n->builtin == IR::Name::builtin_qml_context_object
- || n->builtin == IR::Name::builtin_qml_scope_object) {
+ if (QV4::IR::Name *n = move->source->asName()) {
+ if (n->builtin == QV4::IR::Name::builtin_qml_id_array
+ || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object
+ || n->builtin == QV4::IR::Name::builtin_qml_context_object
+ || n->builtin == QV4::IR::Name::builtin_qml_scope_object) {
// these are free of side-effects
return;
}
@@ -2554,7 +2635,7 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(IR::Move *move
_temps[target->index] = move->source;
}
-void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, IR::ExprList *args, IR::Temp *target)
+void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target)
{
// more than one function call?
if (_nameOfFunctionCalled) {
@@ -2567,18 +2648,19 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const
_functionParameters.clear();
while (args) {
int slot;
- if (IR::Temp *param = args->expr->asTemp()) {
- if (param->kind != IR::Temp::VirtualRegister) {
+ if (QV4::IR::Temp *param = args->expr->asTemp()) {
+ if (param->kind != QV4::IR::Temp::VirtualRegister) {
discard();
return;
}
slot = param->index;
- } else if (IR::Const *param = args->expr->asConst()) {
+ _functionParameters.append(slot);
+ } else if (QV4::IR::Const *param = args->expr->asConst()) {
slot = --_synthesizedConsts;
Q_ASSERT(!_temps.contains(slot));
_temps[slot] = param;
+ _functionParameters.append(slot);
}
- _functionParameters.append(slot);
args = args->next;
}
@@ -2592,15 +2674,15 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *r
discard();
return;
}
- IR::Temp *target = ret->expr->asTemp();
- if (!target || target->kind != IR::Temp::VirtualRegister) {
+ QV4::IR::Temp *target = ret->expr->asTemp();
+ if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
discard();
return;
}
_returnValueOfBindingExpression = target->index;
}
-bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, Binding *binding)
+bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding)
{
_canSimplify = true;
_nameOfFunctionCalled = 0;
@@ -2612,11 +2694,11 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR:
// It would seem unlikely that function with some many basic blocks (after optimization)
// consists merely of a qsTr call or a constant value return ;-)
- if (function->basicBlocks.count() > 10)
+ if (function->basicBlockCount() > 10)
return false;
- foreach (QV4::IR::BasicBlock *bb, function->basicBlocks) {
- foreach (QV4::IR::Stmt *s, bb->statements) {
+ foreach (QV4::IR::BasicBlock *bb, function->basicBlocks()) {
+ foreach (QV4::IR::Stmt *s, bb->statements()) {
s->accept(this);
if (!_canSimplify)
return false;
@@ -2639,7 +2721,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR:
return false;
}
-bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(Binding *binding)
+bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding)
{
if (*_nameOfFunctionCalled == QStringLiteral("qsTr")) {
QString translation;
@@ -2652,7 +2734,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAnd
if (param == end)
return false;
- IR::String *stringParam = _temps[*param]->asString();
+ QV4::IR::String *stringParam = _temps[*param]->asString();
if (!stringParam)
return false;
@@ -2667,8 +2749,8 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAnd
++param;
if (param != end) {
- IR::Const *constParam = _temps[*param]->asConst();
- if (!constParam || constParam->type != IR::SInt32Type)
+ QV4::IR::Const *constParam = _temps[*param]->asConst();
+ if (!constParam || constParam->type != QV4::IR::SInt32Type)
return false;
translationData.number = int(constParam->value);
@@ -2694,7 +2776,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAnd
if (param == end)
return false;
- IR::String *stringParam = _temps[*param]->asString();
+ QV4::IR::String *stringParam = _temps[*param]->asString();
if (!stringParam)
return false;
@@ -2702,8 +2784,8 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAnd
++param;
if (param != end) {
- IR::Const *constParam = _temps[*param]->asConst();
- if (!constParam || constParam->type != IR::SInt32Type)
+ QV4::IR::Const *constParam = _temps[*param]->asConst();
+ if (!constParam || constParam->type != QV4::IR::SInt32Type)
return false;
translationData.number = int(constParam->value);
@@ -2717,6 +2799,44 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAnd
binding->stringIndex = compiler->registerString(id);
binding->value.translationData = translationData;
return true;
+ } else if (*_nameOfFunctionCalled == QStringLiteral("QT_TR_NOOP") || *_nameOfFunctionCalled == QStringLiteral("QT_TRID_NOOP")) {
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ ++param;
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->stringIndex = compiler->registerString(*stringParam->value);
+ return true;
+ } else if (*_nameOfFunctionCalled == QStringLiteral("QT_TRANSLATE_NOOP")) {
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ ++param;
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ ++param;
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->stringIndex = compiler->registerString(*stringParam->value);
+ return true;
}
return false;
}
@@ -2746,15 +2866,15 @@ void QQmlIRFunctionCleanser::clean()
module->functions = newFunctions;
- foreach (IR::Function *function, module->functions) {
- foreach (IR::BasicBlock *block, function->basicBlocks) {
- foreach (IR::Stmt *s, block->statements) {
+ foreach (QV4::IR::Function *function, module->functions) {
+ foreach (QV4::IR::BasicBlock *block, function->basicBlocks()) {
+ foreach (QV4::IR::Stmt *s, block->statements()) {
s->accept(this);
}
}
}
- foreach (QmlObject *obj, *compiler->qmlObjects()) {
+ foreach (QmlIR::Object *obj, *compiler->qmlObjects()) {
if (!obj->runtimeFunctionIndices)
continue;
for (int i = 0; i < obj->runtimeFunctionIndices->count; ++i)
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 74168fee41..fb8ac94fcd 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -45,6 +45,7 @@
#include <qqmlerror.h>
#include <qhash.h>
#include <private/qqmlcompiler_p.h>
+#include <private/qqmlirbuilder_p.h>
QT_BEGIN_NAMESPACE
@@ -54,8 +55,8 @@ class QQmlError;
class QQmlTypeData;
class QQmlImports;
-namespace QtQml {
-struct ParsedQML;
+namespace QmlIR {
+struct Document;
}
namespace QV4 {
@@ -69,7 +70,7 @@ struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QtQml::ParsedQML *parsedQML);
+ QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QmlIR::Document *document);
bool compile();
@@ -87,7 +88,7 @@ public:
QQmlEnginePrivate *enginePrivate() const { return engine; }
const QQmlImports *imports() const;
QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes();
- QList<QtQml::QmlObject*> *qmlObjects();
+ QList<QmlIR::Object*> *qmlObjects();
int rootObjectIndex() const;
void setPropertyCaches(const QVector<QQmlPropertyCache *> &caches);
const QVector<QQmlPropertyCache *> &propertyCaches() const;
@@ -98,18 +99,20 @@ public:
QHash<int, QQmlCompiledData::CustomParserData> *customParserData();
QQmlJS::MemoryPool *memoryPool();
QStringRef newStringRef(const QString &string);
- const QStringList &stringPool() const;
+ const QV4::Compiler::StringTableGenerator *stringPool() const;
void setCustomParserBindings(const QVector<int> &bindings);
void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject);
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
+ QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const;
+
private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
QQmlCompiledData *compiledData;
QQmlTypeData *typeData;
- QtQml::ParsedQML *parsedQML;
+ QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
QHash<int, QQmlCustomParser*> customParsers;
};
@@ -138,10 +141,10 @@ public:
protected:
bool buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding);
bool ensureMetaObject(int objectIndex);
- bool createMetaObject(int objectIndex, const QtQml::QmlObject *obj, QQmlPropertyCache *baseTypeCache);
+ bool createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache);
QQmlEnginePrivate *enginePrivate;
- const QList<QtQml::QmlObject*> &qmlObjects;
+ const QList<QmlIR::Object*> &qmlObjects;
const QQmlImports *imports;
QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
QVector<QByteArray> vmeMetaObjects;
@@ -154,16 +157,16 @@ protected:
// to the final signal name (onTextChanged -> textChanged) and sets the IsSignalExpression flag.
struct SignalHandlerConverter : public QQmlCompilePass
{
- Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
+ Q_DECLARE_TR_FUNCTIONS(SignalHandlerConverter)
public:
SignalHandlerConverter(QQmlTypeCompiler *typeCompiler);
bool convertSignalHandlerExpressionsToFunctionDeclarations();
private:
- bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlObject *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
+ bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
- const QList<QtQml::QmlObject*> &qmlObjects;
+ const QList<QmlIR::Object*> &qmlObjects;
const QHash<int, QQmlCustomParser*> &customParsers;
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
const QSet<QString> &illegalNames;
@@ -182,18 +185,32 @@ public:
bool resolveEnumBindings();
private:
- bool tryQualifiedEnumAssignment(const QmlObject *obj, const QQmlPropertyCache *propertyCache,
+ bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
const QQmlPropertyData *prop,
- QtQml::Binding *binding);
+ QmlIR::Binding *binding);
int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const;
- const QList<QtQml::QmlObject*> &qmlObjects;
+ const QList<QmlIR::Object*> &qmlObjects;
const QVector<QQmlPropertyCache *> propertyCaches;
const QQmlImports *imports;
QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes;
};
+class QQmlCustomParserScriptIndexer: public QQmlCompilePass
+{
+public:
+ QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler);
+
+ void annotateBindingsWithScriptStrings();
+
+private:
+ void scanObjectRecursively(int objectIndex, bool annotateScriptBindings = false);
+
+ const QList<QmlIR::Object*> &qmlObjects;
+ const QHash<int, QQmlCustomParser*> &customParsers;
+};
+
// Annotate properties bound to aliases with a flag
class QQmlAliasAnnotator : public QQmlCompilePass
{
@@ -202,7 +219,19 @@ public:
void annotateBindingsToAliases();
private:
- const QList<QtQml::QmlObject*> &qmlObjects;
+ const QList<QmlIR::Object*> &qmlObjects;
+ const QVector<QQmlPropertyCache *> propertyCaches;
+};
+
+class QQmlScriptStringScanner : public QQmlCompilePass
+{
+public:
+ QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler);
+
+ void scan();
+
+private:
+ const QList<QmlIR::Object*> &qmlObjects;
const QVector<QQmlPropertyCache *> propertyCaches;
};
@@ -215,14 +244,14 @@ public:
bool resolve();
protected:
- void findAndRegisterImplicitComponents(const QtQml::QmlObject *obj, QQmlPropertyCache *propertyCache);
+ void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache);
bool collectIdsAndAliases(int objectIndex);
bool resolveAliases();
QQmlEnginePrivate *enginePrivate;
QQmlJS::MemoryPool *pool;
- QList<QtQml::QmlObject*> *qmlObjects;
+ QList<QmlIR::Object*> *qmlObjects;
const int indexOfRootObject;
// indices of the objects that are actually Component {}
@@ -237,7 +266,7 @@ protected:
QList<int> _objectsWithAliases;
QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
- const QVector<QQmlPropertyCache *> propertyCaches;
+ QVector<QQmlPropertyCache *> propertyCaches;
QVector<QByteArray> *vmeMetaObjectData;
QHash<int, int> *objectIndexToIdForRoot;
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent;
@@ -253,8 +282,8 @@ public:
// Re-implemented for QQmlCustomParser
virtual const QQmlImports &imports() const;
- virtual QQmlJS::AST::Node *astForBinding(int objectIndex, int scriptIndex) const;
virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser);
+ virtual QString bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const;
private:
bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false);
@@ -282,7 +311,7 @@ private:
class QQmlJSCodeGenerator : public QQmlCompilePass
{
public:
- QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QtQml::JSCodeGen *v4CodeGen);
+ QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen);
bool generateCodeForComponents();
@@ -295,9 +324,9 @@ private:
const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent;
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
const QHash<int, QQmlCustomParser*> &customParsers;
- const QList<QtQml::QmlObject*> &qmlObjects;
+ const QList<QmlIR::Object*> &qmlObjects;
const QVector<QQmlPropertyCache *> &propertyCaches;
- QtQml::JSCodeGen * const v4CodeGen;
+ QmlIR::JSCodeGen * const v4CodeGen;
};
class QQmlDefaultPropertyMerger : public QQmlCompilePass
@@ -310,7 +339,7 @@ public:
private:
void mergeDefaultProperties(int objectIndex);
- const QList<QtQml::QmlObject*> &qmlObjects;
+ const QList<QmlIR::Object*> &qmlObjects;
const QVector<QQmlPropertyCache*> &propertyCaches;
};
@@ -328,18 +357,17 @@ private:
virtual void visitJump(QV4::IR::Jump *) {}
virtual void visitCJump(QV4::IR::CJump *) { discard(); }
virtual void visitExp(QV4::IR::Exp *) { discard(); }
- virtual void visitPhi(IR::Phi *) {}
+ virtual void visitPhi(QV4::IR::Phi *) {}
virtual void visitRet(QV4::IR::Ret *ret);
- void visitFunctionCall(const QString *name, IR::ExprList *args, IR::Temp *target);
+ void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target);
void discard() { _canSimplify = false; }
- bool simplifyBinding(QV4::IR::Function *function, Binding *binding);
- bool detectTranslationCallAndConvertBinding(Binding *binding);
+ bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding);
+ bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding);
- const QList<QtQml::QmlObject*> &qmlObjects;
- const QHash<int, QQmlCustomParser*> &customParsers;
+ const QList<QmlIR::Object*> &qmlObjects;
QV4::IR::Module *jsModule;
bool _canSimplify;
@@ -347,7 +375,7 @@ private:
QVector<int> _functionParameters;
int _functionCallReturnValue;
- QHash<int, IR::Expr*> _temps;
+ QHash<int, QV4::IR::Expr*> _temps;
int _returnValueOfBindingExpression;
int _synthesizedConsts;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 504edfcd36..fdc4d5c9f2 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -41,7 +41,6 @@
#include "qv4codegen_p.h"
#include "qv4util_p.h"
-#include "qv4debugging_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
@@ -51,8 +50,13 @@
#include <QtCore/QLinkedList>
#include <QtCore/QStack>
#include <private/qqmljsast_p.h>
-#include <qv4runtime_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4value_inl_p.h>
+
+#ifndef V4_BOOTSTRAP
#include <qv4context_p.h>
+#endif
+
#include <cmath>
#include <iostream>
@@ -2041,7 +2045,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
sourceElements(body);
- _function->insertBasicBlock(_exitBlock);
+ _function->addBasicBlock(_exitBlock);
_block->JUMP(_exitBlock);
@@ -2212,8 +2216,6 @@ bool Codegen::visit(ForEachStatement *ast)
IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler());
IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- enterLoop(ast, foreachin, foreachend, foreachin);
-
int objectToIterateOn = _block->newTemp();
move(_block->TEMP(objectToIterateOn), *expression(ast->expression));
IR::ExprList *args = _function->New<IR::ExprList>();
@@ -2222,6 +2224,7 @@ bool Codegen::visit(ForEachStatement *ast)
int iterator = _block->newTemp();
move(_block->TEMP(iterator), _block->CALL(_block->NAME(IR::Name::builtin_foreach_iterator_object, 0, 0), args));
+ enterLoop(ast, foreachin, foreachend, foreachin);
_block->JUMP(foreachin);
_block = foreachbody;
@@ -2352,8 +2355,6 @@ bool Codegen::visit(LocalForEachStatement *ast)
IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler());
IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- enterLoop(ast, foreachin, foreachend, foreachin);
-
variableDeclaration(ast->declaration);
int iterator = _block->newTemp();
@@ -2363,6 +2364,7 @@ bool Codegen::visit(LocalForEachStatement *ast)
move(_block->TEMP(iterator), _block->CALL(_block->NAME(IR::Name::builtin_foreach_iterator_object, 0, 0), args));
_block->JUMP(foreachin);
+ enterLoop(ast, foreachin, foreachend, foreachin);
_block = foreachbody;
int temp = _block->newTemp();
@@ -2597,7 +2599,7 @@ bool Codegen::visit(TryStatement *ast)
if (ast->catchExpression) {
pushExceptionHandler(catchExceptionHandler);
- _function->insertBasicBlock(catchBody);
+ _function->addBasicBlock(catchBody);
_block = catchBody;
++_function->insideWithOrCatch;
@@ -2615,7 +2617,7 @@ bool Codegen::visit(TryStatement *ast)
_block->JUMP(finallyBody ? finallyBody : end);
popExceptionHandler();
- _function->insertBasicBlock(catchExceptionHandler);
+ _function->addBasicBlock(catchExceptionHandler);
catchExceptionHandler->EXP(catchExceptionHandler->CALL(catchExceptionHandler->NAME(IR::Name::builtin_pop_scope, 0, 0), 0));
if (finallyBody || surroundingExceptionHandler)
catchExceptionHandler->JUMP(finallyBody ? finallyBody : surroundingExceptionHandler);
@@ -2626,7 +2628,7 @@ bool Codegen::visit(TryStatement *ast)
_scopeAndFinally = tcf.parent;
if (finallyBody) {
- _function->insertBasicBlock(finallyBody);
+ _function->addBasicBlock(finallyBody);
_block = finallyBody;
int hasException = _block->newTemp();
@@ -2641,7 +2643,7 @@ bool Codegen::visit(TryStatement *ast)
_block->JUMP(end);
}
- _function->insertBasicBlock(end);
+ _function->addBasicBlock(end);
_block = end;
return false;
@@ -2812,11 +2814,9 @@ void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
return;
hasError = true;
- QQmlError error;
- error.setUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
- error.setDescription(detail);
- error.setLine(loc.startLine);
- error.setColumn(loc.startColumn);
+ QQmlJS::DiagnosticMessage error;
+ error.message = detail;
+ error.loc = loc;
_errors << error;
}
@@ -2826,19 +2826,37 @@ void Codegen::throwReferenceError(const SourceLocation &loc, const QString &deta
return;
hasError = true;
- QQmlError error;
- error.setUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
- error.setDescription(detail);
- error.setLine(loc.startLine);
- error.setColumn(loc.startColumn);
+ QQmlJS::DiagnosticMessage error;
+ error.message = detail;
+ error.loc = loc;
_errors << error;
}
-QList<QQmlError> Codegen::errors() const
+QList<QQmlJS::DiagnosticMessage> Codegen::errors() const
{
return _errors;
}
+#ifndef V4_BOOTSTRAP
+
+QList<QQmlError> Codegen::qmlErrors() const
+{
+ QList<QQmlError> qmlErrors;
+ qmlErrors.reserve(_errors.size());
+
+ QUrl url(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
+ foreach (const QQmlJS::DiagnosticMessage &msg, _errors) {
+ QQmlError e;
+ e.setUrl(url);
+ e.setLine(msg.loc.startLine);
+ e.setColumn(msg.loc.startColumn);
+ e.setDescription(msg.message);
+ qmlErrors << e;
+ }
+
+ return qmlErrors;
+}
+
void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail)
{
if (hasError)
@@ -2854,3 +2872,5 @@ void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const Q
hasError = true;
context->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn);
}
+
+#endif // V4_BOOTSTRAP
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 9c43dc17fe..0d52fb83fa 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -45,10 +45,12 @@
#include "qv4jsir_p.h"
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmljsengine_p.h>
#include <QtCore/QStringList>
#include <QStack>
+#ifndef V4_BOOTSTRAP
#include <qqmlerror.h>
-#include <assert.h>
+#endif
#include <private/qv4util_p.h>
QT_BEGIN_NAMESPACE
@@ -63,7 +65,7 @@ class UiParameterList;
}
-class Q_QML_EXPORT Codegen: protected AST::Visitor
+class Q_QML_PRIVATE_EXPORT Codegen: protected AST::Visitor
{
public:
Codegen(bool strict);
@@ -180,7 +182,7 @@ protected:
MemberMap::const_iterator it = members.find(name);
if (it == members.end())
return -1;
- assert((*it).index != -1 || !parent);
+ Q_ASSERT((*it).index != -1 || !parent);
return (*it).index;
}
@@ -284,7 +286,7 @@ protected:
}
void pushExceptionHandler(QV4::IR::BasicBlock *handler)
{
- handler->isExceptionHandler = true;
+ handler->setExceptionHandler(true);
_exceptionHandlers.push(handler);
}
void popExceptionHandler()
@@ -435,7 +437,10 @@ protected:
virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
public:
- QList<QQmlError> errors() const;
+ QList<DiagnosticMessage> errors() const;
+#ifndef V4_BOOTSTRAP
+ QList<QQmlError> qmlErrors() const;
+#endif
protected:
Result _expr;
@@ -457,7 +462,7 @@ protected:
bool _fileNameIsUrl;
bool hasError;
- QList<QQmlError> _errors;
+ QList<QQmlJS::DiagnosticMessage> _errors;
class ScanFunctions: protected Visitor
{
@@ -533,6 +538,7 @@ protected:
};
+#ifndef V4_BOOTSTRAP
class RuntimeCodegen : public Codegen
{
public:
@@ -546,6 +552,7 @@ public:
private:
QV4::ExecutionContext *context;
};
+#endif // V4_BOOTSTRAP
}
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index ae495e0ffa..cd9d8fe8a9 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -41,11 +41,15 @@
#include "qv4compileddata_p.h"
#include "qv4jsir_p.h"
+#include <private/qv4value_inl_p.h>
+#ifndef V4_BOOTSTRAP
#include <private/qv4engine_p.h>
#include <private/qv4function_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qv4lookup_p.h>
#include <private/qv4regexpobject_p.h>
+#endif
+#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
#include <algorithm>
@@ -56,6 +60,7 @@ namespace QV4 {
namespace CompiledData {
+#ifndef V4_BOOTSTRAP
CompilationUnit::~CompilationUnit()
{
unlink();
@@ -66,8 +71,8 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
this->engine = engine;
engine->compilationUnits.insert(this);
- assert(!runtimeStrings);
- assert(data);
+ Q_ASSERT(!runtimeStrings);
+ Q_ASSERT(data);
runtimeStrings = (QV4::StringValue *)malloc(data->stringTableSize * sizeof(QV4::StringValue));
// memset the strings to 0 in case a GC run happens while we're within the loop below
memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::StringValue));
@@ -180,6 +185,13 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
}
}
+#endif // V4_BOOTSTRAP
+
+Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
+{
+ return irDocument->jsGenerator.generateUnit();
+}
+
QString Binding::valueAsString(const Unit *unit) const
{
switch (type) {
@@ -192,6 +204,11 @@ QString Binding::valueAsString(const Unit *unit) const
return QString::number(value.d);
case Type_Invalid:
return QString();
+#ifdef QT_NO_TRANSLATION
+ case Type_TranslationById:
+ case Type_Translation:
+ return unit->stringAt(stringIndex);
+#else
case Type_TranslationById: {
QByteArray id = unit->stringAt(stringIndex).toUtf8();
return qtTrId(id.constData(), value.translationData.number);
@@ -208,6 +225,7 @@ QString Binding::valueAsString(const Unit *unit) const
return QCoreApplication::translate(contextUtf8.constData(), text.constData(),
comment.constData(), value.translationData.number);
}
+#endif
default:
break;
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 186363dcde..1fba6c0d3c 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -50,6 +50,10 @@
QT_BEGIN_NAMESPACE
+namespace QmlIR {
+struct Document;
+}
+
namespace QV4 {
namespace IR {
struct Function;
@@ -146,7 +150,6 @@ struct JSClass
struct String
{
- quint32 hash;
quint32 flags; // isArrayIndex
QArrayData str;
// uint16 strdata[]
@@ -163,12 +166,14 @@ struct Unit
char magic[8];
qint16 architecture;
qint16 version;
+ quint32 unitSize; // Size of the Unit and any depending data. Does _not_ include size of data needed by QmlUnit.
enum {
IsJavascript = 0x1,
IsQml = 0x2,
StaticData = 0x4, // Unit data persistent in memory?
- IsSingleton = 0x8
+ IsSingleton = 0x8,
+ IsSharedLibrary = 0x10 // .pragma shared?
};
quint32 flags;
uint stringTableSize;
@@ -190,6 +195,8 @@ struct Unit
const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
const uint offset = offsetTable[idx];
const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
+ if (str->str.size == 0)
+ return QString();
QStringDataPtr holder = { const_cast<QStringData *>(static_cast<const QStringData*>(&str->str)) };
QString qstr(holder);
if (flags & StaticData)
@@ -197,8 +204,10 @@ struct Unit
return QString(qstr.constData(), qstr.length());
}
+ const uint *functionOffsetTable() const { return reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
+
const Function *functionAt(int idx) const {
- const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable);
+ const uint *offsetTable = functionOffsetTable();
const uint offset = offsetTable[idx];
return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
}
@@ -220,10 +229,10 @@ struct Unit
return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
}
- static int calculateSize(uint headerSize, uint nStrings, uint nFunctions, uint nRegExps, uint nConstants,
+ static int calculateSize(uint headerSize, uint nFunctions, uint nRegExps, uint nConstants,
uint nLookups, uint nClasses) {
return (headerSize
- + (nStrings + nFunctions + nClasses) * sizeof(uint)
+ + (nFunctions + nClasses) * sizeof(uint)
+ nRegExps * RegExp::calculateSize()
+ nConstants * sizeof(QV4::ReturnedValue)
+ nLookups * Lookup::calculateSize()
@@ -285,7 +294,7 @@ struct Q_QML_EXPORT TranslationData {
int number;
};
-struct Q_QML_EXPORT Binding
+struct Q_QML_PRIVATE_EXPORT Binding
{
quint32 propertyNameIndex;
@@ -523,6 +532,7 @@ struct Import
struct QmlUnit
{
Unit header;
+ quint32 qmlUnitSize; // size including header and all surrounding data.
quint32 nImports;
quint32 offsetToImports;
quint32 nObjects;
@@ -550,26 +560,38 @@ struct QmlUnit
// CompilationUnit * (for functions that need to clean up)
// CompiledData::Function *compiledFunction
-struct Q_QML_EXPORT CompilationUnit
+struct Q_QML_PRIVATE_EXPORT CompilationUnit
{
+#ifdef V4_BOOTSTRAP
+ CompilationUnit()
+ : refCount(0)
+ , data(0)
+ {}
+ virtual ~CompilationUnit() {}
+#else
CompilationUnit()
: refCount(0)
- , engine(0)
, data(0)
+ , engine(0)
, runtimeStrings(0)
, runtimeLookups(0)
, runtimeRegularExpressions(0)
, runtimeClasses(0)
{}
virtual ~CompilationUnit();
+#endif
void ref() { ++refCount; }
void deref() { if (!--refCount) delete this; }
int refCount;
- ExecutionEngine *engine;
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);
+
+#ifndef V4_BOOTSTRAP
+ ExecutionEngine *engine;
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
QV4::StringValue *runtimeStrings; // Array
@@ -577,20 +599,17 @@ struct Q_QML_EXPORT CompilationUnit
QV4::Value *runtimeRegularExpressions;
QV4::InternalClass **runtimeClasses;
QVector<QV4::Function *> runtimeFunctions;
-// QVector<QV4::Function *> runtimeFunctionsSortedByAddress;
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
void unlink();
virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int /*functionIndex*/) { return 0; }
- // ### runtime data
- // pointer to qml data for QML unit
-
void markObjects(QV4::ExecutionEngine *e);
protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
+#endif // V4_BOOTSTRAP
};
}
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index f25b1900ce..65ef5c4b5e 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -42,22 +42,15 @@
#include <qv4compiler_p.h>
#include <qv4compileddata_p.h>
#include <qv4isel_p.h>
-#include <qv4engine_p.h>
-#include <private/qqmlpropertycache_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4value_inl_p.h>
-QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module, int headerSize)
- : irModule(module)
- , stringDataSize(0)
- , jsClassDataSize(0)
+QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
- if (headerSize == -1)
- headerSize = sizeof(QV4::CompiledData::Unit);
- this->headerSize = headerSize;
- // Make sure the empty string always gets index 0
- registerString(QString());
+ clear();
}
-int QV4::Compiler::JSUnitGenerator::registerString(const QString &str)
+int QV4::Compiler::StringTableGenerator::registerString(const QString &str)
{
QHash<QString, int>::ConstIterator it = stringToId.find(str);
if (it != stringToId.end())
@@ -68,12 +61,49 @@ int QV4::Compiler::JSUnitGenerator::registerString(const QString &str)
return strings.size() - 1;
}
-int QV4::Compiler::JSUnitGenerator::getStringId(const QString &string) const
+int QV4::Compiler::StringTableGenerator::getStringId(const QString &string) const
{
Q_ASSERT(stringToId.contains(string));
return stringToId.value(string);
}
+void QV4::Compiler::StringTableGenerator::clear()
+{
+ strings.clear();
+ stringToId.clear();
+ stringDataSize = 0;
+}
+
+void QV4::Compiler::StringTableGenerator::serialize(uint *stringTable, char *dataStart, char *stringData)
+{
+ 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);
+ s->flags = 0; // ###
+ s->str.ref.atomic.store(-1);
+ s->str.size = qstr.length();
+ s->str.alloc = 0;
+ s->str.capacityReserved = false;
+ s->str.offset = sizeof(QArrayData);
+ memcpy(s + 1, qstr.constData(), (qstr.length() + 1)*sizeof(ushort));
+
+ stringData += QV4::CompiledData::String::calculateSize(qstr);
+ }
+}
+
+QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module, int headerSize)
+ : irModule(module)
+ , jsClassDataSize(0)
+{
+ if (headerSize == -1)
+ headerSize = sizeof(QV4::CompiledData::Unit);
+ this->headerSize = headerSize;
+ // Make sure the empty string always gets index 0
+ registerString(QString());
+}
+
uint QV4::Compiler::JSUnitGenerator::registerIndexedGetterLookup()
{
CompiledData::Lookup l;
@@ -175,7 +205,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg
return jsClasses.size() - 1;
}
-QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *totalUnitSize)
+QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
{
registerString(irModule->fileName);
foreach (QV4::IR::Function *f, irModule->functions) {
@@ -186,22 +216,20 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
registerString(*f->locals.at(i));
}
- int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, strings.size(), irModule->functions.size(), regexps.size(),
+ int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, 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 + stringDataSize);
+ functionOffsets.insert(f, functionDataSize + unitSize);
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);
}
- const int totalSize = unitSize + functionDataSize + stringDataSize + jsClassDataSize;
- if (totalUnitSize)
- *totalUnitSize = totalSize;
+ const int totalSize = unitSize + functionDataSize + jsClassDataSize + stringTable.sizeOfTableAndData();
char *data = (char *)malloc(totalSize);
memset(data, 0, totalSize);
QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
@@ -210,10 +238,9 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
unit->architecture = 0; // ###
unit->flags = QV4::CompiledData::Unit::IsJavascript;
unit->version = 1;
- unit->stringTableSize = strings.size();
- unit->offsetToStringTable = headerSize;
+ unit->unitSize = totalSize;
unit->functionTableSize = irModule->functions.size();
- unit->offsetToFunctionTable = unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
+ unit->offsetToFunctionTable = headerSize;
unit->lookupTableSize = lookups.count();
unit->offsetToLookupTable = unit->offsetToFunctionTable + unit->functionTableSize * sizeof(uint);
unit->regexpTableSize = regexps.size();
@@ -222,34 +249,16 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
unit->offsetToConstantTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
unit->jsClassTableSize = jsClasses.count();
unit->offsetToJSClassTable = unit->offsetToConstantTable + unit->constantTableSize * sizeof(ReturnedValue);
+ unit->stringTableSize = stringTable.stringCount();
+ unit->offsetToStringTable = unitSize + functionDataSize + jsClassDataSize;
unit->indexOfRootFunction = -1;
unit->sourceFileIndex = getStringId(irModule->fileName);
- // write strings and string table
- uint *stringTable = (uint *)(data + unit->offsetToStringTable);
- char *string = data + unitSize;
- for (int i = 0; i < strings.size(); ++i) {
- stringTable[i] = string - data;
- const QString &qstr = strings.at(i);
-
- QV4::CompiledData::String *s = (QV4::CompiledData::String*)(string);
- s->hash = QV4::String::createHashValue(qstr.constData(), qstr.length());
- s->flags = 0; // ###
- s->str.ref.atomic.store(-1);
- s->str.size = qstr.length();
- s->str.alloc = 0;
- s->str.capacityReserved = false;
- s->str.offset = sizeof(QArrayData);
- memcpy(s + 1, qstr.constData(), (qstr.length() + 1)*sizeof(ushort));
-
- string += QV4::CompiledData::String::calculateSize(qstr);
- }
-
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 + stringDataSize;
+ char *f = data + unitSize;
for (int i = 0; i < irModule->functions.size(); ++i) {
QV4::IR::Function *function = irModule->functions.at(i);
if (function == irModule->rootFunction)
@@ -271,7 +280,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
// write js classes and js class lookup table
uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable);
- char *jsClass = data + unitSize + stringDataSize + functionDataSize;
+ char *jsClass = data + unitSize + functionDataSize;
for (int i = 0; i < jsClasses.count(); ++i) {
jsClassTable[i] = jsClass - data;
@@ -287,6 +296,13 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
jsClass += CompiledData::JSClass::calculateSize(members.count());
}
+ // write strings and string table
+ {
+ uint *stringTablePtr = (uint *)(data + unit->offsetToStringTable);
+ char *string = data + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
+ stringTable.serialize(stringTablePtr, data, string);
+ }
+
return unit;
}
@@ -383,5 +399,3 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions,
function->nDependingIdObjects, function->nDependingContextProperties + function->nDependingScopeProperties);
}
-
-
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 6fd597a3b3..a52128f653 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -59,13 +59,32 @@ struct JSClassMember;
namespace Compiler {
-struct Q_QML_EXPORT JSUnitGenerator {
- JSUnitGenerator(IR::Module *module, int headerSize = -1);
-
- IR::Module *irModule;
+struct Q_QML_PRIVATE_EXPORT StringTableGenerator {
+ StringTableGenerator();
int registerString(const QString &str);
int getStringId(const QString &string) const;
+ QString stringForIndex(int index) const { return strings.at(index); }
+ uint stringCount() const { return strings.size(); }
+
+ uint sizeOfTableAndData() const { return stringDataSize + strings.count() * sizeof(uint); }
+
+ void clear();
+
+ void serialize(uint *stringTable, char *dataStart, char *stringData);
+
+private:
+ QHash<QString, int> stringToId;
+ QStringList strings;
+ uint stringDataSize;
+};
+
+struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
+ JSUnitGenerator(IR::Module *module, int headerSize = -1);
+
+ int registerString(const QString &str) { return stringTable.registerString(str); }
+ int getStringId(const QString &string) const { return stringTable.getStringId(string); }
+ QString stringForIndex(int index) const { return stringTable.stringForIndex(index); }
uint registerGetterLookup(const QString &name);
uint registerSetterLookup(const QString &name);
@@ -79,13 +98,14 @@ struct Q_QML_EXPORT JSUnitGenerator {
int registerJSClass(int count, IR::ExprList *args);
- QV4::CompiledData::Unit *generateUnit(int *totalUnitSize = 0);
+ QV4::CompiledData::Unit *generateUnit();
// Returns bytes written
int writeFunction(char *f, int index, IR::Function *irFunction);
- QHash<QString, int> stringToId;
- QStringList strings;
- uint stringDataSize;
+ StringTableGenerator stringTable;
+private:
+ IR::Module *irModule;
+
QHash<IR::Function *, uint> functionOffsets;
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 1e0e88730b..9288008632 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -118,7 +118,7 @@ inline QV4::Runtime::BinaryOperation aluOpFunction(IR::AluOp op)
case IR::OpOr:
return 0;
default:
- assert(!"Unknown AluOp");
+ Q_ASSERT(!"Unknown AluOp");
return 0;
}
};
@@ -257,7 +257,7 @@ protected:
if (IR::Jump *jump = s->asJump()) {
IR::MoveMapping moves;
- foreach (IR::Stmt *succStmt, jump->target->statements) {
+ foreach (IR::Stmt *succStmt, jump->target->statements()) {
if (IR::Phi *phi = succStmt->asPhi()) {
forceActivation(*phi->targetTemp);
for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) {
@@ -360,7 +360,7 @@ void InstructionSelection::run(int functionIndex)
qgetenv("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION").isEmpty();
if (doStackSlotAllocation) {
- AllocateStackSlots(opt.lifeRanges()).forFunction(_function);
+ AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function);
} else {
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
@@ -377,7 +377,7 @@ void InstructionSelection::run(int functionIndex)
qSwap(_currentStatement, cs);
int locals = frameSize();
- assert(locals >= 0);
+ Q_ASSERT(locals >= 0);
IR::BasicBlock *exceptionHandler = 0;
@@ -386,10 +386,11 @@ void InstructionSelection::run(int functionIndex)
addInstruction(push);
currentLine = 0;
- for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
+ QVector<IR::BasicBlock *> basicBlocks = _function->basicBlocks();
+ for (int i = 0, ei = basicBlocks.size(); i != ei; ++i) {
blockNeedsDebugInstruction = irModule->debugMode;
- _block = _function->basicBlocks[i];
- _nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
+ _block = basicBlocks[i];
+ _nextBlock = (i < ei - 1) ? basicBlocks[i + 1] : 0;
_addrs.insert(_block, _codeNext - _codeStart);
if (_block->catchBlock != exceptionHandler) {
@@ -404,7 +405,7 @@ void InstructionSelection::run(int functionIndex)
exceptionHandler = _block->catchBlock;
}
- foreach (IR::Stmt *s, _block->statements) {
+ foreach (IR::Stmt *s, _block->statements()) {
_currentStatement = s;
if (s->location.isValid()) {
@@ -607,7 +608,7 @@ void InstructionSelection::loadQmlSingleton(const QString &name, IR::Temp *temp)
void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Temp *targetTemp)
{
- assert(sourceConst);
+ Q_ASSERT(sourceConst);
Instruction::MoveConst move;
move.source = convertToValue(sourceConst).asReturnedValue();
@@ -1009,7 +1010,7 @@ void InstructionSelection::prepareCallArgs(IR::ExprList *e, quint32 &argc, quint
*args = argLocation;
if (e) {
// We need to move all the temps into the function arg array
- assert(argLocation >= 0);
+ Q_ASSERT(argLocation >= 0);
while (e) {
if (IR::Const *c = e->expr->asConst()) {
Instruction::MoveConst move;
@@ -1038,7 +1039,7 @@ void InstructionSelection::visitJump(IR::Jump *s)
if (blockNeedsDebugInstruction) {
Instruction::Debug debug;
- debug.lineNumber = -currentLine;
+ debug.lineNumber = -int(currentLine);
addInstruction(debug);
}
@@ -1053,7 +1054,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
{
if (blockNeedsDebugInstruction) {
Instruction::Debug debug;
- debug.lineNumber = -currentLine;
+ debug.lineNumber = -int(currentLine);
addInstruction(debug);
}
@@ -1093,7 +1094,7 @@ 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 = -currentLine;
+ debug.lineNumber = -int(currentLine);
addInstruction(debug);
}
@@ -1231,7 +1232,7 @@ void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionNam
addInstruction(call);
}
-void InstructionSelection::callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result)
+void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result)
{
Instruction::CallBuiltinForeachIteratorObject call;
call.arg = getParam(arg);
@@ -1467,7 +1468,7 @@ QByteArray InstructionSelection::squeezeCode() const
}
Param InstructionSelection::getParam(IR::Expr *e) {
- assert(e);
+ Q_ASSERT(e);
if (IR::Const *c = e->asConst()) {
int idx = jsUnitGenerator()->registerConstant(convertToValue(c).asReturnedValue());
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index 4c01434156..0aa1972fb4 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -93,7 +93,7 @@ protected:
virtual void callBuiltinReThrow();
virtual void callBuiltinUnwindException(IR::Temp *);
virtual void callBuiltinPushCatchScope(const QString &exceptionName);
- virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
+ virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result);
virtual void callBuiltinPushWithScope(IR::Temp *arg);
virtual void callBuiltinPopScope();
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 0e429423ab..429688090c 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -39,19 +39,16 @@
**
****************************************************************************/
-#include "qv4debugging_p.h"
-#include "qv4engine_p.h"
#include "qv4jsir_p.h"
#include "qv4isel_p.h"
#include "qv4isel_util_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4function_p.h"
+#include <private/qv4value_inl_p.h>
+#ifndef V4_BOOTSTRAP
#include <private/qqmlpropertycache_p.h>
+#endif
#include <QString>
-#include <cassert>
-
namespace {
Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly));
#define qout *qout()
@@ -70,8 +67,10 @@ EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *exe
ownJSGenerator.reset(jsGenerator);
}
this->jsGenerator = jsGenerator;
- assert(execAllocator);
- assert(module);
+#ifndef V4_BOOTSTRAP
+ Q_ASSERT(execAllocator);
+#endif
+ Q_ASSERT(module);
}
EvalInstructionSelection::~EvalInstructionSelection()
@@ -146,6 +145,9 @@ void IRDecoder::visitMove(IR::Move *s)
}
} else if (IR::Member *m = s->source->asMember()) {
if (m->property) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
bool captureRequired = true;
Q_ASSERT(m->kind != IR::Member::MemberOfEnum);
@@ -161,6 +163,7 @@ void IRDecoder::visitMove(IR::Move *s)
}
}
getQObjectProperty(m->base, m->property->coreIndex, captureRequired, attachedPropertiesId, t);
+#endif // V4_BOOTSTRAP
return;
} else if (m->base->asTemp() || m->base->asConst()) {
getProperty(m->base, *m->name, t);
@@ -202,7 +205,11 @@ void IRDecoder::visitMove(IR::Move *s)
Q_ASSERT(m->kind != IR::Member::MemberOfEnum);
const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
if (m->property && attachedPropertiesId == 0) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
setQObjectProperty(s->source, m->base, m->property->coreIndex);
+#endif
return;
} else {
setProperty(s->source, m->base, *m->name);
@@ -221,7 +228,7 @@ void IRDecoder::visitMove(IR::Move *s)
Q_UNIMPLEMENTED();
s->dump(qout, IR::Stmt::MIR);
qout << endl;
- assert(!"TODO");
+ Q_ASSERT(!"TODO");
}
IRDecoder::~IRDecoder()
@@ -252,7 +259,7 @@ void IRDecoder::visitExp(IR::Exp *s)
void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
{
IR::Name *baseName = call->base->asName();
- assert(baseName != 0);
+ Q_ASSERT(baseName != 0);
switch (baseName->builtin) {
case IR::Name::builtin_invalid:
@@ -294,7 +301,7 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
case IR::Name::builtin_throw: {
IR::Expr *arg = call->args->expr;
- assert(arg->asTemp() || arg->asConst());
+ Q_ASSERT(arg->asTemp() || arg->asConst());
callBuiltinThrow(arg);
} return;
@@ -313,19 +320,19 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
} return;
case IR::Name::builtin_foreach_iterator_object: {
- IR::Temp *arg = call->args->expr->asTemp();
- assert(arg != 0);
+ IR::Expr *arg = call->args->expr;
+ Q_ASSERT(arg != 0);
callBuiltinForeachIteratorObject(arg, result);
} return;
case IR::Name::builtin_foreach_next_property_name: {
IR::Temp *arg = call->args->expr->asTemp();
- assert(arg != 0);
+ Q_ASSERT(arg != 0);
callBuiltinForeachNextPropertyname(arg, result);
} return;
case IR::Name::builtin_push_with_scope: {
IR::Temp *arg = call->args->expr->asTemp();
- assert(arg != 0);
+ Q_ASSERT(arg != 0);
callBuiltinPushWithScope(arg);
} return;
@@ -337,10 +344,10 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
if (!call->args)
return;
IR::Const *deletable = call->args->expr->asConst();
- assert(deletable->type == IR::BoolType);
+ Q_ASSERT(deletable->type == IR::BoolType);
for (IR::ExprList *it = call->args->next; it; it = it->next) {
IR::Name *arg = it->expr->asName();
- assert(arg != 0);
+ Q_ASSERT(arg != 0);
callBuiltinDeclareVar(deletable->value != 0, *arg->id);
}
} return;
@@ -396,6 +403,6 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
Q_UNIMPLEMENTED();
call->dump(qout); qout << endl;
- assert(!"TODO!");
+ Q_ASSERT(!"TODO!");
Q_UNREACHABLE();
}
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index f4aab412df..74e6ba8200 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -59,7 +59,7 @@ namespace QV4 {
class ExecutableAllocator;
struct Function;
-class Q_QML_EXPORT EvalInstructionSelection
+class Q_QML_PRIVATE_EXPORT EvalInstructionSelection
{
public:
EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
@@ -90,7 +90,7 @@ protected:
IR::Module *irModule;
};
-class Q_QML_EXPORT EvalISelFactory
+class Q_QML_PRIVATE_EXPORT EvalISelFactory
{
public:
virtual ~EvalISelFactory() = 0;
@@ -99,7 +99,7 @@ public:
};
namespace IR {
-class Q_QML_EXPORT IRDecoder: protected IR::StmtVisitor
+class Q_QML_PRIVATE_EXPORT IRDecoder: protected IR::StmtVisitor
{
public:
IRDecoder() : _function(0) {}
@@ -125,7 +125,7 @@ public: // to implement by subclasses:
virtual void callBuiltinReThrow() = 0;
virtual void callBuiltinUnwindException(IR::Temp *) = 0;
virtual void callBuiltinPushCatchScope(const QString &exceptionName) = 0;
- virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result) = 0;
+ virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result) = 0;
virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result) = 0;
virtual void callBuiltinPushWithScope(IR::Temp *arg) = 0;
virtual void callBuiltinPopScope() = 0;
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index be1714f2de..09b98a18d1 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -136,9 +136,11 @@ public:
{
_stackSlotForTemp.reserve(function->tempCount);
- foreach (IR::BasicBlock *bb, function->basicBlocks) {
+ foreach (IR::BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
_currentBasicBlock = bb;
- foreach (IR::Stmt *s, bb->statements)
+ foreach (IR::Stmt *s, bb->statements())
process(s);
}
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index d9d0742b68..5d30d6e3b9 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -42,12 +42,13 @@
#include "qv4jsir_p.h"
#include <private/qqmljsast_p.h>
+#ifndef V4_BOOTSTRAP
#include <private/qqmlpropertycache_p.h>
+#endif
#include <QtCore/qtextstream.h>
#include <QtCore/qdebug.h>
#include <QtCore/qset.h>
#include <cmath>
-#include <cassert>
#ifdef CONST
#undef CONST
@@ -165,11 +166,14 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
void operator()(IR::Function *function)
{
subexpressions.clear();
+ subexpressions.reserve(function->basicBlockCount() * 8);
- foreach (BasicBlock *block, function->basicBlocks) {
+ foreach (BasicBlock *block, function->basicBlocks()) {
+ if (block->isRemoved())
+ continue;
clone.setBasicBlock(block);
- foreach (Stmt *s, block->statements) {
+ foreach (Stmt *s, block->statements()) {
s->accept(this);
}
}
@@ -277,12 +281,14 @@ static QString dumpStart(const Expr *e) {
return QString();
QString result = typeName(e->type);
+#ifndef V4_BOOTSTRAP
const Temp *temp = const_cast<Expr*>(e)->asTemp();
if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) {
result += QLatin1Char('<');
result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
result += QLatin1Char('>');
}
+#endif
result += QLatin1Char('{');
return result;
}
@@ -555,8 +561,10 @@ void Member::dump(QTextStream &out) const
else
base->dump(out);
out << '.' << *name;
+#ifndef V4_BOOTSTRAP
if (property)
out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)";
+#endif
}
void Exp::dump(QTextStream &out, Mode)
@@ -587,7 +595,7 @@ void Move::dump(QTextStream &out, Mode mode)
void Jump::dump(QTextStream &out, Mode mode)
{
Q_UNUSED(mode);
- out << "goto " << 'L' << target->index << ';';
+ out << "goto " << 'L' << target->index() << ';';
}
void CJump::dump(QTextStream &out, Mode mode)
@@ -596,9 +604,9 @@ void CJump::dump(QTextStream &out, Mode mode)
out << "if (";
cond->dump(out);
if (mode == HIR)
- out << ") goto " << 'L' << iftrue->index << "; else goto " << 'L' << iffalse->index << ';';
+ out << ") goto " << 'L' << iftrue->index() << "; else goto " << 'L' << iffalse->index() << ';';
else
- out << ") goto " << 'L' << iftrue->index << ";";
+ out << ") goto " << 'L' << iftrue->index() << ";";
}
void Ret::dump(QTextStream &out, Mode)
@@ -632,7 +640,7 @@ Function *Module::newFunction(const QString &name, Function *outer)
functions.append(f);
if (!outer) {
if (!isQmlModule) {
- assert(!rootFunction);
+ Q_ASSERT(!rootFunction);
rootFunction = f;
}
} else {
@@ -655,15 +663,37 @@ void Module::setFileName(const QString &name)
}
}
+Function::Function(Module *module, Function *outer, const QString &name)
+ : module(module)
+ , pool(&module->pool)
+ , tempCount(0)
+ , maxNumberOfArguments(0)
+ , outer(outer)
+ , insideWithOrCatch(0)
+ , hasDirectEval(false)
+ , usesArgumentsObject(false)
+ , isStrict(false)
+ , isNamedExpression(false)
+ , hasTry(false)
+ , hasWith(false)
+ , unused(0)
+ , line(-1)
+ , column(-1)
+ , _allBasicBlocks(0)
+{
+ this->name = newString(name);
+ _basicBlocks.reserve(8);
+}
+
Function::~Function()
{
- // destroy the Stmt::Data blocks manually, because memory pool cleanup won't
- // call the Stmt destructors.
- foreach (IR::BasicBlock *b, basicBlocks)
- foreach (IR::Stmt *s, b->statements)
- s->destroyData();
+ if (_allBasicBlocks) {
+ qDeleteAll(*_allBasicBlocks);
+ delete _allBasicBlocks;
+ } else {
+ qDeleteAll(_basicBlocks);
+ }
- qDeleteAll(basicBlocks);
pool = 0;
module = 0;
}
@@ -677,7 +707,31 @@ const QString *Function::newString(const QString &text)
BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode)
{
BasicBlock *block = new BasicBlock(this, containingLoop, catchBlock);
- return mode == InsertBlock ? insertBasicBlock(block) : block;
+ return mode == InsertBlock ? addBasicBlock(block) : block;
+}
+
+BasicBlock *Function::addBasicBlock(BasicBlock *block)
+{
+ Q_ASSERT(block->index() < 0);
+ block->setIndex(_basicBlocks.size());
+ _basicBlocks.append(block);
+ return block;
+}
+
+void Function::removeBasicBlock(BasicBlock *block)
+{
+ block->markAsRemoved();
+ block->in.clear();
+ block->out.clear();
+}
+
+int Function::liveBasicBlocksCount() const
+{
+ int count = 0;
+ foreach (BasicBlock *bb, basicBlocks())
+ if (!bb->isRemoved())
+ ++count;
+ return count;
}
void Function::dump(QTextStream &out, Stmt::Mode mode)
@@ -690,7 +744,7 @@ void Function::dump(QTextStream &out, Stmt::Mode mode)
out << "\treceive " << *formal << ';' << endl;
foreach (const QString *local, locals)
out << "\tlocal " << *local << ';' << endl;
- foreach (BasicBlock *bb, basicBlocks)
+ foreach (BasicBlock *bb, basicBlocks())
bb->dump(out, mode);
out << '}' << endl;
}
@@ -709,13 +763,35 @@ int Function::indexOfArgument(const QStringRef &string) const
}
return -1;
}
+
+void Function::setScheduledBlocks(const QVector<BasicBlock *> &scheduled)
+{
+ Q_ASSERT(!_allBasicBlocks);
+ _allBasicBlocks = new QVector<BasicBlock *>(basicBlocks());
+ _basicBlocks = scheduled;
+}
+
+void Function::renumberBasicBlocks()
+{
+ for (int i = 0, ei = basicBlockCount(); i != ei; ++i)
+ basicBlock(i)->changeIndex(i);
+}
+
+BasicBlock::~BasicBlock()
+{
+ foreach (Stmt *s, _statements)
+ s->destroyData();
+}
+
unsigned BasicBlock::newTemp()
{
+ Q_ASSERT(!isRemoved());
return function->tempCount++;
}
Temp *BasicBlock::TEMP(unsigned index)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(Temp::VirtualRegister, index, 0);
return e;
@@ -723,6 +799,7 @@ Temp *BasicBlock::TEMP(unsigned index)
Temp *BasicBlock::ARG(unsigned index, unsigned scope)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(scope ? Temp::ScopedFormal : Temp::Formal, index, scope);
return e;
@@ -730,6 +807,7 @@ Temp *BasicBlock::ARG(unsigned index, unsigned scope)
Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(scope ? Temp::ScopedLocal : Temp::Local, index, scope);
return e;
@@ -737,6 +815,7 @@ Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
Expr *BasicBlock::CONST(Type type, double value)
{
+ Q_ASSERT(!isRemoved());
Const *e = function->New<Const>();
if (type == NumberType) {
int ival = (int)value;
@@ -745,13 +824,19 @@ Expr *BasicBlock::CONST(Type type, double value)
type = SInt32Type;
else
type = DoubleType;
+ } else if (type == NullType) {
+ value = 0;
+ } else if (type == UndefinedType) {
+ value = qSNaN();
}
+
e->init(type, value);
return e;
}
Expr *BasicBlock::STRING(const QString *value)
{
+ Q_ASSERT(!isRemoved());
String *e = function->New<String>();
e->init(value);
return e;
@@ -759,6 +844,7 @@ Expr *BasicBlock::STRING(const QString *value)
Expr *BasicBlock::REGEXP(const QString *value, int flags)
{
+ Q_ASSERT(!isRemoved());
RegExp *e = function->New<RegExp>();
e->init(value, flags);
return e;
@@ -766,6 +852,7 @@ Expr *BasicBlock::REGEXP(const QString *value, int flags)
Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->init(function->newString(id), line, column);
return e;
@@ -773,6 +860,7 @@ Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->initGlobal(function->newString(id), line, column);
return e;
@@ -781,6 +869,7 @@ Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->init(builtin, line, column);
return e;
@@ -788,6 +877,7 @@ Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
Closure *BasicBlock::CLOSURE(int functionInModule)
{
+ Q_ASSERT(!isRemoved());
Closure *clos = function->New<Closure>();
clos->init(functionInModule, function->module->functions.at(functionInModule)->name);
return clos;
@@ -795,6 +885,7 @@ Closure *BasicBlock::CLOSURE(int functionInModule)
Expr *BasicBlock::CONVERT(Expr *expr, Type type)
{
+ Q_ASSERT(!isRemoved());
Convert *e = function->New<Convert>();
e->init(expr, type);
return e;
@@ -802,6 +893,7 @@ Expr *BasicBlock::CONVERT(Expr *expr, Type type)
Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
{
+ Q_ASSERT(!isRemoved());
Unop *e = function->New<Unop>();
e->init(op, expr);
return e;
@@ -809,6 +901,7 @@ Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
{
+ Q_ASSERT(!isRemoved());
Binop *e = function->New<Binop>();
e->init(op, left, right);
return e;
@@ -816,6 +909,7 @@ Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
Expr *BasicBlock::CALL(Expr *base, ExprList *args)
{
+ Q_ASSERT(!isRemoved());
Call *e = function->New<Call>();
e->init(base, args);
int argc = 0;
@@ -827,6 +921,7 @@ Expr *BasicBlock::CALL(Expr *base, ExprList *args)
Expr *BasicBlock::NEW(Expr *base, ExprList *args)
{
+ Q_ASSERT(!isRemoved());
New *e = function->New<New>();
e->init(base, args);
return e;
@@ -834,6 +929,7 @@ Expr *BasicBlock::NEW(Expr *base, ExprList *args)
Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
{
+ Q_ASSERT(!isRemoved());
Subscript *e = function->New<Subscript>();
e->init(base, index);
return e;
@@ -841,6 +937,7 @@ Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue)
{
+ Q_ASSERT(!isRemoved());
Member*e = function->New<Member>();
e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue);
return e;
@@ -848,6 +945,7 @@ Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *prop
Stmt *BasicBlock::EXP(Expr *expr)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -859,6 +957,7 @@ Stmt *BasicBlock::EXP(Expr *expr)
Stmt *BasicBlock::MOVE(Expr *target, Expr *source)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -870,6 +969,7 @@ Stmt *BasicBlock::MOVE(Expr *target, Expr *source)
Stmt *BasicBlock::JUMP(BasicBlock *target)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -877,10 +977,10 @@ Stmt *BasicBlock::JUMP(BasicBlock *target)
s->init(target);
appendStatement(s);
- assert(! out.contains(target));
+ Q_ASSERT(! out.contains(target));
out.append(target);
- assert(! target->in.contains(this));
+ Q_ASSERT(! target->in.contains(this));
target->in.append(this);
return s;
@@ -888,6 +988,7 @@ Stmt *BasicBlock::JUMP(BasicBlock *target)
Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -900,16 +1001,16 @@ Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
s->init(cond, iftrue, iffalse);
appendStatement(s);
- assert(! out.contains(iftrue));
+ Q_ASSERT(! out.contains(iftrue));
out.append(iftrue);
- assert(! iftrue->in.contains(this));
+ Q_ASSERT(! iftrue->in.contains(this));
iftrue->in.append(this);
- assert(! out.contains(iffalse));
+ Q_ASSERT(! out.contains(iffalse));
out.append(iffalse);
- assert(! iffalse->in.contains(this));
+ Q_ASSERT(! iffalse->in.contains(this));
iffalse->in.append(this);
return s;
@@ -917,6 +1018,7 @@ Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
Stmt *BasicBlock::RET(Temp *expr)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -928,11 +1030,11 @@ Stmt *BasicBlock::RET(Temp *expr)
void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
{
- out << 'L' << index << ':';
+ out << 'L' << index() << ':';
if (catchBlock)
- out << " (catchBlock L" << catchBlock->index << ")";
+ out << " (catchBlock L" << catchBlock->index() << ")";
out << endl;
- foreach (Stmt *s, statements) {
+ foreach (Stmt *s, statements()) {
out << '\t';
s->dump(out, mode);
@@ -943,11 +1045,62 @@ void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
}
}
+void BasicBlock::setStatements(const QVector<Stmt *> &newStatements)
+{
+ Q_ASSERT(!isRemoved());
+ Q_ASSERT(newStatements.size() >= _statements.size());
+ _statements = newStatements;
+}
+
void BasicBlock::appendStatement(Stmt *statement)
{
+ Q_ASSERT(!isRemoved());
if (nextLocation.isValid())
statement->location = nextLocation;
- statements.append(statement);
+ _statements.append(statement);
+}
+
+void BasicBlock::prependStatement(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.prepend(stmt);
+}
+
+void BasicBlock::insertStatementBefore(Stmt *before, Stmt *newStmt)
+{
+ int idx = _statements.indexOf(before);
+ Q_ASSERT(idx >= 0);
+ _statements.insert(idx, newStmt);
+}
+
+void BasicBlock::insertStatementBefore(int index, Stmt *newStmt)
+{
+ Q_ASSERT(index >= 0);
+ _statements.insert(index, newStmt);
+}
+
+void BasicBlock::insertStatementBeforeTerminator(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.insert(_statements.size() - 1, stmt);
+}
+
+void BasicBlock::replaceStatement(int index, Stmt *newStmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements[index] = newStmt;
+}
+
+void BasicBlock::removeStatement(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.remove(_statements.indexOf(stmt));
+}
+
+void BasicBlock::removeStatement(int idx)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.remove(idx);
}
CloneExpr::CloneExpr(BasicBlock *block)
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index a333214a8b..398d5d5fa0 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -643,6 +643,8 @@ struct Stmt {
virtual Phi *asPhi() { return 0; }
virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
+private: // For memory management in BasicBlock
+ friend struct BasicBlock;
void destroyData() {
delete d;
d = 0;
@@ -742,7 +744,7 @@ struct Phi: Stmt {
virtual void dump(QTextStream &out, Mode mode);
};
-struct Q_QML_EXPORT Module {
+struct Q_QML_PRIVATE_EXPORT Module {
QQmlJS::MemoryPool pool;
QVector<Function *> functions;
Function *rootFunction;
@@ -762,122 +764,74 @@ struct Q_QML_EXPORT Module {
void setFileName(const QString &name);
};
-// Map from meta property index (existence implies dependency) to notify signal index
-typedef QHash<int, int> PropertyDependencyMap;
-
-struct Function {
- Module *module;
- QQmlJS::MemoryPool *pool;
- const QString *name;
- QVector<BasicBlock *> basicBlocks;
- int tempCount;
- int maxNumberOfArguments;
- QSet<QString> strings;
- QList<const QString *> formals;
- QList<const QString *> locals;
- QVector<Function *> nestedFunctions;
- Function *outer;
-
- int insideWithOrCatch;
-
- uint hasDirectEval: 1;
- uint usesArgumentsObject : 1;
- uint usesThis : 1;
- uint isStrict: 1;
- uint isNamedExpression : 1;
- uint hasTry: 1;
- uint hasWith: 1;
- uint unused : 25;
-
- // Location of declaration in source code (-1 if not specified)
- int line;
- int column;
-
- // Qml extension:
- QSet<int> idObjectDependencies;
- PropertyDependencyMap contextObjectPropertyDependencies;
- PropertyDependencyMap scopeObjectPropertyDependencies;
-
- template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
-
- Function(Module *module, Function *outer, const QString &name)
- : module(module)
- , pool(&module->pool)
- , tempCount(0)
- , maxNumberOfArguments(0)
- , outer(outer)
- , insideWithOrCatch(0)
- , hasDirectEval(false)
- , usesArgumentsObject(false)
- , isStrict(false)
- , isNamedExpression(false)
- , hasTry(false)
- , hasWith(false)
- , unused(0)
- , line(-1)
- , column(-1)
- { this->name = newString(name); }
-
- ~Function();
-
- enum BasicBlockInsertMode {
- InsertBlock,
- DontInsertBlock
- };
-
- BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
- const QString *newString(const QString &text);
-
- void RECEIVE(const QString &name) { formals.append(newString(name)); }
- void LOCAL(const QString &name) { locals.append(newString(name)); }
-
- inline BasicBlock *insertBasicBlock(BasicBlock *block) { basicBlocks.append(block); return block; }
-
- void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
-
- void removeSharedExpressions();
-
- int indexOfArgument(const QStringRef &string) const;
-
- bool variablesCanEscape() const
- { return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
-};
-
struct BasicBlock {
+private:
+ Q_DISABLE_COPY(BasicBlock)
+
+public:
Function *function;
BasicBlock *catchBlock;
- QVector<Stmt *> statements;
QVector<BasicBlock *> in;
QVector<BasicBlock *> out;
QBitArray liveIn;
QBitArray liveOut;
- int index;
- bool isExceptionHandler;
QQmlJS::AST::SourceLocation nextLocation;
BasicBlock(Function *function, BasicBlock *containingLoop, BasicBlock *catcher)
: function(function)
, catchBlock(catcher)
- , index(-1)
- , isExceptionHandler(false)
, _containingGroup(containingLoop)
+ , _index(-1)
+ , _isExceptionHandler(false)
, _groupStart(false)
+ , _isRemoved(false)
{}
- ~BasicBlock() {}
+ ~BasicBlock();
- template <typename Instr> inline Instr i(Instr i) { statements.append(i); return i; }
+ const QVector<Stmt *> &statements() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _statements;
+ }
+
+ int statementCount() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _statements.size();
+ }
+
+ void setStatements(const QVector<Stmt *> &newStatements);
+
+ template <typename Instr> inline Instr i(Instr i)
+ {
+ Q_ASSERT(!isRemoved());
+ appendStatement(i);
+ return i;
+ }
+
+ void appendStatement(Stmt *statement);
+ void prependStatement(Stmt *stmt);
+ void insertStatementBefore(Stmt *before, Stmt *newStmt);
+ void insertStatementBefore(int index, Stmt *newStmt);
+ void insertStatementBeforeTerminator(Stmt *stmt);
+ void replaceStatement(int index, Stmt *newStmt);
+ void removeStatement(Stmt *stmt);
+ void removeStatement(int idx);
inline bool isEmpty() const {
- return statements.isEmpty();
+ Q_ASSERT(!isRemoved());
+ return _statements.isEmpty();
}
inline Stmt *terminator() const {
- if (! statements.isEmpty() && statements.at(statements.size() - 1)->asTerminator() != 0)
- return statements.at(statements.size() - 1);
+ Q_ASSERT(!isRemoved());
+ if (! _statements.isEmpty() && _statements.last()->asTerminator() != 0)
+ return _statements.last();
return 0;
}
inline bool isTerminated() const {
+ Q_ASSERT(!isRemoved());
if (terminator() != 0)
return true;
return false;
@@ -918,20 +872,172 @@ struct BasicBlock {
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
- void appendStatement(Stmt *statement);
-
BasicBlock *containingGroup() const
- { return _containingGroup; }
+ {
+ Q_ASSERT(!isRemoved());
+ return _containingGroup;
+ }
+
+ void setContainingGroup(BasicBlock *loopHeader)
+ {
+ Q_ASSERT(!isRemoved());
+ _containingGroup = loopHeader;
+ }
bool isGroupStart() const
- { return _groupStart; }
+ {
+ Q_ASSERT(!isRemoved());
+ return _groupStart;
+ }
void markAsGroupStart()
- { _groupStart = true; }
+ {
+ Q_ASSERT(!isRemoved());
+ _groupStart = true;
+ }
+
+ // Returns the index of the basic-block.
+ // See Function for the full description.
+ int index() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _index;
+ }
+
+ bool isExceptionHandler() const
+ { return _isExceptionHandler; }
+
+ void setExceptionHandler(bool onoff)
+ { _isExceptionHandler = onoff; }
+
+ bool isRemoved() const
+ { return _isRemoved; }
+
+private: // For Function's eyes only.
+ friend struct Function;
+ void setIndex(int index)
+ {
+ Q_ASSERT(_index < 0);
+ changeIndex(index);
+ }
+
+ void changeIndex(int index)
+ {
+ Q_ASSERT(index >= 0);
+ _index = index;
+ }
+
+ void markAsRemoved()
+ {
+ _isRemoved = true;
+ _index = -1;
+ }
private:
+ QVector<Stmt *> _statements;
BasicBlock *_containingGroup;
- bool _groupStart;
+ int _index;
+ unsigned _isExceptionHandler : 1;
+ unsigned _groupStart : 1;
+ unsigned _isRemoved : 1;
+};
+
+// Map from meta property index (existence implies dependency) to notify signal index
+typedef QHash<int, int> PropertyDependencyMap;
+
+// The Function owns (manages), among things, a list of basic-blocks. All the blocks have an index,
+// which corresponds to the index in the entry/index in the vector in which they are stored. This
+// means that algorithms/classes can also store any information about a basic block in an array,
+// where the index corresponds to the index of the basic block, which can then be used to query
+// the function for a pointer to a basic block. This also means that basic-blocks cannot be removed
+// or renumbered.
+//
+// Note that currently there is one exception: after optimization and block scheduling, the
+// method setScheduledBlocks can be called once, to register a newly ordered list. For debugging
+// purposes, these blocks are not immediately renumbered, so renumberBasicBlocks should be called
+// immediately after changing the order. That will restore the property of having a corresponding
+// block-index and block-position-in-basicBlocks-vector.
+//
+// In order for optimization/transformation passes to skip uninteresting basic blocks that will be
+// removed, the block can be marked as such. After doing so, any access will result in a failing
+// assertion.
+struct Function {
+ Module *module;
+ QQmlJS::MemoryPool *pool;
+ const QString *name;
+ int tempCount;
+ int maxNumberOfArguments;
+ QSet<QString> strings;
+ QList<const QString *> formals;
+ QList<const QString *> locals;
+ QVector<Function *> nestedFunctions;
+ Function *outer;
+
+ int insideWithOrCatch;
+
+ uint hasDirectEval: 1;
+ uint usesArgumentsObject : 1;
+ uint usesThis : 1;
+ uint isStrict: 1;
+ uint isNamedExpression : 1;
+ uint hasTry: 1;
+ uint hasWith: 1;
+ uint unused : 25;
+
+ // Location of declaration in source code (-1 if not specified)
+ int line;
+ int column;
+
+ // Qml extension:
+ QSet<int> idObjectDependencies;
+ PropertyDependencyMap contextObjectPropertyDependencies;
+ PropertyDependencyMap scopeObjectPropertyDependencies;
+
+ template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
+
+ Function(Module *module, Function *outer, const QString &name);
+ ~Function();
+
+ enum BasicBlockInsertMode {
+ InsertBlock,
+ DontInsertBlock
+ };
+
+ BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
+ const QString *newString(const QString &text);
+
+ void RECEIVE(const QString &name) { formals.append(newString(name)); }
+ void LOCAL(const QString &name) { locals.append(newString(name)); }
+
+ BasicBlock *addBasicBlock(BasicBlock *block);
+ void removeBasicBlock(BasicBlock *block);
+
+ const QVector<BasicBlock *> &basicBlocks() const
+ { return _basicBlocks; }
+
+ BasicBlock *basicBlock(int idx) const
+ { return _basicBlocks.at(idx); }
+
+ int basicBlockCount() const
+ { return _basicBlocks.size(); }
+
+ int liveBasicBlocksCount() const;
+
+ void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
+
+ void removeSharedExpressions();
+
+ int indexOfArgument(const QStringRef &string) const;
+
+ bool variablesCanEscape() const
+ { return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
+
+ void setScheduledBlocks(const QVector<BasicBlock *> &scheduled);
+ void renumberBasicBlocks();
+
+private:
+ QVector<BasicBlock *> _basicBlocks;
+ QVector<BasicBlock *> *_allBasicBlocks;
};
class CloneExpr: protected IR::ExprVisitor
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index ca0bbb1bb3..84232a9ebb 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -54,9 +54,6 @@
#include <QtCore/QLinkedList>
#include <QtCore/QStack>
#include <qv4runtime_p.h>
-#include <qv4context_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmlengine_p.h>
#include <cmath>
#include <iostream>
#include <cassert>
@@ -82,11 +79,11 @@ void showMeTheCode(IR::Function *function)
QVector<Stmt *> code;
QHash<Stmt *, BasicBlock *> leader;
- foreach (BasicBlock *block, function->basicBlocks) {
- if (block->statements.isEmpty())
+ foreach (BasicBlock *block, function->basicBlocks()) {
+ if (block->isRemoved() || block->isEmpty())
continue;
- leader.insert(block->statements.first(), block);
- foreach (Stmt *s, block->statements) {
+ leader.insert(block->statements().first(), block);
+ foreach (Stmt *s, block->statements()) {
code.append(s);
}
}
@@ -118,11 +115,11 @@ void showMeTheCode(IR::Function *function)
qout << endl;
QByteArray str;
str.append('L');
- str.append(QByteArray::number(bb->index));
+ str.append(QByteArray::number(bb->index()));
str.append(':');
if (bb->catchBlock) {
str.append(" (exception handler L");
- str.append(QByteArray::number(bb->catchBlock->index));
+ str.append(QByteArray::number(bb->catchBlock->index()));
str.append(')');
}
for (int i = 66 - str.length(); i; --i)
@@ -130,11 +127,11 @@ void showMeTheCode(IR::Function *function)
qout << str;
qout << "// predecessor blocks:";
foreach (BasicBlock *in, bb->in)
- qout << " L" << in->index;
+ qout << " L" << in->index();
if (bb->in.isEmpty())
qout << "(none)";
if (BasicBlock *container = bb->containingGroup())
- qout << "; container block: L" << container->index;
+ qout << "; container block: L" << container->index();
if (bb->isGroupStart())
qout << "; group start";
qout << endl;
@@ -161,7 +158,7 @@ void showMeTheCode(IR::Function *function)
qout << endl;
if (n && s->asCJump()) {
- qout << " else goto L" << s->asCJump()->iffalse->index << ";" << endl;
+ qout << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl;
}
}
@@ -175,24 +172,21 @@ class ProcessedBlocks
QBitArray processed;
public:
- ProcessedBlocks(const QVector<BasicBlock *> allBlocks)
+ ProcessedBlocks(IR::Function *function)
{
- int maxBB = 0;
- foreach (BasicBlock *bb, allBlocks)
- maxBB = qMax(maxBB, bb->index);
- processed = QBitArray(maxBB + 1, false);
+ processed = QBitArray(function->basicBlockCount(), false);
}
bool alreadyProcessed(BasicBlock *bb) const
{
Q_ASSERT(bb);
- return processed.at(bb->index);
+ return processed.at(bb->index());
}
void markAsProcessed(BasicBlock *bb)
{
- processed.setBit(bb->index);
+ processed.setBit(bb->index());
}
};
@@ -226,7 +220,7 @@ class BasicBlockSet
Numbers *blockNumbers;
Flags *blockFlags;
- QVector<BasicBlock *> allBlocks;
+ IR::Function *function;
enum { MaxVectorCapacity = 8 };
// Q_DISABLE_COPY(BasicBlockSet); disabled because MSVC wants assignment operator for std::vector
@@ -268,10 +262,10 @@ public:
BasicBlock *operator*() const
{
if (set.blockNumbers) {
- return set.allBlocks.at(*numberIt);
+ return set.function->basicBlock(*numberIt);
} else {
Q_ASSERT(flagIt <= INT_MAX);
- return set.allBlocks.at(static_cast<int>(flagIt));
+ return set.function->basicBlock(static_cast<int>(flagIt));
}
}
@@ -308,22 +302,23 @@ public:
friend class const_iterator;
public:
- BasicBlockSet(): blockNumbers(0), blockFlags(0) {}
+ BasicBlockSet(): blockNumbers(0), blockFlags(0), function(0) {}
#ifdef Q_COMPILER_RVALUE_REFS
BasicBlockSet(BasicBlockSet &&other): blockNumbers(0), blockFlags(0)
{
std::swap(blockNumbers, other.blockNumbers);
std::swap(blockFlags, other.blockFlags);
- std::swap(allBlocks, other.allBlocks);
+ std::swap(function, other.function);
}
#endif // Q_COMPILER_RVALUE_REFS
~BasicBlockSet() { delete blockNumbers; delete blockFlags; }
- void init(const QVector<BasicBlock *> &nodes)
+ void init(IR::Function *f)
{
- Q_ASSERT(allBlocks.isEmpty());
- allBlocks = nodes;
+ Q_ASSERT(!function);
+ Q_ASSERT(f);
+ function = f;
blockNumbers = new Numbers;
blockNumbers->reserve(MaxVectorCapacity);
}
@@ -331,25 +326,25 @@ public:
void insert(BasicBlock *bb)
{
if (blockFlags) {
- (*blockFlags)[bb->index] = true;
+ (*blockFlags)[bb->index()] = true;
return;
}
for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end();
i != ei; ++i)
- if (*i == bb->index)
+ if (*i == bb->index())
return;
if (blockNumbers->size() == MaxVectorCapacity) {
- blockFlags = new Flags(allBlocks.size(), false);
+ blockFlags = new Flags(function->basicBlockCount(), false);
for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end();
i != ei; ++i)
blockFlags->operator[](*i) = true;
delete blockNumbers;
blockNumbers = 0;
- blockFlags->operator[](bb->index) = true;
+ blockFlags->operator[](bb->index()) = true;
} else {
- blockNumbers->push_back(bb->index);
+ blockNumbers->push_back(bb->index());
}
}
@@ -371,7 +366,7 @@ class DominatorTree {
typedef int BasicBlockIndex;
enum { InvalidBasicBlockIndex = -1 };
- QVector<BasicBlock *> nodes;
+ IR::Function *function;
int N;
std::vector<int> dfnum; // BasicBlock index -> dfnum
std::vector<int> vertex;
@@ -410,12 +405,12 @@ class DominatorTree {
vertex[N] = n;
parent[n] = todo.parent;
++N;
- const QVector<BasicBlock *> &out = nodes[n]->out;
+ const QVector<BasicBlock *> &out = function->basicBlock(n)->out;
for (int i = out.size() - 1; i > 0; --i)
- worklist.push_back(DFSTodo(out[i]->index, n));
+ worklist.push_back(DFSTodo(out[i]->index(), n));
if (out.size() > 0) {
- todo.node = out.first()->index;
+ todo.node = out.first()->index();
todo.parent = n;
continue;
}
@@ -463,21 +458,23 @@ class DominatorTree {
}
void calculateIDoms() {
- Q_ASSERT(nodes.first()->in.isEmpty());
-
- vertex = std::vector<int>(nodes.size(), InvalidBasicBlockIndex);
- parent = std::vector<int>(nodes.size(), InvalidBasicBlockIndex);
- dfnum = std::vector<int>(nodes.size(), 0);
- semi = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- ancestor = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- idom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- samedom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- best = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
+ Q_ASSERT(function->basicBlock(0)->in.isEmpty());
+
+ const int bbCount = function->basicBlockCount();
+ vertex = std::vector<int>(bbCount, InvalidBasicBlockIndex);
+ parent = std::vector<int>(bbCount, InvalidBasicBlockIndex);
+ dfnum = std::vector<int>(bbCount, 0);
+ semi = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ ancestor = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ idom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ samedom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ best = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
QHash<BasicBlockIndex, std::vector<BasicBlockIndex> > bucket;
+ bucket.reserve(bbCount);
- DFS(nodes.first()->index);
- Q_ASSERT(N == nodes.size()); // fails with unreachable nodes, but those should have been removed before.
+ DFS(function->basicBlock(0)->index());
+ Q_ASSERT(N == function->liveBasicBlocksCount());
std::vector<BasicBlockIndex> worklist;
worklist.reserve(vertex.capacity() / 2);
@@ -487,12 +484,12 @@ class DominatorTree {
BasicBlockIndex p = parent[n];
BasicBlockIndex s = p;
- foreach (BasicBlock *v, nodes.at(n)->in) {
+ foreach (BasicBlock *v, function->basicBlock(n)->in) {
BasicBlockIndex ss = InvalidBasicBlockIndex;
- if (dfnum[v->index] <= dfnum[n])
- ss = v->index;
+ if (dfnum[v->index()] <= dfnum[n])
+ ss = v->index();
else
- ss = semi[ancestorWithLowestSemi(v->index, worklist)];
+ ss = semi[ancestorWithLowestSemi(v->index(), worklist)];
if (dfnum[ss] < dfnum[s])
s = ss;
}
@@ -540,6 +537,7 @@ class DominatorTree {
qout << "(none)";
qout << " -> " << to->index << endl;
}
+ qout << "N = " << N << endl;
#endif // SHOW_SSA
}
@@ -551,10 +549,12 @@ class DominatorTree {
void computeDF() {
// compute children of each node in the dominator tree
std::vector<std::vector<BasicBlockIndex> > children; // BasicBlock index -> children
- children.resize(nodes.size());
- foreach (BasicBlock *n, nodes) {
- const BasicBlockIndex nodeIndex = n->index;
- Q_ASSERT(nodes.at(nodeIndex) == n);
+ children.resize(function->basicBlockCount());
+ foreach (BasicBlock *n, function->basicBlocks()) {
+ if (n->isRemoved())
+ continue;
+ const BasicBlockIndex nodeIndex = n->index();
+ Q_ASSERT(function->basicBlock(nodeIndex) == n);
const BasicBlockIndex nodeDominator = idom[nodeIndex];
if (nodeDominator == InvalidBasicBlockIndex)
continue; // there is no dominator to add this node to as a child (e.g. the start node)
@@ -563,18 +563,20 @@ class DominatorTree {
// Fill the worklist and initialize the node status for each basic-block
QHash<BasicBlockIndex, NodeProgress> nodeStatus;
- nodeStatus.reserve(nodes.size());
+ nodeStatus.reserve(function->basicBlockCount());
std::vector<BasicBlockIndex> worklist;
- worklist.reserve(nodes.size() * 2);
- for (int i = 0, ei = nodes.size(); i != ei; ++i) {
- BasicBlockIndex nodeIndex = nodes.at(i)->index;
+ worklist.reserve(function->basicBlockCount() * 2);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+ BasicBlockIndex nodeIndex = bb->index();
worklist.push_back(nodeIndex);
NodeProgress &np = nodeStatus[nodeIndex];
np.children = children[nodeIndex];
np.todo = children[nodeIndex];
}
- std::vector<bool> DF_done(nodes.size(), false);
+ std::vector<bool> DF_done(function->basicBlockCount(), false);
while (!worklist.empty()) {
BasicBlockIndex node = worklist.back();
@@ -597,16 +599,16 @@ class DominatorTree {
if (np.todo.empty()) {
BasicBlockSet &S = DF[node];
- S.init(nodes);
- foreach (BasicBlock *y, nodes.at(node)->out)
- if (idom[y->index] != node)
+ S.init(function);
+ foreach (BasicBlock *y, function->basicBlock(node)->out)
+ if (idom[y->index()] != node)
S.insert(y);
foreach (BasicBlockIndex child, np.children) {
const BasicBlockSet &ws = DF[child];
for (BasicBlockSet::const_iterator it = ws.begin(), eit = ws.end(); it != eit; ++it) {
BasicBlock *w = *it;
- const BasicBlockIndex wIndex = w->index;
- if (node == wIndex || !dominates(node, w->index))
+ const BasicBlockIndex wIndex = w->index();
+ if (node == wIndex || !dominates(node, w->index()))
S.insert(w);
}
}
@@ -651,21 +653,21 @@ class DominatorTree {
}
public:
- DominatorTree(const QVector<BasicBlock *> &nodes)
- : nodes(nodes)
+ DominatorTree(IR::Function *function)
+ : function(function)
, N(0)
{
- DF.resize(nodes.size());
+ DF.resize(function->basicBlockCount());
calculateIDoms();
computeDF();
}
const BasicBlockSet &dominatorFrontier(BasicBlock *n) const {
- return DF[n->index];
+ return DF[n->index()];
}
BasicBlock *immediateDominator(BasicBlock *bb) const {
- return nodes[idom[bb->index]];
+ return function->basicBlock(idom[bb->index()]);
}
void dumpImmediateDominators() const
@@ -680,46 +682,30 @@ public:
void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator)
{
- Q_ASSERT(bb->index >= 0);
+ Q_ASSERT(bb->index() >= 0);
- int blockIndex;
- if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index) >= idom.size()) {
+ if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index()) >= idom.size()) {
// This is a new block, probably introduced by edge splitting. So, we'll have to grow
// the array before inserting the immediate dominator.
- nodes.append(bb);
- idom.resize(nodes.size(), InvalidBasicBlockIndex);
- blockIndex = nodes.size() - 1;
- } else {
- blockIndex = getBlockIndex(bb);
+ idom.resize(function->basicBlockCount(), InvalidBasicBlockIndex);
}
- idom[blockIndex] = getBlockIndex(newDominator);
+ idom[bb->index()] = newDominator->index();
}
bool dominates(BasicBlock *dominator, BasicBlock *dominated) const {
- // The index of the basic blocks might have changed, or the nodes array might have changed,
- // so get the index from our copy of the array.
- return dominates(getBlockIndex(dominator), getBlockIndex(dominated));
+ return dominates(dominator->index(), dominated->index());
}
private:
- int getBlockIndex(BasicBlock *bb) const {
- if (!bb)
- return InvalidBasicBlockIndex;
-
- if (bb->index >= 0 && bb->index < nodes.size()) {
- if (nodes.at(bb->index) == bb)
- return bb->index;
- }
-
- return nodes.indexOf(bb);
- }
-
bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const {
// dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
Q_ASSERT(dominated != InvalidBasicBlockIndex);
- for (BasicBlockIndex it = dominated; it != InvalidBasicBlockIndex; it = idom[it]) {
+ if (dominator == dominated)
+ return false;
+
+ for (BasicBlockIndex it = idom[dominated]; it != InvalidBasicBlockIndex; it = idom[it]) {
if (it == dominator)
return true;
}
@@ -729,8 +715,9 @@ private:
};
class VariableCollector: public StmtVisitor, ExprVisitor {
- QHash<Temp, QSet<BasicBlock *> > _defsites;
- QHash<BasicBlock *, QSet<Temp> > A_orig;
+ typedef QHash<Temp, QSet<BasicBlock *> > DefSites;
+ DefSites _defsites;
+ QVector<QSet<Temp> > A_orig;
QSet<Temp> nonLocals;
QSet<Temp> killed;
@@ -747,16 +734,22 @@ public:
: function(function)
{
_defsites.reserve(function->tempCount);
+ A_orig.resize(function->basicBlockCount());
+ for (int i = 0, ei = A_orig.size(); i != ei; ++i)
+ A_orig[i].reserve(8);
#if defined(SHOW_SSA)
qout << "Variables collected:" << endl;
#endif // SHOW_SSA
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
currentBB = bb;
killed.clear();
- killed.reserve(bb->statements.size() / 2);
- foreach (Stmt *s, bb->statements) {
+ killed.reserve(bb->statements().size() / 2);
+ foreach (Stmt *s, bb->statements()) {
s->accept(this);
}
}
@@ -782,7 +775,7 @@ public:
}
QSet<Temp> inBlock(BasicBlock *n) const {
- return A_orig[n];
+ return A_orig.at(n->index());
}
bool isNonLocal(const Temp &var) const { return nonLocals.contains(var); }
@@ -828,8 +821,15 @@ protected:
qout << " -> L" << currentBB->index << endl;
#endif // SHOW_SSA
- _defsites[*t].insert(currentBB);
- A_orig[currentBB].insert(*t);
+ DefSites::iterator defsitesIt = _defsites.find(*t);
+ if (defsitesIt == _defsites.end()) {
+ QSet<BasicBlock *> bbs;
+ bbs.reserve(4);
+ defsitesIt = _defsites.insert(*t, bbs);
+ }
+ defsitesIt->insert(currentBB);
+
+ A_orig[currentBB->index()].insert(*t);
// For semi-pruned SSA:
killed.insert(*t);
@@ -858,7 +858,7 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) {
phiNode->d = new Stmt::Data;
phiNode->targetTemp = f->New<Temp>();
phiNode->targetTemp->init(a.kind, a.index, 0);
- y->statements.prepend(phiNode);
+ y->prependStatement(phiNode);
phiNode->d->incoming.resize(y->in.size());
for (int i = 0, ei = y->in.size(); i < ei; ++i) {
@@ -997,15 +997,15 @@ public:
VariableRenamer(IR::Function *f)
: function(f)
, tempCount(0)
- , processed(f->basicBlocks)
+ , processed(f)
{
localMapping.reserve(f->tempCount);
vregMapping.reserve(f->tempCount);
- todo.reserve(f->basicBlocks.size());
+ todo.reserve(f->basicBlockCount());
}
void run() {
- todo.append(TodoAction(function->basicBlocks.first()));
+ todo.append(TodoAction(function->basicBlock(0)));
while (!todo.isEmpty()) {
TodoAction todoAction = todo.back();
@@ -1060,13 +1060,13 @@ private:
void renameStatementsAndPhis(BasicBlock *bb)
{
- foreach (Stmt *s, bb->statements)
+ foreach (Stmt *s, bb->statements())
s->accept(this);
foreach (BasicBlock *Y, bb->out) {
const int j = Y->in.indexOf(bb);
Q_ASSERT(j >= 0 && j < Y->in.size());
- foreach (Stmt *s, Y->statements) {
+ foreach (Stmt *s, Y->statements()) {
if (Phi *phi = s->asPhi()) {
Temp *t = phi->d->incoming[j]->asTemp();
unsigned newTmp = currentNumber(*t);
@@ -1201,7 +1201,7 @@ protected:
void convertToSSA(IR::Function *function, const DominatorTree &df)
{
-#ifdef SHOW_SSA
+#if defined(SHOW_SSA)
qout << "Converting function ";
if (function->name)
qout << *function->name;
@@ -1213,8 +1213,16 @@ void convertToSSA(IR::Function *function, const DominatorTree &df)
// Collect all applicable variables:
VariableCollector variables(function);
+ // Prepare for phi node insertion:
+ QVector<QSet<Temp> > A_phi;
+ A_phi.resize(function->basicBlockCount());
+ for (int i = 0, ei = A_phi.size(); i != ei; ++i) {
+ QSet<Temp> temps;
+ temps.reserve(4);
+ A_phi[i] = temps;
+ }
+
// Place phi functions:
- QHash<BasicBlock *, QSet<Temp> > A_phi;
foreach (Temp a, variables.vars()) {
if (!variables.isNonLocal(a))
continue; // for semi-pruned SSA
@@ -1227,9 +1235,9 @@ void convertToSSA(IR::Function *function, const DominatorTree &df)
for (BasicBlockSet::const_iterator it = dominatorFrontierForN.begin(), eit = dominatorFrontierForN.end();
it != eit; ++it) {
BasicBlock *y = *it;
- if (!A_phi[y].contains(a)) {
+ if (!A_phi.at(y->index()).contains(a)) {
insertPhiNode(a, y, function);
- A_phi[y].insert(a);
+ A_phi[y->index()].insert(a);
if (!variables.inBlock(y).contains(a))
W.append(y);
}
@@ -1267,7 +1275,8 @@ public:
private:
IR::Function *function;
- QHash<UntypedTemp, DefUse> _defUses;
+ typedef QHash<UntypedTemp, DefUse> DefUses;
+ DefUses _defUses;
QHash<Stmt *, QList<Temp> > _usesPerStatement;
BasicBlock *_block;
@@ -1302,9 +1311,12 @@ public:
DefUsesCalculator(IR::Function *function)
: function(function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
_block = bb;
- foreach (Stmt *stmt, bb->statements) {
+ foreach (Stmt *stmt, bb->statements()) {
_stmt = stmt;
stmt->accept(this);
}
@@ -1360,8 +1372,16 @@ public:
QList<Temp> usedVars(Stmt *s) const
{ return _usesPerStatement[s]; }
- QList<Stmt *> uses(const UntypedTemp &var) const
- { return _defUses[var].uses; }
+ const QList<Stmt *> &uses(const UntypedTemp &var) const
+ {
+ static const QList<Stmt *> noUses;
+
+ DefUses::const_iterator it = _defUses.find(var);
+ if (it == _defUses.end())
+ return noUses;
+ else
+ return it->uses;
+ }
QVector<Stmt*> removeDefUses(Stmt *s)
{
@@ -1386,7 +1406,7 @@ public:
foreach (const UntypedTemp &var, _defUses.keys()) {
const DefUse &du = _defUses[var];
var.temp.dump(qout);
- qout<<" -> defined in block "<<du.blockOfStatement->index<<", statement: ";
+ qout<<" -> defined in block "<<du.blockOfStatement->index()<<", statement: ";
du.defStmt->dump(qout);
qout<<endl<<" uses:"<<endl;
foreach (Stmt *s, du.uses) {
@@ -1478,10 +1498,7 @@ void cleanupPhis(DefUsesCalculator &defUses)
foreach (Phi *phi, toRemove) {
Temp targetVar = *phi->targetTemp;
- BasicBlock *bb = defUses.defStmtBlock(targetVar);
- int idx = bb->statements.indexOf(phi);
- bb->statements[idx]->destroyData();
- bb->statements.remove(idx);
+ defUses.defStmtBlock(targetVar)->removeStatement(phi);
foreach (const Temp &usedVar, defUses.usedVars(phi))
defUses.removeUse(phi, usedVar);
@@ -1493,7 +1510,10 @@ class StatementWorklist
{
QVector<Stmt *> worklist;
QBitArray inWorklist;
- QHash<Stmt*,Stmt**> ref;
+ QSet<Stmt *> removed;
+ QHash<Stmt*,Stmt*> replaced;
+
+ Q_DISABLE_COPY(StatementWorklist)
public:
StatementWorklist(IR::Function *function)
@@ -1503,12 +1523,13 @@ public:
// Put in all statements, and number them on the fly. The numbering is used to index the
// bit array.
- foreach (BasicBlock *bb, function->basicBlocks) {
- for (int i = 0, ei = bb->statements.size(); i != ei; ++i) {
- Stmt **s = &bb->statements[i];
- (*s)->id = stmtCount++;
- w.append(*s);
- ref.insert(*s, s);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ foreach (Stmt *s, bb->statements()) {
+ s->id = stmtCount++;
+ w.append(s);
}
}
@@ -1527,29 +1548,40 @@ public:
void clear(Stmt *stmt)
{
Q_ASSERT(!inWorklist.at(stmt->id));
- *ref[stmt] = 0;
+ removed.insert(stmt);
}
void replace(Stmt *oldStmt, Stmt *newStmt)
{
Q_ASSERT(oldStmt);
Q_ASSERT(newStmt);
+ Q_ASSERT(!removed.contains(oldStmt));
if (newStmt->id == -1)
newStmt->id = oldStmt->id;
- *ref[oldStmt] = newStmt;
+ QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(oldStmt);
+ if (it != replaced.end())
+ oldStmt = it.key();
+ replaced[oldStmt] = newStmt;
}
void cleanup(IR::Function *function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
- for (int i = 0; i < bb->statements.size();) {
- if (bb->statements[i]) {
- bb->statements[i]->id = -1;
- ++i;
- } else {
- bb->statements.remove(i);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ for (int i = 0; i < bb->statementCount();) {
+ Stmt *stmt = bb->statements()[i];
+ QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(stmt);
+ if (it != replaced.end() && !removed.contains(it.value())) {
+ bb->replaceStatement(i, it.value());
+ } else if (removed.contains(stmt)) {
+ bb->removeStatement(i);
+ continue;
}
+
+ ++i;
}
}
}
@@ -1849,8 +1881,9 @@ class TypeInference: public StmtVisitor, public ExprVisitor {
QQmlEnginePrivate *qmlEngine;
IR::Function *function;
const DefUsesCalculator &_defUses;
- QHash<Temp, DiscoveredType> _tempTypes;
- QSet<Stmt *> _worklist;
+ typedef QHash<Temp, DiscoveredType> TempTypes;
+ TempTypes _tempTypes;
+ QList<Stmt *> _worklist;
struct TypingResult {
DiscoveredType type;
bool fullyTyped;
@@ -1872,26 +1905,29 @@ public:
// TODO: the worklist handling looks a bit inefficient... check if there is something better
_worklist.clear();
- for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (bb->isRemoved())
+ continue;
if (i == 0 || !bb->in.isEmpty())
- foreach (Stmt *s, bb->statements)
- if (!s->asJump())
- _worklist.insert(s);
+ _worklist += bb->statements().toList();
}
while (!_worklist.isEmpty()) {
- QList<Stmt *> worklist = _worklist.values();
+ QList<Stmt *> worklist = QSet<Stmt *>::fromList(_worklist).toList();
_worklist.clear();
while (!worklist.isEmpty()) {
Stmt *s = worklist.first();
worklist.removeFirst();
+ if (s->asJump())
+ continue;
+
#if defined(SHOW_SSA)
qout<<"Typing stmt ";s->dump(qout);qout<<endl;
#endif
if (!run(s)) {
- _worklist.insert(s);
+ _worklist += s;
#if defined(SHOW_SSA)
qout<<"Pushing back stmt: ";
s->dump(qout);qout<<endl;
@@ -1942,8 +1978,11 @@ private:
#endif
if (isAlwaysVar(t))
ty = DiscoveredType(VarType);
- if (_tempTypes[*t] != ty) {
- _tempTypes[*t] = ty;
+ TempTypes::iterator it = _tempTypes.find(*t);
+ if (it == _tempTypes.end())
+ it = _tempTypes.insert(*t, DiscoveredType());
+ if (it.value() != ty) {
+ it.value() = ty;
#if defined(SHOW_SSA)
foreach (Stmt *s, _defUses.uses(*t)) {
@@ -1953,7 +1992,7 @@ private:
}
#endif
- _worklist += QSet<Stmt *>::fromList(_defUses.uses(*t));
+ _worklist += _defUses.uses(*t);
}
} else {
e->type = (Type) ty.type;
@@ -2243,7 +2282,7 @@ public:
private:
bool isUsedAsInt32(const UntypedTemp &t, const QVector<UntypedTemp> &knownOk) const
{
- QList<Stmt *> uses = _defUses.uses(t);
+ const QList<Stmt *> &uses = _defUses.uses(t);
if (uses.isEmpty())
return false;
@@ -2305,6 +2344,10 @@ void convertConst(Const *c, Type targetType)
case BoolType:
c->value = !(c->value == 0 || std::isnan(c->value));
break;
+ case NullType:
+ case UndefinedType:
+ c->value = qSNaN();
+ c->type = targetType;
default:
Q_UNIMPLEMENTED();
Q_ASSERT(!"Unimplemented!");
@@ -2369,10 +2412,12 @@ public:
void run(IR::Function *f) {
_f = f;
- foreach (BasicBlock *bb, f->basicBlocks) {
+ foreach (BasicBlock *bb, f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
_conversions.clear();
- foreach (Stmt *s, bb->statements) {
+ foreach (Stmt *s, bb->statements()) {
_currStmt = s;
s->accept(this);
}
@@ -2403,11 +2448,9 @@ public:
if (Phi *phi = conversion.stmt->asPhi()) {
int idx = phi->d->incoming.indexOf(t);
Q_ASSERT(idx != -1);
- QVector<Stmt *> &stmts = bb->in[idx]->statements;
- stmts.insert(stmts.size() - 1, convCall);
+ bb->in[idx]->insertStatementBeforeTerminator(convCall);
} else {
- int idx = bb->statements.indexOf(conversion.stmt);
- bb->statements.insert(idx, convCall);
+ bb->insertStatementBefore(conversion.stmt, convCall);
}
*conversion.expr = source;
@@ -2428,9 +2471,7 @@ public:
_defUses.removeUse(move, *unopOperand);
}
- int idx = bb->statements.indexOf(conversion.stmt);
- Q_ASSERT(idx != -1);
- bb->statements.insert(idx, extraMove);
+ bb->insertStatementBefore(conversion.stmt, extraMove);
*conversion.expr = bb->CONVERT(tmp, conversion.targetType);
_defUses.addUse(*tmp, move);
@@ -2562,56 +2603,55 @@ protected:
void splitCriticalEdges(IR::Function *f, DominatorTree &df)
{
- for (int i = 0, ei = f->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = f->basicBlocks[i];
- if (bb->in.size() > 1) {
- for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
- BasicBlock *inBB = bb->in[inIdx];
- if (inBB->out.size() > 1) { // this should have been split!
- int newIndex = f->basicBlocks.last()->index + 1;
-#if defined(SHOW_SSA)
- qDebug() << "Splitting edge from block" << inBB->index << "to block" << bb->index << "by introducing block" << newIndex;
-#endif
+ foreach (BasicBlock *bb, f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+ if (bb->in.size() < 2)
+ continue;
- BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
-
- // create the basic block:
- BasicBlock *newBB = new BasicBlock(f, containingGroup, bb->catchBlock);
- newBB->index = newIndex;
- f->basicBlocks.append(newBB);
- Jump *s = f->New<Jump>();
- s->init(bb);
- newBB->statements.append(s);
-
- // rewire the old outgoing edge
- int outIdx = inBB->out.indexOf(bb);
- inBB->out[outIdx] = newBB;
- newBB->in.append(inBB);
-
- // rewire the old incoming edge
- bb->in[inIdx] = newBB;
- newBB->out.append(bb);
-
- // patch the terminator
- Stmt *terminator = inBB->terminator();
- if (Jump *j = terminator->asJump()) {
- Q_ASSERT(outIdx == 0);
- j->target = newBB;
- } else if (CJump *j = terminator->asCJump()) {
- if (outIdx == 0)
- j->iftrue = newBB;
- else if (outIdx == 1)
- j->iffalse = newBB;
- else
- Q_ASSERT(!"Invalid out edge index for CJUMP!");
- } else {
- Q_ASSERT(!"Unknown terminator!");
- }
+ for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
+ BasicBlock *inBB = bb->in[inIdx];
+ if (inBB->out.size() < 2)
+ continue;
- // Set the immediate dominator of the new block to inBB
- df.updateImmediateDominator(newBB, inBB);
- }
+ // We found a critical edge.
+ BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
+
+ // create the basic block:
+ BasicBlock *newBB = f->newBasicBlock(containingGroup, bb->catchBlock);
+ Jump *s = f->New<Jump>();
+ s->init(bb);
+ newBB->appendStatement(s);
+
+ // rewire the old outgoing edge
+ int outIdx = inBB->out.indexOf(bb);
+ inBB->out[outIdx] = newBB;
+ newBB->in.append(inBB);
+
+ // rewire the old incoming edge
+ bb->in[inIdx] = newBB;
+ newBB->out.append(bb);
+
+ // patch the terminator
+ Stmt *terminator = inBB->terminator();
+ if (Jump *j = terminator->asJump()) {
+ Q_ASSERT(outIdx == 0);
+ j->target = newBB;
+ } else if (CJump *j = terminator->asCJump()) {
+ if (outIdx == 0)
+ j->iftrue = newBB;
+ else if (outIdx == 1)
+ j->iffalse = newBB;
+ else
+ Q_ASSERT(!"Invalid out edge index for CJUMP!");
+ } else if (terminator->asRet()) {
+ Q_ASSERT(!"A block with a RET at the end cannot have outgoing edges.");
+ } else {
+ Q_ASSERT(!"Unknown terminator!");
}
+
+ // Set the immediate dominator of the new block to inBB
+ df.updateImmediateDominator(newBB, inBB);
}
}
}
@@ -2704,6 +2744,7 @@ class BlockScheduler
void emitBlock(BasicBlock *bb)
{
+ Q_ASSERT(!bb->isRemoved());
if (emitted.alreadyProcessed(bb))
return;
@@ -2751,22 +2792,24 @@ public:
BlockScheduler(IR::Function *function, const DominatorTree &dominatorTree)
: function(function)
, dominatorTree(dominatorTree)
- , emitted(function->basicBlocks)
+ , sequence(0)
+ , emitted(function)
{}
QHash<BasicBlock *, BasicBlock *> go()
{
showMeTheCode(function);
- schedule(function->basicBlocks.first());
+ schedule(function->basicBlock(0));
#if defined(SHOW_SSA)
qDebug() << "Block sequence:";
foreach (BasicBlock *bb, sequence)
- qDebug("\tL%d", bb->index);
+ qDebug("\tL%d", bb->index());
#endif // SHOW_SSA
- Q_ASSERT(function->basicBlocks.size() == sequence.size());
- function->basicBlocks = sequence;
+ Q_ASSERT(function->liveBasicBlocksCount() == sequence.size());
+ function->setScheduledBlocks(sequence);
+ function->renumberBasicBlocks();
return loopsStartEnd;
}
};
@@ -2778,7 +2821,7 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
foreach (BasicBlock *bb2, bb->out) {
if (bb2 && bb2->in.size() > 1) {
qout << "found critical edge between block "
- << bb->index << " and block " << bb2->index;
+ << bb->index() << " and block " << bb2->index();
Q_ASSERT(false);
}
}
@@ -2787,51 +2830,50 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
}
#endif
-void cleanupBasicBlocks(IR::Function *function, bool renumber)
+void cleanupBasicBlocks(IR::Function *function)
{
showMeTheCode(function);
// Algorithm: this is the iterative version of a depth-first search for all blocks that are
// reachable through outgoing edges, starting with the start block and all exception handler
// blocks.
- QSet<BasicBlock *> postponed, done;
- QSet<BasicBlock *> toRemove;
- toRemove.reserve(function->basicBlocks.size());
- done.reserve(function->basicBlocks.size());
- postponed.reserve(8);
- for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = function->basicBlocks[i];
- if (i == 0 || bb->isExceptionHandler)
- postponed.insert(bb);
- else
- toRemove.insert(bb);
+ QBitArray reachableBlocks(function->basicBlockCount());
+ QVector<BasicBlock *> postponed;
+ postponed.reserve(16);
+ for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (i == 0 || bb->isExceptionHandler())
+ postponed.append(bb);
}
while (!postponed.isEmpty()) {
- QSet<BasicBlock *>::iterator it = postponed.begin();
- BasicBlock *bb = *it;
- postponed.erase(it);
- done.insert(bb);
+ BasicBlock *bb = postponed.back();
+ postponed.pop_back();
+ if (bb->isRemoved()) // this block was removed before, we don't need to clean it up.
+ continue;
+
+ reachableBlocks.setBit(bb->index());
foreach (BasicBlock *outBB, bb->out) {
- if (!done.contains(outBB)) {
- postponed.insert(outBB);
- toRemove.remove(outBB);
- }
+ if (!reachableBlocks.at(outBB->index()))
+ postponed.append(outBB);
}
}
- foreach (BasicBlock *bb, toRemove) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved()) // the block has already been removed, so ignore it
+ continue;
+ if (reachableBlocks.at(bb->index())) // the block is reachable, so ignore it
+ continue;
+
foreach (BasicBlock *outBB, bb->out) {
- if (toRemove.contains(outBB))
+ if (outBB->isRemoved() || !reachableBlocks.at(outBB->index()))
continue; // We do not need to unlink from blocks that are scheduled to be removed.
- // Actually, it is potentially dangerous: if that block was already
- // destroyed, this could result in a use-after-free.
int idx = outBB->in.indexOf(bb);
if (idx != -1) {
outBB->in.remove(idx);
- foreach (Stmt *s, outBB->statements) {
+ foreach (Stmt *s, outBB->statements()) {
if (Phi *phi = s->asPhi())
phi->d->incoming.remove(idx);
else
@@ -2840,18 +2882,9 @@ void cleanupBasicBlocks(IR::Function *function, bool renumber)
}
}
- foreach (Stmt *s, bb->statements)
- s->destroyData();
- int idx = function->basicBlocks.indexOf(bb);
- if (idx != -1)
- function->basicBlocks.remove(idx);
- delete bb;
+ function->removeBasicBlock(bb);
}
- if (renumber)
- for (int i = 0; i < function->basicBlocks.size(); ++i)
- function->basicBlocks[i]->index = i;
-
showMeTheCode(function);
}
@@ -2904,7 +2937,7 @@ public:
, _replacement(0)
{}
- QVector<Stmt *> operator()(Temp *toReplace, Expr *replacement)
+ void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QList<Stmt *> *newUses = 0)
{
Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName());
@@ -2913,20 +2946,22 @@ public:
qSwap(_toReplace, toReplace);
qSwap(_replacement, replacement);
- QList<Stmt *> uses = _defUses.uses(*_toReplace);
+ const QList<Stmt *> &uses = _defUses.uses(*_toReplace);
+ if (newUses)
+ newUses->reserve(uses.size());
+
// qout << " " << uses.size() << " uses:"<<endl;
- QVector<Stmt *> result;
- result.reserve(uses.size());
foreach (Stmt *use, uses) {
// qout<<" ";use->dump(qout);qout<<"\n";
use->accept(this);
// qout<<" -> ";use->dump(qout);qout<<"\n";
- result.append(use);
+ W += use;
+ if (newUses)
+ newUses->append(use);
}
qSwap(_replacement, replacement);
qSwap(_toReplace, toReplace);
- return result;
}
protected:
@@ -2991,6 +3026,11 @@ private:
}
}
+ if (e1->type == IR::NullType && e2->type == IR::NullType)
+ return true;
+ if (e1->type == IR::UndefinedType && e2->type == IR::UndefinedType)
+ return true;
+
return false;
}
};
@@ -3003,28 +3043,24 @@ namespace {
void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, StatementWorklist &W,
DominatorTree &df)
{
- // TODO: change this to mark the block as deleted, but leave it alone so that other references
- // won't be dangling pointers.
// TODO: after the change above: if we keep on detaching the block from predecessors or
// successors, update the DominatorTree too.
// don't purge blocks that are entry points for catch statements. They might not be directly
// connected, but are required anyway
- if (bb->isExceptionHandler)
+ if (bb->isExceptionHandler())
return;
QVector<BasicBlock *> toPurge;
+ toPurge.reserve(8);
toPurge.append(bb);
while (!toPurge.isEmpty()) {
bb = toPurge.first();
toPurge.removeFirst();
- int bbIdx = func->basicBlocks.indexOf(bb);
- if (bbIdx == -1)
+ if (bb->isRemoved())
continue;
- else
- func->basicBlocks.remove(bbIdx);
// unlink all incoming edges
foreach (BasicBlock *in, bb->in) {
@@ -3038,7 +3074,7 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta
int idx = out->in.indexOf(bb);
if (idx != -1) {
out->in.remove(idx);
- foreach (Stmt *outStmt, out->statements) {
+ foreach (Stmt *outStmt, out->statements()) {
if (!outStmt)
continue;
if (Phi *phi = outStmt->asPhi()) {
@@ -3063,19 +3099,15 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta
}
// unlink all defs/uses from the statements in the basic block
- foreach (Stmt *s, bb->statements) {
+ foreach (Stmt *s, bb->statements()) {
if (!s)
continue;
W += defUses.removeDefUses(s);
W -= s;
-
- // clean-up the statement's data
- s->destroyData();
}
- bb->statements.clear();
- delete bb;
+ func->removeBasicBlock(bb);
}
}
@@ -3116,18 +3148,20 @@ bool tryOptimizingComparison(Expr *&expr)
expr = leftConst;
return true;
case OpStrictEqual:
- if (!strictlyEqualTypes(leftConst->type, rightConst->type))
- return false;
- // intentional fall-through
+ leftConst->value = Runtime::compareStrictEqual(&l, &r);
+ leftConst->type = BoolType;
+ expr = leftConst;
+ return true;
case OpEqual:
leftConst->value = Runtime::compareEqual(&l, &r);
leftConst->type = BoolType;
expr = leftConst;
return true;
case OpStrictNotEqual:
- if (!strictlyEqualTypes(leftConst->type, rightConst->type))
- return false;
- // intentional fall-through
+ leftConst->value = Runtime::compareStrictNotEqual(&l, &r);
+ leftConst->type = BoolType;
+ expr = leftConst;
+ return true;
case OpNotEqual:
leftConst->value = Runtime::compareNotEqual(&l, &r);
leftConst->type = BoolType;
@@ -3154,7 +3188,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
if (Phi *phi = s->asPhi()) {
// constant propagation:
if (Const *c = isConstPhi(phi)) {
- W += replaceUses(phi->targetTemp, c);
+ replaceUses(phi->targetTemp, c, W);
defUses.removeDef(*phi->targetTemp);
W.clear(s);
continue;
@@ -3165,11 +3199,11 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
Temp *t = phi->targetTemp;
Expr *e = phi->d->incoming.first();
- QVector<Stmt *> newT2Uses = replaceUses(t, e);
- W += newT2Uses;
+ QList<Stmt *> newT2Uses;
+ replaceUses(t, e, W, &newT2Uses);
if (Temp *t2 = e->asTemp()) {
defUses.removeUse(s, *t2);
- defUses.addUses(*t2, QList<Stmt*>::fromVector(newT2Uses));
+ defUses.addUses(*t2, newT2Uses);
}
defUses.removeDef(*t);
W.clear(s);
@@ -3214,13 +3248,9 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
// constant propagation:
if (Const *sourceConst = m->source->asConst()) {
- if (sourceConst->type & NumberType || sourceConst->type == BoolType) {
- // TODO: when propagating other constants, e.g. undefined, the other
- // optimization passes have to be changed to cope with them.
- W += replaceUses(targetTemp, sourceConst);
- defUses.removeDef(*targetTemp);
- W.clear(s);
- }
+ replaceUses(targetTemp, sourceConst, W);
+ defUses.removeDef(*targetTemp);
+ W.clear(s);
continue;
}
if (Member *member = m->source->asMember()) {
@@ -3228,7 +3258,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
Const *c = function->New<Const>();
const int enumValue = member->attachedPropertiesIdOrEnumValue;
c->init(SInt32Type, enumValue);
- W += replaceUses(targetTemp, c);
+ replaceUses(targetTemp, c, W);
defUses.removeDef(*targetTemp);
W.clear(s);
defUses.removeUse(s, *member->base->asTemp());
@@ -3246,10 +3276,10 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
// copy propagation:
if (Temp *sourceTemp = unescapableTemp(m->source, function)) {
- QVector<Stmt *> newT2Uses = replaceUses(targetTemp, sourceTemp);
- W += newT2Uses;
+ QList<Stmt *> newT2Uses;
+ replaceUses(targetTemp, sourceTemp, W, &newT2Uses);
defUses.removeUse(s, *sourceTemp);
- defUses.addUses(*sourceTemp, QList<Stmt*>::fromVector(newT2Uses));
+ defUses.addUses(*sourceTemp, newT2Uses);
defUses.removeDef(*targetTemp);
W.clear(s);
continue;
@@ -3366,8 +3396,8 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
QV4::Primitive lc = convertToValue(leftConst);
QV4::Primitive rc = convertToValue(rightConst);
- double l = RuntimeHelpers::toNumber(&lc);
- double r = RuntimeHelpers::toNumber(&rc);
+ double l = lc.toNumber();
+ double r = rc.toNumber();
switch (binop->op) {
case OpMul:
@@ -3514,16 +3544,19 @@ protected:
class LifeRanges {
typedef QSet<Temp> LiveRegs;
- QHash<BasicBlock *, LiveRegs> _liveIn;
+ QVector<LiveRegs> _liveIn;
QHash<Temp, LifeTimeInterval> _intervals;
- QVector<LifeTimeInterval> _sortedRanges;
+ typedef QVector<LifeTimeInterval> LifeTimeIntervals;
+ LifeTimeIntervals _sortedIntervals;
public:
LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops)
{
+ _liveIn.resize(function->basicBlockCount());
+
int id = 0;
- foreach (BasicBlock *bb, function->basicBlocks) {
- foreach (Stmt *s, bb->statements) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ foreach (Stmt *s, bb->statements()) {
if (s->asPhi())
s->id = id + 1;
else
@@ -3531,34 +3564,34 @@ public:
}
}
- for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = function->basicBlockCount() - 1; i >= 0; --i) {
+ BasicBlock *bb = function->basicBlock(i);
buildIntervals(bb, startEndLoops.value(bb, 0), function);
}
- _sortedRanges.reserve(_intervals.size());
+ _sortedIntervals.reserve(_intervals.size());
for (QHash<Temp, LifeTimeInterval>::const_iterator i = _intervals.begin(), ei = _intervals.end(); i != ei; ++i) {
- LifeTimeInterval range = i.value();
- range.setTemp(i.key());
- _sortedRanges.append(range);
+ LifeTimeIntervals::iterator lti = _sortedIntervals.insert(_sortedIntervals.end(), i.value());
+ lti->setTemp(i.key());
}
- std::sort(_sortedRanges.begin(), _sortedRanges.end(), LifeTimeInterval::lessThan);
+ std::sort(_sortedIntervals.begin(), _sortedIntervals.end(), LifeTimeInterval::lessThan);
+ _intervals.clear();
}
- QVector<LifeTimeInterval> ranges() const { return _sortedRanges; }
+ QVector<LifeTimeInterval> intervals() const { return _sortedIntervals; }
void dump() const
{
qout << "Life ranges:" << endl;
qout << "Intervals:" << endl;
- foreach (const LifeTimeInterval &range, _sortedRanges) {
+ foreach (const LifeTimeInterval &range, _sortedIntervals) {
range.dump(qout);
qout << endl;
}
- foreach (BasicBlock *bb, _liveIn.keys()) {
- qout << "L" << bb->index <<" live-in: ";
- QList<Temp> live = QList<Temp>::fromSet(_liveIn.value(bb));
+ for (int i = 0, ei = _liveIn.size(); i != ei; ++i) {
+ qout << "L" << i <<" live-in: ";
+ QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i));
std::sort(live.begin(), live.end());
for (int i = 0; i < live.size(); ++i) {
if (i > 0) qout << ", ";
@@ -3573,11 +3606,11 @@ private:
{
LiveRegs live;
foreach (BasicBlock *successor, bb->out) {
- live.unite(_liveIn[successor]);
+ live.unite(_liveIn[successor->index()]);
const int bbIndex = successor->in.indexOf(bb);
Q_ASSERT(bbIndex >= 0);
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
if (Temp *t = phi->d->incoming[bbIndex]->asTemp())
live.insert(*t);
@@ -3587,12 +3620,14 @@ private:
}
}
+ QVector<Stmt *> statements = bb->statements();
+
foreach (const Temp &opd, live)
- _intervals[opd].addRange(bb->statements.first()->id, bb->statements.last()->id);
+ _intervals[opd].addRange(statements.first()->id, statements.last()->id);
InputOutputCollector collector(function);
- for (int i = bb->statements.size() - 1; i >= 0; --i) {
- Stmt *s = bb->statements[i];
+ for (int i = statements.size() - 1; i >= 0; --i) {
+ Stmt *s = statements[i];
if (Phi *phi = s->asPhi()) {
LiveRegs::iterator it = live.find(*phi->targetTemp);
if (it == live.end()) {
@@ -3609,19 +3644,30 @@ private:
live.remove(opd);
}
foreach (const Temp &opd, collector.inputs) {
- _intervals[opd].addRange(bb->statements.first()->id, s->id);
+ _intervals[opd].addRange(statements.first()->id, s->id);
live.insert(opd);
}
}
if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null.
foreach (const Temp &opd, live)
- _intervals[opd].addRange(bb->statements.first()->id, loopEnd->statements.last()->id);
+ _intervals[opd].addRange(statements.first()->id, loopEnd->terminator()->id);
}
- _liveIn[bb] = live;
+ _liveIn[bb->index()] = live;
}
};
+
+void removeUnreachleBlocks(IR::Function *function)
+{
+ QVector<BasicBlock *> newSchedule;
+ newSchedule.reserve(function->basicBlockCount());
+ foreach (BasicBlock *bb, function->basicBlocks())
+ if (!bb->isRemoved())
+ newSchedule.append(bb);
+ function->setScheduledBlocks(newSchedule);
+ function->renumberBasicBlocks();
+}
} // anonymous namespace
void LifeTimeInterval::setFrom(Stmt *from) {
@@ -3684,8 +3730,8 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
// search where to split the interval
for (int i = 0, ei = _ranges.size(); i < ei; ++i) {
- if (_ranges[i].start <= atPosition) {
- if (_ranges[i].end >= atPosition) {
+ if (_ranges.at(i).start <= atPosition) {
+ if (_ranges.at(i).end >= atPosition) {
// split happens in the middle of a range. Keep this range in both the old and the
// new interval, and correct the end/start later
_ranges.resize(i + 1);
@@ -3767,6 +3813,11 @@ bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTim
return r1.temp() < r2.temp();
}
+Optimizer::Optimizer(IR::Function *function)
+ : function(function)
+ , inSSA(false)
+{}
+
void Optimizer::run(QQmlEnginePrivate *qmlEngine)
{
#if defined(SHOW_SSA)
@@ -3774,12 +3825,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
<< " with " << function->basicBlocks.size() << " basic blocks." << endl << flush;
#endif
- // Number all basic blocks, so we have nice numbers in the dumps:
- for (int i = 0; i < function->basicBlocks.size(); ++i)
- function->basicBlocks[i]->index = i;
// showMeTheCode(function);
- cleanupBasicBlocks(function, true);
+ cleanupBasicBlocks(function);
function->removeSharedExpressions();
@@ -3791,7 +3839,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
// Calculate the dominator tree:
- DominatorTree df(function->basicBlocks);
+ DominatorTree df(function);
// qout << "Converting to SSA..." << endl;
convertToSSA(function, df);
@@ -3836,21 +3884,22 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// condition is calculated to be always false) are not yet removed. This will choke the
// block scheduling, so remove those now.
// qout << "Cleaning up unreachable basic blocks..." << endl;
- cleanupBasicBlocks(function, false);
+ cleanupBasicBlocks(function);
// showMeTheCode(function);
// qout << "Doing block scheduling..." << endl;
// df.dumpImmediateDominators();
startEndLoops = BlockScheduler(function, df).go();
-// showMeTheCode(function);
+ showMeTheCode(function);
#ifndef QT_NO_DEBUG
- checkCriticalEdges(function->basicBlocks);
+ checkCriticalEdges(function->basicBlocks());
#endif
// qout << "Finished SSA." << endl;
inSSA = true;
} else {
+ removeUnreachleBlocks(function);
inSSA = false;
}
}
@@ -3861,13 +3910,13 @@ void Optimizer::convertOutOfSSA() {
// There should be no critical edges at this point.
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
MoveMapping moves;
foreach (BasicBlock *successor, bb->out) {
const int inIdx = successor->in.indexOf(bb);
Q_ASSERT(inIdx >= 0);
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
moves.add(clone(phi->d->incoming[inIdx], function),
clone(phi->targetTemp, function)->asTemp());
@@ -3893,11 +3942,10 @@ void Optimizer::convertOutOfSSA() {
moves.insertMoves(bb, function, true);
}
- foreach (BasicBlock *bb, function->basicBlocks) {
- while (!bb->statements.isEmpty()) {
- if (Phi *phi = bb->statements.first()->asPhi()) {
- phi->destroyData();
- bb->statements.removeFirst();
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ while (!bb->isEmpty()) {
+ if (bb->statements().first()->asPhi()) {
+ bb->removeStatement(0);
} else {
break;
}
@@ -3905,14 +3953,14 @@ void Optimizer::convertOutOfSSA() {
}
}
-QVector<LifeTimeInterval> Optimizer::lifeRanges() const
+QVector<LifeTimeInterval> Optimizer::lifeTimeIntervals() const
{
Q_ASSERT(isInSSA());
LifeRanges lifeRanges(function, startEndLoops);
// lifeRanges.dump();
// showMeTheCode(function);
- return lifeRanges.ranges();
+ return lifeRanges.intervals();
}
QSet<Jump *> Optimizer::calculateOptionalJumps()
@@ -3920,16 +3968,18 @@ QSet<Jump *> Optimizer::calculateOptionalJumps()
QSet<Jump *> optional;
QSet<BasicBlock *> reachableWithoutJump;
- const int maxSize = function->basicBlocks.size();
+ const int maxSize = function->basicBlockCount();
optional.reserve(maxSize);
reachableWithoutJump.reserve(maxSize);
- for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = maxSize - 1; i >= 0; --i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (bb->isRemoved())
+ continue;
- if (Jump *jump = bb->statements.last()->asJump()) {
+ if (Jump *jump = bb->statements().last()->asJump()) {
if (reachableWithoutJump.contains(jump->target)) {
- if (bb->statements.size() > 1)
+ if (bb->statements().size() > 1)
reachableWithoutJump.clear();
optional.insert(jump);
reachableWithoutJump.insert(bb);
@@ -4044,12 +4094,12 @@ QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *functio
QList<IR::Move *> newMoves;
newMoves.reserve(_moves.size());
- int insertionPoint = atEnd ? bb->statements.size() - 1 : 0;
+ int insertionPoint = atEnd ? bb->statements().size() - 1 : 0;
foreach (const Move &m, _moves) {
IR::Move *move = function->New<IR::Move>();
move->init(clone(m.to, function), clone(m.from, function));
move->swap = m.needsSwap;
- bb->statements.insert(insertionPoint++, move);
+ bb->insertStatementBefore(insertionPoint++, move);
newMoves.append(move);
}
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index 87f28d0eb2..372fe5cdeb 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -77,12 +77,12 @@ private:
public:
enum { Invalid = -1 };
- LifeTimeInterval()
+ explicit LifeTimeInterval(int rangeCapacity = 2)
: _end(Invalid)
, _reg(Invalid)
, _isFixedInterval(0)
, _isSplitFromInterval(0)
- {}
+ { _ranges.reserve(rangeCapacity); }
bool isValid() const { return _end != Invalid; }
@@ -92,8 +92,7 @@ public:
void setFrom(Stmt *from);
void addRange(int from, int to);
- Ranges ranges() const { return _ranges; }
- void reserveRanges(int capacity) { _ranges.reserve(capacity); }
+ const Ranges &ranges() const { return _ranges; }
int start() const { return _ranges.first().start; }
int end() const { return _end; }
@@ -137,13 +136,12 @@ public:
}
};
-class Q_QML_EXPORT Optimizer
+class Q_QML_PRIVATE_EXPORT Optimizer
{
+ Q_DISABLE_COPY(Optimizer)
+
public:
- Optimizer(Function *function)
- : function(function)
- , inSSA(false)
- {}
+ Optimizer(Function *function);
void run(QQmlEnginePrivate *qmlEngine);
void convertOutOfSSA();
@@ -153,7 +151,7 @@ public:
QHash<BasicBlock *, BasicBlock *> loopStartEndBlocks() const { return startEndLoops; }
- QVector<LifeTimeInterval> lifeRanges() const;
+ QVector<LifeTimeInterval> lifeTimeIntervals() const;
QSet<IR::Jump *> calculateOptionalJumps();
diff --git a/src/qml/debugger/qqmlabstractprofileradapter.cpp b/src/qml/debugger/qqmlabstractprofileradapter.cpp
index d7168428f6..01d1fcc4fe 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter.cpp
+++ b/src/qml/debugger/qqmlabstractprofileradapter.cpp
@@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
/*!
* \class QQmlAbstractProfilerAdapter
+ * \inmodule QtQml
* Abstract base class for all adapters between profilers and the QQmlProfilerService. Adapters have
* to retrieve profiler-specific data and convert it to the format sent over the wire. Adapters must
* live in the QDebugServer thread but the actual profilers can live in different threads. The
@@ -101,7 +102,7 @@ void QQmlAbstractProfilerAdapter::stopProfiling() {
}
/*!
- * \fn bool QQmlAbstractProfilerAdapter::isRunning()
+ * \fn bool QQmlAbstractProfilerAdapter::isRunning() const
* Returns if the profiler is currently running. The profiler is considered to be running after
* \c startProfiling() has been called until \c stopProfiling() is called. That is independent of
* \c waiting. The profiler may be running and waiting at the same time.
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
index 2d3e54c46a..b1eb130ee8 100644
--- a/src/qml/debugger/qqmldebugserver.cpp
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -413,6 +413,7 @@ QQmlDebugServer::QQmlDebugServer()
Q_D(QQmlDebugServer);
d->thread = new QQmlDebugServerThread;
moveToThread(d->thread);
+ d->thread->setObjectName(QStringLiteral("QQmlDebugServerThread"));
d->thread->setPluginName(pluginName);
d->thread->setPortRange(portFrom, portTo, block, hostAddress);
diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp
index f25c931d63..99446e945e 100644
--- a/src/qml/debugger/qqmlprofiler.cpp
+++ b/src/qml/debugger/qqmlprofiler.cpp
@@ -147,59 +147,4 @@ void QQmlProfiler::reportData()
emit dataReady(result);
}
-/*!
- * \fn void QQmlVmeProfiler::Data::clear()
- * Resets the profiling data to defaults.
- */
-
-/*!
- * \fn bool QQmlVmeProfiler::startBackground(const QString &typeName)
- * If profiling is enabled clears the current range data, then stops the
- * profiler previously running in the foreground if any, then starts a new one
- * in the background, setting the given typeName. \a typeName is the type of
- * object being created.
- */
-
-/*!
- * \fn bool QQmlVmeProfiler::start(const QString &typeName, const QUrl &url, int line, int column)
- * If profiling is enabled clears the current range data, then stops the
- * profiler previously running in the foreground if any, then starts a new one
- * in the foreground, setting the given location. \a url is the URL of
- * file being executed, \line line is the current line in in that file, and
- * \a column is the current column in that file.
- */
-
-/*!
- * \fn bool QQmlVmeProfiler::pop()
- * Stops the currently running profiler, if any, then retrieves an old one from the stack
- * of paused profilers and starts that if possible.
- */
-
-/*!
- * \fn void QQmlVmeProfiler::push()
- * Pushes the currently running profiler on the stack of paused profilers. Note: The profiler
- * isn't paused here. That's a separate step. If it's never paused, but pop()'ed later that
- * won't do any harm, though.
- */
-
-/*!
- * \fn void QQmlVmeProfiler::clear()
- * Stops the currently running (foreground and background) profilers and removes all saved
- * data about paused profilers.
- */
-
-/*!
- * \fn void QQmlVmeProfiler::stop()
- * Stop profiler running in the foreground, if any.
- */
-
-/*!
- * \fn bool QQmlVmeProfiler::foreground(const QUrl &url, int line, int column)
- * Stops the profiler currently running in the foreground, if any and puts the
- * next profiler from the background in its place if there are any profilers in
- * the background. Additionally the rangeLocation is set. \a url is the URL of
- * file being executed, \line line is the current line in in that file, and
- * \a column is the current column in that file.
- */
-
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 6afdc1e73b..84001905ab 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -55,6 +55,7 @@
#include <private/qv4function_p.h>
#include <private/qqmlboundsignal_p.h>
+#include <private/qfinitestack_p.h>
#include "qqmlprofilerdefinitions_p.h"
#include "qqmlabstractprofileradapter_p.h"
@@ -142,6 +143,11 @@ public:
location.sourceFile, location.line, location.column));
}
+ void startCreating()
+ {
+ m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, 1 << Creating));
+ }
+
void startCreating(const QString &typeName, const QUrl &fileName, int line, int column)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
@@ -149,16 +155,11 @@ public:
1 << Creating, typeName, fileName, line, column));
}
- void startCreating(const QString &typeName)
- {
- m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeData),
- 1 << Creating, typeName));
- }
-
- void creatingLocation(const QUrl &fileName, int line, int column)
+ void updateCreating(const QString &typeName, const QUrl &fileName, int line, int column)
{
- m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeLocation, 1 << Creating,
- fileName, line, column));
+ m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
+ (1 << RangeLocation | 1 << RangeData),
+ 1 << Creating, typeName, fileName, line, column));
}
template<RangeType Range>
@@ -246,108 +247,91 @@ struct QQmlCompilingProfiler : public QQmlProfilerHelper {
}
};
-#define Q_QML_VME_PROFILE(profilerMember, Method) Q_QML_PROFILE_IF_ENABLED(profilerMember.profiler, profilerMember.Method)
-
struct QQmlVmeProfiler : public QQmlProfilerDefinitions {
public:
struct Data {
- Data() : line(0), column(0) {}
- QUrl url;
- int line;
- int column;
- QString typeName;
+ Data() : m_line(0), m_column(0) {}
+ QUrl m_url;
+ int m_line;
+ int m_column;
+ QString m_typeName;
};
- QQmlVmeProfiler() : profiler(0), running(false) {}
+ QQmlVmeProfiler() : profiler(0) {}
- void clear(bool stopProfiling = false)
+ void init(QQmlProfiler *p, int maxDepth)
{
- ranges.clear();
- if (running)
- profiler->endRange<Creating>();
- for (int i = 0; i < backgroundRanges.count(); ++i) {
- profiler->endRange<Creating>();
- }
- backgroundRanges.clear();
- running = false;
- if (stopProfiling) profiler = 0;
+ profiler = p;
+ ranges.allocate(maxDepth);
}
- void startBackground(const QString &typeName)
+ Data pop()
{
- if (running) {
- profiler->endRange<Creating>();
- running = false;
- }
- profiler->startCreating(typeName);
- backgroundRanges.push(typeName);
+ if (ranges.count() > 0)
+ return ranges.pop();
+ else
+ return Data();
}
- void start(const QString &typeName, const QUrl &url, int line, int column)
+ void push(const Data &data)
{
- switchRange();
- setCurrentRange(typeName, url, line, column);
- profiler->startCreating(typeName, url, line, column);
+ if (ranges.capacity() > ranges.count())
+ ranges.push(data);
}
- void stop()
- {
- if (running) {
- profiler->endRange<Creating>();
- running = false;
- }
- }
+ QQmlProfiler *profiler;
- void pop()
+private:
+ QFiniteStack<Data> ranges;
+};
+
+#define Q_QML_OC_PROFILE(profilerMember, Code)\
+ Q_QML_PROFILE_IF_ENABLED(profilerMember.profiler, Code)
+
+class QQmlObjectCreationProfiler : public QQmlVmeProfiler::Data {
+public:
+
+ QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler)
{
- if (ranges.count() > 0) {
- switchRange();
- currentRange = ranges.pop();
- profiler->startCreating(currentRange.typeName, currentRange.url,
- currentRange.line, currentRange.column);
- }
+ Q_QML_PROFILE(profiler, startCreating());
}
- void push()
+ ~QQmlObjectCreationProfiler()
{
- if (running)
- ranges.push(currentRange);
+ Q_QML_PROFILE(profiler, endRange<QQmlProfilerDefinitions::Creating>());
}
- void foreground(const QUrl &url, int line, int column)
+ void update(const QString &typeName, const QUrl &url, int line, int column)
{
- if (backgroundRanges.count() > 0) {
- switchRange();
- setCurrentRange(backgroundRanges.pop(), url, line, column);
- profiler->creatingLocation(url, line, column);
- }
+ profiler->updateCreating(typeName, url, line, column);
+ m_typeName = typeName;
+ m_url = url;
+ m_line = line;
+ m_column = column;
}
- QQmlProfiler *profiler;
-
private:
+ QQmlProfiler *profiler;
+};
- void switchRange()
+class QQmlObjectCompletionProfiler {
+public:
+ QQmlObjectCompletionProfiler(QQmlVmeProfiler *parent) :
+ profiler(parent->profiler)
{
- if (running)
- profiler->endRange<Creating>();
- else
- running = true;
+ Q_QML_PROFILE_IF_ENABLED(profiler, {
+ QQmlVmeProfiler::Data data = parent->pop();
+ profiler->startCreating(data.m_typeName, data.m_url, data.m_line, data.m_column);
+ });
}
- void setCurrentRange(const QString &typeName, const QUrl &url, int line, int column)
+ ~QQmlObjectCompletionProfiler()
{
- currentRange.typeName = typeName;
- currentRange.url = url;
- currentRange.line = line;
- currentRange.column = column;
+ Q_QML_PROFILE(profiler, endRange<QQmlProfilerDefinitions::Creating>());
}
-
- Data currentRange;
- QStack<Data> ranges;
- QStack<QString> backgroundRanges;
- bool running;
+private:
+ QQmlProfiler *profiler;
};
QT_END_NAMESPACE
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 68233747b7..c083d63e51 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -94,9 +94,6 @@ when passed from C++ to QML and vice-versa:
\li QDate
\li \l date
\row
- \li QTime, QDateTime
- \li \l time
- \row
\li QPoint, QPointF
\li \l point
\row
diff --git a/src/qml/doc/src/javascript/expressions.qdoc b/src/qml/doc/src/javascript/expressions.qdoc
index 13238b2e43..c33daf7acc 100644
--- a/src/qml/doc/src/javascript/expressions.qdoc
+++ b/src/qml/doc/src/javascript/expressions.qdoc
@@ -143,11 +143,11 @@ Those signals can be handled by signal handler functions, which can be defined
by clients to implement custom program logic.
Suppose that a button represented by a Rectangle type has a MouseArea and a
-Text label. The MouseArea will emit its "pressed" signal when the user presses
-the defined interactive area, which will automatically trigger the
-\l{MouseArea::}{onPressed} handler, which can be defined by clients. The QML
-engine will execute the JavaScript expressions defined in the onPressed and
-onReleased handlers, as required. Typically, a signal handler is bound to
+Text label. The MouseArea will emit its \l{MouseArea::}{pressed} signal when the
+user presses the defined interactive area, which will automatically trigger the
+\c onPressed handler, which can be defined by clients. The QML
+engine will execute the JavaScript expressions defined in the \c onPressed and
+\c onReleased handlers, as required. Typically, a signal handler is bound to
JavaScript expressions to initiate other events or to simply assign property
values.
@@ -327,8 +327,8 @@ instances - can use this attached property. If there is more than one
\c onCompleted() handler to execute at startup, they are run sequentially in
an undefined order.
-Likewise, the \l {Component::onDestruction} handler definitions are triggered
-on component destruction.
+Likewise, every \c Component will emit a \l {Component::destruction}{destruction()}
+signal just before being destroyed.
*/
diff --git a/src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc b/src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc
index b5fe941f9f..8bfe309144 100644
--- a/src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc
@@ -69,7 +69,7 @@
as a new QML type. It provides the current time through \c hour and \c minute
properties.
- \snippet plugins/plugin.cpp 0
+ \snippet qmlextensionplugins/plugin.cpp 0
\dots
To make this type available, we create a plugin class named \c QExampleQmlPlugin
@@ -79,7 +79,7 @@
definition to register the plugin with the Qt meta object system using a unique
identifier for the plugin.
- \snippet plugins/plugin.cpp plugin
+ \snippet qmlextensionplugins/plugin.cpp plugin
The \c TimeModel class receives a \c{1.0} version of this plugin library, as
a QML type called \c Time. The Q_ASSERT() macro can ensure the type namespace is
@@ -112,15 +112,15 @@
that is built by the project (as shown above in the \c .pro file) so both of these
need to be specified in the \c qmldir file:
- \quotefile plugins/imports/TimeExample/qmldir
+ \quotefile qmlextensionplugins/imports/TimeExample/qmldir
Once the project is built and installed, the new \c Time component is
accessible by any QML component that imports the \c TimeExample
module
- \snippet plugins/plugins.qml 0
+ \snippet qmlextensionplugins/plugins.qml 0
- The full source code is available in the \l {qml/plugins}{plugins example}.
+ The full source code is available in the \l {qml/qmlextensionplugins}{plugins example}.
\section1 Reference
diff --git a/src/qml/doc/src/qmllanguageref/qmlreference.qdoc b/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
index 0bc8f90238..5111990b46 100644
--- a/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
+++ b/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -28,14 +28,14 @@
/*!
\page qmlreference.html
\title The QML Reference
-\brief A declarative language for application development
+\brief A multi-paradigm language for application development
-QML is a declarative language for creating highly dynamic applications. With
+QML is a multi-paradigm language for creating highly dynamic applications. With
QML, application building blocks such as UI components are \e declared and
-various properties set to define the application behavior. When coupled with
-JavaScript, application behavior becomes scriptable. In addition, QML heavily
-uses Qt, which allows types and other Qt features to be accessible directly from
-QML applications.
+various properties set to define the application behavior. Application behavior
+can be further scripted through JavaScript, which is a subset of the language.
+In addition, QML heavily uses Qt, which allows types and other Qt features to
+be accessible directly from QML applications.
This reference guide describes the features of the QML language. Many of the
QML types in the guide originate from the \l{Qt QML} or \l{Qt Quick}
diff --git a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
index cdfab3cd3f..8d71a04ac2 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -29,8 +29,12 @@
\title QML Syntax Basics
\brief Description of the basics of QML syntax
-QML is a declarative language that enables objects to be defined in terms of their attributes
-and how they relate and respond to changes in other objects. In contrast to imperative code, where changes in attributes and behavior are expressed through a series of statements that are processed step by step, the declarative QML syntax integrates attribute and behavioral changes directly into the definitions of individual objects.
+QML is a multi-paradigm language that enables objects to be defined in terms of their attributes
+and how they relate and respond to changes in other objects. In contrast to purely imperative code,
+where changes in attributes and behavior are expressed through a series of statements that are
+processed step by step, QML's declarative syntax integrates attribute and behavioral changes
+directly into the definitions of individual objects. These attribute definitions can then include
+imperative code, in the case where complex custom application behavior is needed.
QML source code is generally loaded by the engine through QML \e documents, which are
standalone documents of QML code. These can be used to define \l {QML Object Types}{QML object types} that can then be reused throughout an application.
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 2a9c94d22e..46a225ee30 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -633,7 +633,7 @@ defined by its implementation.
A signal is a notification from an object that some event has occurred: for
example, a property has changed, an animation has started or stopped, or
when an image has been downloaded. The \l MouseArea type, for example, has
-a \l {MouseArea::onClicked}{clicked} signal that is emitted when the user clicks
+a \l {MouseArea::}{clicked} signal that is emitted when the user clicks
within the mouse area.
An object can be notified through a \l{Signal handler attributes}
diff --git a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
index 4f2351d564..3e830c1f3c 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
@@ -65,7 +65,7 @@ Rectangle {
}
\endqml
-Looking at the \l MouseArea documentation, you can see the \l {MouseArea::onClicked}{clicked} signal is emitted with a parameter named \c mouse which is a \l MouseEvent object that contains further details about the mouse click event. This name can be referred to in our \c onClicked handler to access this parameter. For example, the \l MouseEvent type has \c x and \c y coordinates that allows us to print out the exact location where the mouse was clicked:
+Looking at the \l MouseArea documentation, you can see the \l {MouseArea::}{clicked} signal is emitted with a parameter named \c mouse which is a \l MouseEvent object that contains further details about the mouse click event. This name can be referred to in our \c onClicked handler to access this parameter. For example, the \l MouseEvent type has \c x and \c y coordinates that allows us to print out the exact location where the mouse was clicked:
\qml
import QtQuick 2.0
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 4e644c434d..cd44b537df 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -54,7 +54,6 @@
#include <WTFStubs.h>
#include <iostream>
-#include <cassert>
#if ENABLE(ASSEMBLER)
@@ -338,8 +337,11 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe
convertUInt32ToDouble(toUInt32Register(src, Assembler::ScratchRegister),
dest, Assembler::ReturnValueRegister);
return Assembler::Jump();
+ case IR::NullType:
+ case IR::UndefinedType:
case IR::BoolType:
// TODO?
+ case IR::StringType:
return jump();
default:
break;
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index d8efea17af..6fde517e1f 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -150,7 +150,7 @@ public:
static const int RegisterArgumentCount = 0;
static RegisterID registerForArgument(int)
{
- assert(false);
+ Q_ASSERT(false);
// Not reached.
return JSC::X86Registers::eax;
}
@@ -187,7 +187,7 @@ public:
JSC::X86Registers::r8,
JSC::X86Registers::r9
};
- assert(index >= 0 && index < RegisterArgumentCount);
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
return regs[index];
};
static const int StackShadowSpace = 32;
@@ -203,7 +203,7 @@ public:
JSC::X86Registers::r8,
JSC::X86Registers::r9
};
- assert(index >= 0 && index < RegisterArgumentCount);
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
return regs[index];
};
static const int StackShadowSpace = 0;
@@ -219,12 +219,12 @@ public:
#define ARGUMENTS_IN_REGISTERS
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
- static const RegisterID StackFrameRegister = JSC::ARMRegisters::r4;
- static const RegisterID StackPointerRegister = JSC::ARMRegisters::sp;
+ static const RegisterID StackPointerRegister = JSC::ARMRegisters::sp; // r13
+ static const RegisterID StackFrameRegister = JSC::ARMRegisters::fp; // r11
static const RegisterID LocalsRegister = JSC::ARMRegisters::r7;
+ static const RegisterID ScratchRegister = JSC::ARMRegisters::r6;
static const RegisterID ContextRegister = JSC::ARMRegisters::r5;
static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
- static const RegisterID ScratchRegister = JSC::ARMRegisters::r6;
static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
@@ -238,7 +238,7 @@ public:
static const int RegisterArgumentCount = 4;
static RegisterID registerForArgument(int index)
{
- assert(index >= 0 && index < RegisterArgumentCount);
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
return static_cast<RegisterID>(JSC::ARMRegisters::r0 + index);
};
@@ -446,6 +446,7 @@ public:
struct CallToLink {
Call call;
FunctionPtr externalFunction;
+ Label label;
const char* functionName;
};
struct PointerToValue {
@@ -473,6 +474,7 @@ public:
ctl.call = call();
ctl.externalFunction = function;
ctl.functionName = functionName;
+ ctl.label = label();
_callsToLink.append(ctl);
}
@@ -582,7 +584,7 @@ public:
void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber)
{
- assert(temp.value);
+ Q_ASSERT(temp.value);
Pointer addr = loadTempAddress(dest, temp.value);
loadArgumentInRegister(addr, dest, argumentNumber);
}
@@ -591,7 +593,7 @@ public:
{
Q_UNUSED(argumentNumber);
- assert(block.block);
+ Q_ASSERT(block.block);
DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), dest);
addPatch(patch, block.block);
}
@@ -630,13 +632,13 @@ public:
} else if (expr->asConst()) {
loadArgumentInRegister(expr->asConst(), dest, argumentNumber);
} else {
- assert(!"unimplemented expression type in loadArgument");
+ Q_ASSERT(!"unimplemented expression type in loadArgument");
}
}
#else
void loadArgumentInRegister(IR::Expr*, RegisterID)
{
- assert(!"unimplemented: expression in loadArgument");
+ Q_ASSERT(!"unimplemented: expression in loadArgument");
}
#endif
@@ -771,7 +773,7 @@ public:
template <int StackSlot>
void loadArgumentOnStack(Reference temp, int argumentNumber)
{
- assert (temp.value);
+ Q_ASSERT (temp.value);
Pointer ptr = loadTempAddress(ScratchRegister, temp.value);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
@@ -782,7 +784,7 @@ public:
{
Q_UNUSED(argumentNumber);
- assert(block.block);
+ Q_ASSERT(block.block);
DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), ScratchRegister);
poke(ScratchRegister, StackSlot);
addPatch(patch, block.block);
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index e584f1142f..344bbf56e0 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -148,7 +148,7 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target)
Assembler::PointerToValue(lhs),
Assembler::PointerToValue(rhs));
} else {
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
}
if (done.isSet())
@@ -240,11 +240,14 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target)
bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
{
Q_ASSERT(leftSource->type == IR::SInt32Type);
- Assembler::RegisterID targetReg;
- if (target->kind == IR::Temp::PhysicalRegister)
- targetReg = (Assembler::RegisterID) target->index;
- else
- targetReg = Assembler::ReturnValueRegister;
+ Assembler::RegisterID targetReg = Assembler::ReturnValueRegister;
+ if (target->kind == IR::Temp::PhysicalRegister) {
+ // We try to load leftSource into the target's register, but we can't do that if
+ // the target register is the same as rightSource.
+ IR::Temp *rhs = rightSource->asTemp();
+ if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != target->index)
+ targetReg = (Assembler::RegisterID) target->index;
+ }
switch (op) {
case IR::OpBitAnd: {
@@ -296,13 +299,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (IR::Const *c = rightSource->asConst()) {
- as->lshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
+ if (int(c->value) == 0)
+ as->move(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), targetReg);
+ else
+ as->lshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
+ Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
} else {
as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
- if (!rightSource->asConst())
- as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister);
+#if CPU(ARM) || CPU(X86) || CPU(X86_64)
+ // The ARM assembler will generate this for us, and Intel will do it on the CPU.
+#else
+ as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister);
+#endif
as->lshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg);
}
as->storeInt32(targetReg, target);
@@ -311,12 +320,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (IR::Const *c = rightSource->asConst()) {
- as->rshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
+ if (int(c->value) == 0)
+ as->move(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), targetReg);
+ else
+ as->rshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
+ Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
} else {
as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
+#if CPU(ARM) || CPU(X86) || CPU(X86_64)
+ // The ARM assembler will generate this for us, and Intel will do it on the CPU.
+#else
as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister);
+#endif
as->rshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg);
}
as->storeInt32(targetReg, target);
@@ -325,12 +341,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (IR::Const *c = rightSource->asConst()) {
- as->urshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
+ if (int(c->value) == 0)
+ as->move(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), targetReg);
+ else
+ as->urshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
+ Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
} else {
as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
+#if CPU(ARM) || CPU(X86) || CPU(X86_64)
+ // The ARM assembler will generate this for us, and Intel will do it on the CPU.
+#else
as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister);
+#endif
as->urshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg);
}
as->storeUInt32(targetReg, target);
@@ -338,12 +361,6 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
case IR::OpAdd: {
Q_ASSERT(rightSource->type == IR::SInt32Type);
- Assembler::RegisterID targetReg;
- if (target->kind == IR::Temp::PhysicalRegister)
- targetReg = (Assembler::RegisterID) target->index;
- else
- targetReg = Assembler::ReturnValueRegister;
-
as->add32(as->toInt32Register(leftSource, targetReg),
as->toInt32Register(rightSource, Assembler::ScratchRegister),
targetReg);
@@ -363,12 +380,6 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
return true;
}
- Assembler::RegisterID targetReg;
- if (target->kind == IR::Temp::PhysicalRegister)
- targetReg = (Assembler::RegisterID) target->index;
- else
- targetReg = Assembler::ReturnValueRegister;
-
as->move(as->toInt32Register(leftSource, targetReg), targetReg);
as->sub32(as->toInt32Register(rightSource, Assembler::ScratchRegister), targetReg);
as->storeInt32(targetReg, target);
@@ -376,12 +387,6 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
case IR::OpMul: {
Q_ASSERT(rightSource->type == IR::SInt32Type);
- Assembler::RegisterID targetReg;
- if (target->kind == IR::Temp::PhysicalRegister)
- targetReg = (Assembler::RegisterID) target->index;
- else
- targetReg = Assembler::ReturnValueRegister;
-
as->mul32(as->toInt32Register(leftSource, targetReg),
as->toInt32Register(rightSource, Assembler::ScratchRegister),
targetReg);
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 5e51b84cd5..3307fcc0d1 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -58,7 +58,6 @@
#include <WTFStubs.h>
#include <iostream>
-#include <cassert>
#if ENABLE(ASSEMBLER)
@@ -116,7 +115,13 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput, const Q
it != end; ++it) {
QByteArray ptrString = QByteArray::number(quintptr(it.key()), 16);
ptrString.prepend("0x");
- processedOutput = processedOutput.replace(ptrString, it.value());
+ int idx = processedOutput.indexOf(ptrString);
+ if (idx < 0)
+ continue;
+ idx = processedOutput.lastIndexOf('\n', idx);
+ if (idx < 0)
+ continue;
+ processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value());
}
fprintf(stderr, "%s\n", processedOutput.constData());
fflush(stderr);
@@ -132,7 +137,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
it.next();
IR::BasicBlock *block = it.key();
Label target = _addrs.value(block);
- assert(target.isSet());
+ Q_ASSERT(target.isSet());
foreach (Jump jump, it.value())
jump.linkTo(target, this);
}
@@ -144,7 +149,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
linkBuffer.link(ctl.call, ctl.externalFunction);
- functions[ctl.externalFunction.value()] = ctl.functionName;
+ functions[linkBuffer.locationOf(ctl.label).dataLocation()] = ctl.functionName;
}
foreach (const DataLabelPatch &p, _dataLabelPatches)
@@ -160,7 +165,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
it.next();
IR::BasicBlock *block = it.key();
Label target = _addrs.value(block);
- assert(target.isSet());
+ Q_ASSERT(target.isSet());
foreach (DataLabelPtr label, it.value())
linkBuffer.patch(label, linkBuffer.locationOf(target));
}
@@ -253,10 +258,10 @@ static QVector<int> getIntRegisters()
static const QVector<int> intRegisters = QVector<int>()
<< JSC::ARMRegisters::r1
<< JSC::ARMRegisters::r2
+ << JSC::ARMRegisters::r3
+ << JSC::ARMRegisters::r4
<< JSC::ARMRegisters::r8
- << JSC::ARMRegisters::r9
- << JSC::ARMRegisters::r10
- << JSC::ARMRegisters::r11;
+ << JSC::ARMRegisters::r9;
return intRegisters;
}
@@ -337,12 +342,14 @@ void InstructionSelection::run(int functionIndex)
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
int lastLine = 0;
- for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
- IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
- _block = _function->basicBlocks[i];
+ for (int i = 0, ei = _function->basicBlockCount(); i != ei; ++i) {
+ IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlock(i + 1) : 0;
+ _block = _function->basicBlock(i);
+ if (_block->isRemoved())
+ continue;
_as->registerBlock(_block, nextBlock);
- foreach (IR::Stmt *s, _block->statements) {
+ foreach (IR::Stmt *s, _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lineNumber));
@@ -367,14 +374,14 @@ void InstructionSelection::run(int functionIndex)
qSwap(_removableJumps, removableJumps);
}
-void *InstructionSelection::addConstantTable(QVector<Primitive> *values)
+const void *InstructionSelection::addConstantTable(QVector<Primitive> *values)
{
compilationUnit->constantValues.append(*values);
values->clear();
QVector<QV4::Primitive> &finalValues = compilationUnit->constantValues.last();
finalValues.squeeze();
- return finalValues.data();
+ return finalValues.constData();
}
QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
@@ -474,12 +481,12 @@ void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionNam
generateFunctionCall(Assembler::ContextRegister, Runtime::pushCatchScope, Assembler::ContextRegister, s);
}
-void InstructionSelection::callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result)
+void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
- generateFunctionCall(result, Runtime::foreachIterator, Assembler::ContextRegister, Assembler::Reference(arg));
+ generateFunctionCall(result, Runtime::foreachIterator, Assembler::ContextRegister, Assembler::PointerToValue(arg));
}
void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result)
@@ -941,7 +948,7 @@ void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr
void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
IR::Temp *result)
{
- assert(base != 0);
+ Q_ASSERT(base != 0);
prepareCallData(args, base);
@@ -961,7 +968,7 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR:
void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
IR::Temp *result)
{
- assert(base != 0);
+ Q_ASSERT(base != 0);
prepareCallData(args, base);
generateFunctionCall(result, Runtime::callElement, Assembler::ContextRegister,
@@ -1264,7 +1271,7 @@ void InstructionSelection::convertTypeToUInt32(IR::Temp *source, IR::Temp *targe
void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result)
{
- assert(func != 0);
+ Q_ASSERT(func != 0);
prepareCallData(args, 0);
if (useFastLookups && func->global) {
@@ -1301,7 +1308,7 @@ void InstructionSelection::constructProperty(IR::Temp *base, const QString &name
void InstructionSelection::constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result)
{
- assert(value != 0);
+ Q_ASSERT(value != 0);
prepareCallData(args, 0);
generateFunctionCall(result, Runtime::constructValue,
@@ -1371,7 +1378,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
Runtime::CompareOperationContext opContext = 0;
const char *opName = 0;
switch (b->op) {
- default: Q_UNREACHABLE(); assert(!"todo"); break;
+ 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;
@@ -1613,10 +1620,10 @@ Assembler::ImplicitAddress Assembler::ConstantTable::loadValueAddress(const Prim
void Assembler::ConstantTable::finalize(JSC::LinkBuffer &linkBuffer, InstructionSelection *isel)
{
- void *tablePtr = isel->addConstantTable(&_values);
+ const void *tablePtr = isel->addConstantTable(&_values);
foreach (DataLabelPtr label, _toPatch)
- linkBuffer.patch(label, tablePtr);
+ linkBuffer.patch(label, const_cast<void *>(tablePtr));
}
bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 62891e4273..d589223d7e 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -72,7 +72,7 @@ public:
virtual void run(int functionIndex);
- void *addConstantTable(QVector<QV4::Primitive> *values);
+ const void *addConstantTable(QVector<QV4::Primitive> *values);
protected:
virtual QV4::CompiledData::CompilationUnit *backendCompileStep();
@@ -89,7 +89,7 @@ protected:
virtual void callBuiltinReThrow();
virtual void callBuiltinUnwindException(IR::Temp *);
virtual void callBuiltinPushCatchScope(const QString &exceptionName);
- virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
+ virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result);
virtual void callBuiltinPushWithScope(IR::Temp *arg);
virtual void callBuiltinPopScope();
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index 72ec66d1c2..b5765cd589 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -97,8 +97,8 @@ public:
void collect(IR::Function *function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
- foreach (Stmt *s, bb->statements) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ foreach (Stmt *s, bb->statements()) {
Q_ASSERT(s->id > 0);
_currentStmt = s;
s->accept(this);
@@ -207,7 +207,7 @@ protected: // IRDecoder
virtual void callBuiltinReThrow() {}
virtual void callBuiltinUnwindException(IR::Temp *) {}
virtual void callBuiltinPushCatchScope(const QString &) {};
- virtual void callBuiltinForeachIteratorObject(IR::Temp *, IR::Temp *) {}
+ virtual void callBuiltinForeachIteratorObject(IR::Expr *, IR::Temp *) {}
virtual void callBuiltinForeachNextProperty(IR::Temp *, IR::Temp *) {}
virtual void callBuiltinForeachNextPropertyname(IR::Temp *, IR::Temp *) {}
virtual void callBuiltinPushWithScope(IR::Temp *) {}
@@ -705,8 +705,8 @@ public:
for (int i = 0, ei = _intervals.size(); i != ei; ++i)
_unprocessed[i] = &_intervals[i];
- _liveAtStart.reserve(function->basicBlocks.size());
- _liveAtEnd.reserve(function->basicBlocks.size());
+ _liveAtStart.reserve(function->basicBlockCount());
+ _liveAtEnd.reserve(function->basicBlockCount());
}
void run() {
@@ -718,13 +718,14 @@ public:
private:
void renumber()
{
- foreach (BasicBlock *bb, _function->basicBlocks) {
+ foreach (BasicBlock *bb, _function->basicBlocks()) {
+ QVector<Stmt *> statements = bb->statements();
QVector<Stmt *> newStatements;
- newStatements.reserve(bb->statements.size() + 7);
+ newStatements.reserve(bb->statements().size() + 7);
bool seenFirstNonPhiStmt = false;
- for (int i = 0, ei = bb->statements.size(); i != ei; ++i) {
- _currentStmt = bb->statements[i];
+ for (int i = 0, ei = statements.size(); i != ei; ++i) {
+ _currentStmt = statements[i];
_loads.clear();
_stores.clear();
addNewIntervals();
@@ -766,7 +767,7 @@ private:
}
#endif
- bb->statements = newStatements;
+ bb->setStatements(newStatements);
}
}
@@ -833,7 +834,7 @@ private:
void resolve()
{
- foreach (BasicBlock *bb, _function->basicBlocks) {
+ foreach (BasicBlock *bb, _function->basicBlocks()) {
foreach (BasicBlock *bbOut, bb->out)
resolveEdge(bb, bbOut);
}
@@ -848,11 +849,11 @@ private:
MoveMapping mapping;
- const int predecessorEnd = predecessor->statements.last()->id; // the terminator is always last and always has an id set...
+ const int predecessorEnd = predecessor->terminator()->id; // the terminator is always last and always has an id set...
Q_ASSERT(predecessorEnd > 0); // ... but we verify it anyway for good measure.
int successorStart = -1;
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (s && s->id > 0) {
successorStart = s->id;
break;
@@ -869,7 +870,7 @@ private:
Expr *moveFrom = 0;
if (it->start() == successorStart) {
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (!s || s->id < 1)
continue;
if (Phi *phi = s->asPhi()) {
@@ -925,14 +926,14 @@ private:
Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole);
if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) {
- const int successorEnd = successor->statements.last()->id;
+ const int successorEnd = successor->terminator()->id;
const int idx = successor->in.indexOf(predecessor);
foreach (const Use &use, _info->uses(it->temp())) {
if (use.pos == static_cast<unsigned>(successorStart)) {
// only check the current edge, not all other possible ones. This is
// important for phi nodes: they have uses that are only valid when
// coming in over a specific edge.
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
Q_ASSERT(it->temp().index != phi->targetTemp->index);
Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0
@@ -1076,6 +1077,8 @@ RegisterAllocator::RegisterAllocator(const QVector<int> &normalRegisters, const
{
Q_ASSERT(normalRegisters.size() >= 2);
Q_ASSERT(fpRegisters.size() >= 2);
+ _active.reserve((normalRegisters.size() + fpRegisters.size()) * 2);
+ _inactive.reserve(_active.size());
}
RegisterAllocator::~RegisterAllocator()
@@ -1084,13 +1087,16 @@ RegisterAllocator::~RegisterAllocator()
void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
{
+ _lastAssignedRegister.reserve(function->tempCount);
+ _assignedSpillSlots.reserve(function->tempCount);
_activeSpillSlots.resize(function->tempCount);
#ifdef DEBUG_REGALLOC
qDebug() << "*** Running regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***";
#endif // DEBUG_REGALLOC
- _unhandled = opt.lifeRanges();
+ _unhandled = opt.lifeTimeIntervals();
+ _handled.reserve(_unhandled.size());
_info.reset(new RegAllocInfo);
_info->collect(function);
@@ -1111,10 +1117,6 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
prepareRanges();
- _handled.reserve(_unhandled.size());
- _active.reserve(32);
- _inactive.reserve(16);
-
Optimizer::showMeTheCode(function);
linearScan();
@@ -1135,46 +1137,55 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
#endif // DEBUG_REGALLOC
}
-static inline LifeTimeInterval createFixedInterval(int reg, bool isFP, int rangeCount)
+static inline LifeTimeInterval createFixedInterval(int rangeCount)
{
+ LifeTimeInterval i(rangeCount);
+ i.setReg(0);
+
Temp t;
- t.init(Temp::PhysicalRegister, reg, 0);
- t.type = isFP ? IR::DoubleType : IR::SInt32Type;
- LifeTimeInterval i;
+ t.init(Temp::PhysicalRegister, 0, 0);
+ t.type = IR::SInt32Type;
i.setTemp(t);
- i.setReg(reg);
- i.setFixedInterval(true);
- i.reserveRanges(rangeCount);
+
return i;
}
+static inline LifeTimeInterval cloneFixedInterval(int reg, bool isFP, LifeTimeInterval lti)
+{
+ lti.setReg(reg);
+ lti.setFixedInterval(true);
+
+ Temp t;
+ t.init(Temp::PhysicalRegister, reg, 0);
+ t.type = isFP ? IR::DoubleType : IR::SInt32Type;
+ lti.setTemp(t);
+
+ return lti;
+}
+
void RegisterAllocator::prepareRanges()
{
+ LifeTimeInterval ltiWithCalls = createFixedInterval(_info->calls().size());
+ foreach (int callPosition, _info->calls())
+ ltiWithCalls.addRange(callPosition, callPosition);
+
const int regCount = _normalRegisters.size();
- _fixedRegisterRanges.resize(regCount);
- for (int reg = 0; reg < regCount; ++reg)
- _fixedRegisterRanges[reg] = createFixedInterval(reg, false, _info->calls().size());
+ _fixedRegisterRanges.reserve(regCount);
+ for (int reg = 0; reg < regCount; ++reg) {
+ LifeTimeInterval lti = cloneFixedInterval(reg, false, ltiWithCalls);
+ _fixedRegisterRanges.append(lti);
+ if (lti.isValid())
+ _active.append(lti);
+ }
const int fpRegCount = _fpRegisters.size();
- _fixedFPRegisterRanges.resize(fpRegCount);
+ _fixedFPRegisterRanges.reserve(fpRegCount);
for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) {
- _fixedFPRegisterRanges[fpReg] = createFixedInterval(fpReg, true, _info->calls().size());
- }
-
- foreach (int callPosition, _info->calls()) {
- for (int reg = 0; reg < regCount; ++reg)
- _fixedRegisterRanges[reg].addRange(callPosition, callPosition);
- for (int fpReg = 0; fpReg < fpRegCount; ++fpReg)
- _fixedFPRegisterRanges[fpReg].addRange(callPosition, callPosition);
+ LifeTimeInterval lti = cloneFixedInterval(fpReg, true, ltiWithCalls);
+ _fixedFPRegisterRanges.append(lti);
+ if (lti.isValid())
+ _active.append(lti);
}
- for (int reg = 0; reg < regCount; ++reg)
- if (_fixedRegisterRanges[reg].isValid())
- _active.append(_fixedRegisterRanges[reg]);
- for (int fpReg = 0; fpReg < fpRegCount; ++fpReg)
- if (_fixedFPRegisterRanges[fpReg].isValid())
- _active.append(_fixedFPRegisterRanges[fpReg]);
-
- std::sort(_active.begin(), _active.end(), LifeTimeInterval::lessThan);
}
void RegisterAllocator::linearScan()
@@ -1186,7 +1197,7 @@ void RegisterAllocator::linearScan()
// check for intervals in active that are handled or inactive
for (int i = 0; i < _active.size(); ) {
- const LifeTimeInterval &it = _active[i];
+ const LifeTimeInterval &it = _active.at(i);
if (it.end() < position) {
if (!it.isFixedInterval())
_handled += it;
@@ -1201,7 +1212,7 @@ void RegisterAllocator::linearScan()
// check for intervals in inactive that are handled or active
for (int i = 0; i < _inactive.size(); ) {
- LifeTimeInterval &it = _inactive[i];
+ const LifeTimeInterval &it = _inactive.at(i);
if (it.end() < position) {
if (!it.isFixedInterval())
_handled += it;
@@ -1222,6 +1233,10 @@ void RegisterAllocator::linearScan()
Q_ASSERT(!current.isFixedInterval());
+#ifdef DEBUG_REGALLOC
+ qDebug() << "** Position" << position;
+#endif // DEBUG_REGALLOC
+
if (_info->canHaveRegister(current.temp())) {
tryAllocateFreeReg(current, position);
if (current.reg() == LifeTimeInterval::Invalid)
@@ -1374,11 +1389,15 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int
QVector<LifeTimeInterval *> nextUseRangeForReg(nextUsePos.size(), 0);
Q_ASSERT(nextUsePos.size() > 0);
+ const bool definedAtCurrentPosition = !current.isSplitFromInterval() && current.start() == position;
+
for (int i = 0, ei = _active.size(); i != ei; ++i) {
LifeTimeInterval &it = _active[i];
if (it.isFP() == needsFPReg) {
int nu = it.isFixedInterval() ? 0 : nextUse(it.temp(), current.firstPossibleUsePosition(isPhiTarget));
- if (nu != -1 && nu < nextUsePos[it.reg()]) {
+ if (nu == position && !definedAtCurrentPosition) {
+ nextUsePos[it.reg()] = 0;
+ } else if (nu != -1 && nu < nextUsePos[it.reg()]) {
nextUsePos[it.reg()] = nu;
nextUseRangeForReg[it.reg()] = &it;
} else if (nu == -1 && nextUsePos[it.reg()] == INT_MAX) {
@@ -1440,8 +1459,8 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int
splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position);
// make sure that current does not intersect with the fixed interval for reg
- const LifeTimeInterval &fixedRegRange = needsFPReg ? _fixedFPRegisterRanges[reg]
- : _fixedRegisterRanges[reg];
+ const LifeTimeInterval &fixedRegRange = needsFPReg ? _fixedFPRegisterRanges.at(reg)
+ : _fixedRegisterRanges.at(reg);
int ni = nextIntersection(current, fixedRegRange, position);
if (ni != -1) {
#ifdef DEBUG_REGALLOC
@@ -1603,7 +1622,7 @@ void RegisterAllocator::assignSpillSlot(const Temp &t, int startPos, int endPos)
return;
for (int i = 0, ei = _activeSpillSlots.size(); i != ei; ++i) {
- if (_activeSpillSlots[i] < startPos) {
+ if (_activeSpillSlots.at(i) < startPos) {
_activeSpillSlots[i] = endPos;
_assignedSpillSlots.insert(t, i);
return;
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 1ff6f509e0..d05ada481a 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -78,6 +78,7 @@ Q_DECLARE_METATYPE(QList<int>)
/*!
\since 5.0
\class QJSEngine
+ \reentrant
\brief The QJSEngine class provides an environment for evaluating JavaScript code.
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 5fba40edac..b17ac17752 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -522,7 +522,7 @@ QJSValue QJSValue::call(const QJSValueList &args)
return QJSValue();
ExecutionEngine *engine = d->engine;
- assert(engine);
+ Q_ASSERT(engine);
Scope scope(engine);
ScopedCallData callData(scope, args.length());
@@ -571,7 +571,7 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
return QJSValue();
ExecutionEngine *engine = d->engine;
- assert(engine);
+ Q_ASSERT(engine);
Scope scope(engine);
if (!instance.d->checkEngine(engine)) {
@@ -623,7 +623,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
return QJSValue();
ExecutionEngine *engine = d->engine;
- assert(engine);
+ Q_ASSERT(engine);
Scope scope(engine);
ScopedCallData callData(scope, args.size());
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index ac26794506..72010d3fa8 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -1,11 +1,10 @@
INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
+!qmldevtools_build {
SOURCES += \
$$PWD/qv4engine.cpp \
$$PWD/qv4context.cpp \
- $$PWD/qv4runtime.cpp \
- $$PWD/qv4value.cpp \
$$PWD/qv4persistent.cpp \
$$PWD/qv4debugging.cpp \
$$PWD/qv4lookup.cpp \
@@ -26,13 +25,13 @@ SOURCES += \
$$PWD/qv4globalobject.cpp \
$$PWD/qv4jsonobject.cpp \
$$PWD/qv4mathobject.cpp \
+ $$PWD/qv4memberdata.cpp \
$$PWD/qv4numberobject.cpp \
$$PWD/qv4object.cpp \
$$PWD/qv4objectproto.cpp \
$$PWD/qv4regexpobject.cpp \
$$PWD/qv4stringobject.cpp \
$$PWD/qv4variantobject.cpp \
- $$PWD/qv4string.cpp \
$$PWD/qv4objectiterator.cpp \
$$PWD/qv4regexp.cpp \
$$PWD/qv4serialize.cpp \
@@ -49,10 +48,7 @@ HEADERS += \
$$PWD/qv4global_p.h \
$$PWD/qv4engine_p.h \
$$PWD/qv4context_p.h \
- $$PWD/qv4runtime_p.h \
$$PWD/qv4math_p.h \
- $$PWD/qv4value_inl_p.h \
- $$PWD/qv4value_p.h \
$$PWD/qv4persistent_p.h \
$$PWD/qv4debugging_p.h \
$$PWD/qv4lookup_p.h \
@@ -73,13 +69,13 @@ HEADERS += \
$$PWD/qv4globalobject_p.h \
$$PWD/qv4jsonobject_p.h \
$$PWD/qv4mathobject_p.h \
+ $$PWD/qv4memberdata_p.h \
$$PWD/qv4numberobject_p.h \
$$PWD/qv4object_p.h \
$$PWD/qv4objectproto_p.h \
$$PWD/qv4regexpobject_p.h \
$$PWD/qv4stringobject_p.h \
$$PWD/qv4variantobject_p.h \
- $$PWD/qv4string_p.h \
$$PWD/qv4property_p.h \
$$PWD/qv4objectiterator_p.h \
$$PWD/qv4regexp_p.h \
@@ -95,6 +91,20 @@ HEADERS += \
$$PWD/qv4vme_moth_p.h \
$$PWD/qv4profiling_p.h
+}
+
+
+HEADERS += \
+ $$PWD/qv4runtime_p.h \
+ $$PWD/qv4value_inl_p.h \
+ $$PWD/qv4string_p.h \
+ $$PWD/qv4value_p.h
+
+SOURCES += \
+ $$PWD/qv4runtime.cpp \
+ $$PWD/qv4string.cpp \
+ $$PWD/qv4value.cpp
+
# Use SSE2 floating point math on 32 bit instead of the default
# 387 to make test results pass on 32 and on 64 bit builds.
linux-g++*:isEqual(QT_ARCH,i386) {
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index c8ba2c4037..987b228209 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -93,8 +93,9 @@ void ArgumentsObject::fullyCreate()
uint argCount = qMin(context->realArgumentCount, context->callData->argc);
ArrayData::realloc(this, ArrayData::Sparse, 0, argCount, true);
context->engine->requireArgumentsAccessors(numAccessors);
+ mappedArguments.ensureIndex(engine(), numAccessors);
for (uint i = 0; i < (uint)numAccessors; ++i) {
- mappedArguments.append(context->callData->args[i]);
+ mappedArguments[i] = context->callData->args[i];
arraySet(i, context->engine->argumentsAccessors[i], Attr_Accessor);
}
arrayPut(numAccessors, context->callData->args + numAccessors, argCount - numAccessors);
@@ -113,7 +114,8 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
Property map;
PropertyAttributes mapAttrs;
bool isMapped = false;
- if (pd && index < (uint)mappedArguments.size())
+ uint numAccessors = qMin((int)context->function->formalParameterCount(), context->realArgumentCount);
+ if (pd && index < (uint)numAccessors)
isMapped = arrayData->attributes(index).isAccessor() && pd->getter() == context->engine->argumentsAccessors[index].getter();
if (isMapped) {
@@ -121,7 +123,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
map.copy(*pd, mapAttrs);
setArrayAttributes(index, Attr_Data);
pd = arrayData->getProperty(index);
- pd->value = mappedArguments.at(index);
+ pd->value = mappedArguments[index];
}
bool strict = ctx->strictMode;
@@ -158,6 +160,8 @@ ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasPrope
*hasProperty = true;
return args->context->callData->args[index].asReturnedValue();
}
+ if (hasProperty)
+ *hasProperty = false;
return Encode::undefined();
}
@@ -232,9 +236,9 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData)
void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e)
{
ArgumentsObject *o = static_cast<ArgumentsObject *>(that);
- o->context->mark(e);
- for (int i = 0; i < o->mappedArguments.size(); ++i)
- o->mappedArguments.at(i).mark(e);
+ if (o->context)
+ o->context->mark(e);
+ o->mappedArguments.mark(e);
Object::markObjects(that, e);
}
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index a7904105e4..80c2a70501 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -80,7 +80,7 @@ struct ArgumentsObject: Object {
Q_MANAGED_TYPE(ArgumentsObject)
CallContext *context;
bool fullyCreated;
- QVector<Value> mappedArguments;
+ Members mappedArguments;
ArgumentsObject(CallContext *context);
~ArgumentsObject() {}
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 9156a94e09..ed2122fb89 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -156,21 +156,22 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e
newData->sparse = old->sparse;
old->sparse = 0;
newData->freeList = old->freeList;
- return;
+ } else {
+ newData->sparse = new SparseArray;
+ uint *lastFree = &newData->freeList;
+ for (uint i = 0; i < toCopy; ++i) {
+ if (!newData->data[i].isEmpty()) {
+ SparseArrayNode *n = newData->sparse->insert(i);
+ n->value = i;
+ } else {
+ *lastFree = i;
+ newData->data[i].tag = Value::Empty_Type;
+ lastFree = &newData->data[i].uint_32;
+ }
+ }
}
- newData->sparse = new SparseArray;
uint *lastFree = &newData->freeList;
- for (uint i = 0; i < toCopy; ++i) {
- if (!newData->data[i].isEmpty()) {
- SparseArrayNode *n = newData->sparse->insert(i);
- n->value = i;
- } else {
- *lastFree = i;
- newData->data[i].tag = Value::Empty_Type;
- lastFree = &newData->data[i].uint_32;
- }
- }
for (uint i = toCopy; i < newData->alloc; ++i) {
*lastFree = i;
newData->data[i].tag = Value::Empty_Type;
@@ -580,6 +581,8 @@ uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n)
if (other->isSparse())
obj->initSparseArray();
+ else
+ obj->arrayCreate();
uint oldSize = obj->getLength();
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index f127c75fb0..50b7b8a947 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -140,8 +140,8 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
V4_ARRAYDATA
SimpleArrayData(ExecutionEngine *engine)
- : ArrayData(engine->emptyClass)
- { setVTable(staticVTable()); }
+ : ArrayData(engine->simpleArrayDataClass)
+ {}
uint len;
uint offset;
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 0d8e57bdd5..b43b4893a3 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -319,9 +319,15 @@ void ExecutionContext::setProperty(const StringRef name, const ValueRef value)
}
if (activation) {
- if (ctx->type == Type_QmlContext || activation->hasOwnProperty(name)) {
+ if (ctx->type == Type_QmlContext) {
activation->put(name, value);
return;
+ } else {
+ uint member = activation->internalClass->find(name);
+ if (member < UINT_MAX) {
+ activation->putValue(activation->propertyAt(member), activation->internalClass->propertyData[member], value);
+ return;
+ }
}
}
}
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index ddced40714..a07cbf2da5 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -60,7 +60,7 @@ struct ValueRef;
namespace CompiledData {
struct CompilationUnit;
struct Function;
-};
+}
struct CallContext;
struct CallContext;
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index bbf064b6f8..ceef88455b 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -51,7 +51,6 @@
#include <cmath>
#include <qmath.h>
#include <qnumeric.h>
-#include <cassert>
#include <time.h>
#include <private/qqmljsengine_p.h>
@@ -157,7 +156,7 @@ static inline bool InLeapYear(double t)
if (x == 365)
return 0;
- assert(x == 366);
+ Q_ASSERT(x == 366);
return 1;
}
@@ -628,12 +627,13 @@ static double getLocalTZA()
#ifndef Q_OS_WIN
struct tm t;
time_t curr;
+ tzset();
time(&curr);
localtime_r(&curr, &t);
time_t locl = mktime(&t);
gmtime_r(&curr, &t);
time_t globl = mktime(&t);
- return double(locl - globl) * 1000.0;
+ return (double(locl) - double(globl)) * 1000.0;
#else
TIME_ZONE_INFORMATION tzInfo;
GetTimeZoneInformation(&tzInfo);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 5c7caca477..8916cc597e 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -68,6 +68,7 @@
#include "qv4sequenceobject_p.h"
#include "qv4qobjectwrapper_p.h"
#include "qv4qmlextensions_p.h"
+#include "qv4memberdata_p.h"
#include <QtCore/QTextStream>
@@ -214,11 +215,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
identifierTable = new IdentifierTable(this);
- emptyClass = new (classPool.allocate(sizeof(InternalClass))) InternalClass(this);
+ classPool = new InternalClassPool;
+
+ emptyClass = new (classPool) InternalClass(this);
executionContextClass = InternalClass::create(this, ExecutionContext::staticVTable(), 0);
+ constructClass = InternalClass::create(this, Object::staticVTable(), 0);
stringClass = InternalClass::create(this, String::staticVTable(), 0);
regExpValueClass = InternalClass::create(this, RegExp::staticVTable(), 0);
+ id_empty = newIdentifier(QString());
id_undefined = newIdentifier(QStringLiteral("undefined"));
id_null = newIdentifier(QStringLiteral("null"));
id_true = newIdentifier(QStringLiteral("true"));
@@ -251,6 +256,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
id_destroy = newIdentifier(QStringLiteral("destroy"));
id_valueOf = newIdentifier(QStringLiteral("valueOf"));
+ memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0);
+
ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(InternalClass::create(this, ObjectPrototype::staticVTable(), 0));
objectClass = InternalClass::create(this, Object::staticVTable(), objectPrototype);
Q_ASSERT(objectClass->vtable == Object::staticVTable());
@@ -260,6 +267,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
ArrayPrototype *arrayPrototype = new (memoryManager) ArrayPrototype(arrayClass);
arrayClass = arrayClass->changePrototype(arrayPrototype);
+ simpleArrayDataClass = InternalClass::create(this, SimpleArrayData::staticVTable(), 0);
+
InternalClass *argsClass = InternalClass::create(this, ArgumentsObject::staticVTable(), objectPrototype);
argsClass = argsClass->addMember(id_length, Attr_NotEnumerable);
argumentsObjectClass = argsClass->addMember(id_callee, Attr_Data|Attr_NotEnumerable);
@@ -282,9 +291,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
DatePrototype *datePrototype = new (memoryManager) DatePrototype(InternalClass::create(this, DatePrototype::staticVTable(), objectPrototype));
dateClass = InternalClass::create(this, DateObject::staticVTable(), datePrototype);
- FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(InternalClass::create(this, FunctionPrototype::staticVTable(), objectPrototype));
- functionClass = InternalClass::create(this, FunctionObject::staticVTable(), functionPrototype);
+ InternalClass *functionProtoClass = InternalClass::create(this, FunctionObject::staticVTable(), objectPrototype);
uint index;
+ functionProtoClass = functionProtoClass->addMember(id_prototype, Attr_NotEnumerable, &index);
+ Q_ASSERT(index == FunctionObject::Index_Prototype);
+ FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(functionProtoClass);
+ functionClass = InternalClass::create(this, FunctionObject::staticVTable(), functionPrototype);
functionClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == FunctionObject::Index_Prototype);
protoClass = objectClass->addMember(id_constructor, Attr_NotEnumerable, &index);
@@ -419,6 +431,7 @@ ExecutionEngine::~ExecutionEngine()
delete m_qmlExtensions;
emptyClass->destroy();
+ delete classPool;
delete bumperPointerAllocator;
delete regExpCache;
delete regExpAllocator;
@@ -454,7 +467,7 @@ void ExecutionEngine::initRootContext()
InternalClass *ExecutionEngine::newClass(const InternalClass &other)
{
- return new (classPool.allocate(sizeof(InternalClass))) InternalClass(other);
+ return new (classPool) InternalClass(other);
}
ExecutionContext *ExecutionEngine::pushGlobalContext()
@@ -830,11 +843,22 @@ void ExecutionEngine::markObjects()
c = c->parent;
}
+ id_empty->mark(this);
+ id_undefined->mark(this);
+ id_null->mark(this);
+ id_true->mark(this);
+ id_false->mark(this);
+ id_boolean->mark(this);
+ id_number->mark(this);
+ id_string->mark(this);
+ id_object->mark(this);
+ id_function->mark(this);
id_length->mark(this);
id_prototype->mark(this);
id_constructor->mark(this);
id_arguments->mark(this);
id_caller->mark(this);
+ id_callee->mark(this);
id_this->mark(this);
id___proto__->mark(this);
id_enumerable->mark(this);
@@ -876,7 +900,7 @@ void ExecutionEngine::markObjects()
if (m_qmlExtensions)
m_qmlExtensions->markObjects(this);
- emptyClass->markObjects();
+ classPool->markObjects(this);
for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
it != end; ++it)
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 6bfdf1f5a1..d678d6595e 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -109,6 +109,7 @@ struct SequencePrototype;
struct EvalFunction;
struct IdentifierTable;
struct InternalClass;
+struct InternalClassPool;
class MultiplyWrappedQObjectMap;
class RegExp;
class RegExpCache;
@@ -197,13 +198,15 @@ public:
Value uRIErrorCtor;
Value sequencePrototype;
- QQmlJS::MemoryPool classPool;
+ InternalClassPool *classPool;
InternalClass *emptyClass;
InternalClass *executionContextClass;
+ InternalClass *constructClass;
InternalClass *stringClass;
InternalClass *objectClass;
InternalClass *arrayClass;
+ InternalClass *simpleArrayDataClass;
InternalClass *stringObjectClass;
InternalClass *booleanClass;
InternalClass *numberClass;
@@ -227,6 +230,7 @@ public:
InternalClass *strictArgumentsObjectClass;
InternalClass *variantClass;
+ InternalClass *memberDataClass;
EvalFunction *evalFunction;
FunctionObject *thrower;
@@ -234,6 +238,7 @@ public:
Property *argumentsAccessors;
int nArgumentsAccessors;
+ StringValue id_empty;
StringValue id_undefined;
StringValue id_null;
StringValue id_true;
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 29615e8ec2..9d6403e7dd 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -50,7 +50,6 @@
#include <cmath>
#include <qmath.h>
#include <qnumeric.h>
-#include <cassert>
#include <private/qqmljsengine_p.h>
#include <private/qqmljslexer_p.h>
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index 9b31524614..5c3419fd79 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -41,7 +41,6 @@
#include "qv4executableallocator_p.h"
-#include <assert.h>
#include <wtf/StdLibExtras.h>
#include <wtf/PageAllocation.h>
@@ -81,7 +80,7 @@ ExecutableAllocator::Allocation *ExecutableAllocator::Allocation::split(size_t d
bool ExecutableAllocator::Allocation::mergeNext(ExecutableAllocator *allocator)
{
- assert(free);
+ Q_ASSERT(free);
if (!next || !next->free)
return false;
@@ -101,7 +100,7 @@ bool ExecutableAllocator::Allocation::mergeNext(ExecutableAllocator *allocator)
bool ExecutableAllocator::Allocation::mergePrevious(ExecutableAllocator *allocator)
{
- assert(free);
+ Q_ASSERT(free);
if (!prev || !prev->free)
return false;
@@ -185,8 +184,8 @@ ExecutableAllocator::Allocation *ExecutableAllocator::allocate(size_t size)
chunk->firstAllocation = allocation;
}
- assert(allocation);
- assert(allocation->free);
+ Q_ASSERT(allocation);
+ Q_ASSERT(allocation->free);
allocation->free = false;
@@ -204,16 +203,16 @@ void ExecutableAllocator::free(Allocation *allocation)
{
QMutexLocker locker(&mutex);
- assert(allocation);
+ Q_ASSERT(allocation);
allocation->free = true;
QMap<quintptr, ChunkOfPages*>::Iterator it = chunks.lowerBound(allocation->addr);
if (it != chunks.begin())
--it;
- assert(it != chunks.end());
+ Q_ASSERT(it != chunks.end());
ChunkOfPages *chunk = *it;
- assert(chunk->contains(allocation));
+ Q_ASSERT(chunk->contains(allocation));
bool merged = allocation->mergeNext(this);
merged |= allocation->mergePrevious(this);
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index 8ce1146ac9..d54f29b89a 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -52,7 +52,7 @@
namespace WTF {
class PageAllocation;
-};
+}
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index c53c528e39..8e943fa6ef 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -167,12 +167,13 @@ ReturnedValue FunctionObject::call(Managed *, CallData *)
void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
{
FunctionObject *o = static_cast<FunctionObject *>(that);
- o->scope->mark(e);
+ if (o->scope)
+ o->scope->mark(e);
Object::markObjects(that, e);
}
-FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
+FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
{
if (function->needsActivation() ||
function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith ||
@@ -236,7 +237,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
QV4::Function *vmf = compilationUnit->linkToEngine(v4);
- return FunctionObject::creatScriptFunction(v4->rootContext, vmf)->asReturnedValue();
+ return FunctionObject::createScriptFunction(v4->rootContext, vmf)->asReturnedValue();
}
// 15.3.1: This is equivalent to new Function(...)
@@ -357,11 +358,6 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
Scope s(scope);
ScopedValue protectThis(s, this);
- this->function = function;
- this->function->compilationUnit->ref();
- Q_ASSERT(function);
- Q_ASSERT(function->code);
-
// global function
if (!scope)
return;
@@ -545,7 +541,7 @@ InternalClass *SimpleScriptFunction::internalClassForConstructor()
Scope scope(internalClass->engine);
ScopedObject p(scope, proto);
if (p)
- classForConstructor = InternalClass::create(scope.engine, Object::staticVTable(), p.getPointer());
+ classForConstructor = internalClass->engine->constructClass->changePrototype(p.getPointer());
else
classForConstructor = scope.engine->objectClass;
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 778b3157e8..5b832d0595 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -135,7 +135,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
return v.asFunctionObject();
}
- static FunctionObject *creatScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true);
+ static FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true);
ReturnedValue protoProperty() { return memberData[Index_Prototype].asReturnedValue(); }
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 4e05bb81ab..a00231c3a1 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -45,6 +45,7 @@
#include <QtCore/qglobal.h>
#include <QString>
#include <qtqmlglobal.h>
+#include <private/qtqmlglobal_p.h>
#if defined(Q_CC_MSVC)
#include <float.h>
@@ -66,6 +67,10 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
#define qOffsetOf(s, m) ((size_t)((((char *)&(((s *)64)->m)) - 64)))
+#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+#define V4_BOOTSTRAP
+#endif
+
// Decide whether to enable or disable the JIT
// White list architectures
@@ -184,8 +189,8 @@ enum PropertyFlag {
Attr_Invalid = 0xff
};
-Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag);
-Q_DECLARE_OPERATORS_FOR_FLAGS(PropertyFlags);
+Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
+Q_DECLARE_OPERATORS_FOR_FLAGS(PropertyFlags)
struct PropertyAttributes
{
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 76a8b0c25c..eb0994c1e6 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -414,7 +414,7 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
needsActivation = function->needsActivation();
if (strictMode) {
- ScopedFunctionObject e(scope, FunctionObject::creatScriptFunction(ctx, function));
+ ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
ScopedCallData callData(scope, 0);
callData->thisObject = ctx->callData->thisObject;
return e->call(callData);
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index 02fc8b70c6..09956fc342 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -80,9 +80,14 @@ public:
Identifier *identifierImpl(const String *str);
void mark(ExecutionEngine *e) {
- for (int i = 0; i < alloc; ++i)
- if (entries[i])
- entries[i]->mark(e);
+ for (int i = 0; i < alloc; ++i) {
+ String *entry = entries[i];
+ if (!entry || entry->markBit)
+ continue;
+ entry->markBit = 1;
+ Q_ASSERT(entry->internalClass->vtable->markObjects);
+ entry->internalClass->vtable->markObjects(entry, e);
+ }
}
};
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 7642db1e9b..d5bae0e35e 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -148,7 +148,7 @@ void QV4Include::finished()
QByteArray data = m_reply->readAll();
QString code = QString::fromUtf8(data);
- QQmlScript::Parser::extractPragmas(code);
+ QmlIR::Document::removeScriptPragmas(code);
QV4::ScopedObject qmlglobal(scope, m_qmlglobal.value());
QV4::Script script(v4, qmlglobal, code, m_url.toString());
@@ -216,7 +216,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
if (f.open(QIODevice::ReadOnly)) {
QByteArray data = f.readAll();
QString code = QString::fromUtf8(data);
- QQmlScript::Parser::extractPragmas(code);
+ QmlIR::Document::removeScriptPragmas(code);
QV4::Script script(v4, qmlcontextobject, code, url.toString());
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 4fe8f0bd44..3dc20b8e76 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -129,7 +129,7 @@ uint PropertyHash::lookup(const Identifier *identifier) const
InternalClass::InternalClass(ExecutionEngine *engine)
: engine(engine)
, prototype(0)
- , vtable(&Managed::static_vtbl)
+ , vtable(&QV4::Managed::static_vtbl)
, m_sealed(0)
, m_frozen(0)
, size(0)
@@ -138,7 +138,8 @@ InternalClass::InternalClass(ExecutionEngine *engine)
InternalClass::InternalClass(const QV4::InternalClass &other)
- : engine(other.engine)
+ : QQmlJS::Managed()
+ , engine(other.engine)
, prototype(other.prototype)
, vtable(other.vtable)
, propertyTable(other.propertyTable)
@@ -160,10 +161,10 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu
if (newClass->size > object->internalClass->size) {
Q_ASSERT(newClass->size == object->internalClass->size + 1);
- memmove(object->memberData + idx + 2, object->memberData + idx + 1, (object->internalClass->size - idx - 1)*sizeof(Value));
+ memmove(object->memberData.data() + idx + 2, object->memberData.data() + idx + 1, (object->internalClass->size - idx - 1)*sizeof(Value));
} else if (newClass->size < object->internalClass->size) {
Q_ASSERT(newClass->size == object->internalClass->size - 1);
- memmove(object->memberData + idx + 1, object->memberData + idx + 2, (object->internalClass->size - idx - 2)*sizeof(Value));
+ memmove(object->memberData.data() + idx + 1, object->memberData.data() + idx + 2, (object->internalClass->size - idx - 2)*sizeof(Value));
}
object->internalClass = newClass;
}
@@ -368,7 +369,7 @@ void InternalClass::removeMember(Object *object, Identifier *id)
}
// remove the entry in memberdata
- memmove(object->memberData + propIdx, object->memberData + propIdx + 1, (object->internalClass->size - propIdx)*sizeof(Value));
+ memmove(object->memberData.data() + propIdx, object->memberData.data() + propIdx + 1, (object->internalClass->size - propIdx)*sizeof(Value));
oldClass->transitions.insert(t, object->internalClass);
}
@@ -455,20 +456,24 @@ void InternalClass::destroy()
transitions.clear();
}
-void InternalClass::markObjects()
+struct InternalClassPoolVisitor
{
- // all prototype changes are done on the empty class
- Q_ASSERT(!prototype);
-
- for (QHash<Transition, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end();
- it != end; ++it) {
- if (it.key().flags == Transition::VTableChange) {
- it.value()->markObjects();
- } else if (it.key().flags == Transition::ProtoChange) {
- Q_ASSERT(it.value()->prototype);
- it.value()->prototype->mark(engine);
- }
+ ExecutionEngine *engine;
+ void operator()(InternalClass *klass)
+ {
+ // all prototype changes are done on the empty class
+ Q_ASSERT(!klass->prototype || klass != engine->emptyClass);
+
+ if (klass->prototype)
+ klass->prototype->mark(engine);
}
+};
+
+void InternalClassPool::markObjects(ExecutionEngine *engine)
+{
+ InternalClassPoolVisitor v;
+ v.engine = engine;
+ visitManagedPool<InternalClass, InternalClassPoolVisitor>(v);
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 91c6e264db..bd1828a146 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -44,6 +44,7 @@
#include <QHash>
#include <QVector>
#include "qv4global_p.h"
+#include <private/qqmljsmemorypool_p.h>
QT_BEGIN_NAMESPACE
@@ -213,7 +214,7 @@ struct InternalClassTransition
};
uint qHash(const QV4::InternalClassTransition &t, uint = 0);
-struct InternalClass {
+struct InternalClass : public QQmlJS::Managed {
ExecutionEngine *engine;
Object *prototype;
const ManagedVTable *vtable;
@@ -247,7 +248,6 @@ struct InternalClass {
InternalClass *frozen();
void destroy();
- void markObjects();
private:
InternalClass *addMemberImpl(String *string, PropertyAttributes data, uint *index);
@@ -256,6 +256,11 @@ private:
InternalClass(const InternalClass &other);
};
+struct InternalClassPool : public QQmlJS::MemoryPool
+{
+ void markObjects(ExecutionEngine *engine);
+};
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 36706f2766..ca82af1b30 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -594,8 +594,6 @@ static inline bool scanEscapeSequence(const QChar *&json, const QChar *end, uint
return false;
++json;
}
- if (*ch <= 0x1f)
- return false;
return true;
}
default:
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 081b5b3514..1155bbf9e9 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -288,6 +288,52 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object)
return Encode::undefined();
}
+ReturnedValue Lookup::getterTwoClasses(Lookup *l, const ValueRef object)
+{
+ Lookup l1 = *l;
+
+ if (l1.getter == Lookup::getter0 || l1.getter == Lookup::getter1) {
+ if (Object *o = object->asObject()) {
+ ReturnedValue v = o->getLookup(l);
+ Lookup l2 = *l;
+
+ if (l2.getter == Lookup::getter0 || l2.getter == Lookup::getter1) {
+ // if we have a getter0, make sure it comes first
+ if (l2.getter == Lookup::getter0)
+ qSwap(l1, l2);
+
+ l->classList[0] = l1.classList[0];
+ l->classList[1] = l1.classList[1];
+ l->classList[2] = l2.classList[0];
+ l->classList[3] = l2.classList[1];
+ l->index = l1.index;
+ l->index2 = l2.index;
+
+ if (l1.getter == Lookup::getter0) {
+ l->getter = (l2.getter == Lookup::getter0) ? Lookup::getter0getter0 : Lookup::getter0getter1;
+ } else {
+ Q_ASSERT(l1.getter == Lookup::getter1 && l2.getter == Lookup::getter1);
+ l->getter = Lookup::getter1getter1;
+ }
+ return v;
+ }
+ }
+ }
+
+ l->getter = getterFallback;
+ return getterFallback(l, object);
+}
+
+ReturnedValue Lookup::getterFallback(Lookup *l, const ValueRef object)
+{
+ QV4::Scope scope(l->name->engine());
+ QV4::ScopedObject o(scope, object->toObject(scope.engine->currentContext()));
+ if (!o)
+ return Encode::undefined();
+ QV4::ScopedString s(scope, l->name);
+ return o->get(s);
+}
+
ReturnedValue Lookup::getter0(Lookup *l, const ValueRef object)
{
if (object->isManaged()) {
@@ -295,10 +341,9 @@ ReturnedValue Lookup::getter0(Lookup *l, const ValueRef object)
// the internal class won't match
Object *o = object->objectValue();
if (l->classList[0] == o->internalClass)
- return static_cast<Object *>(o)->memberData[l->index].asReturnedValue();
+ return o->memberData[l->index].asReturnedValue();
}
- l->getter = getterGeneric;
- return getterGeneric(l, object);
+ return getterTwoClasses(l, object);
}
ReturnedValue Lookup::getter1(Lookup *l, const ValueRef object)
@@ -311,8 +356,7 @@ ReturnedValue Lookup::getter1(Lookup *l, const ValueRef object)
l->classList[1] == o->prototype()->internalClass)
return o->prototype()->memberData[l->index].asReturnedValue();
}
- l->getter = getterGeneric;
- return getterGeneric(l, object);
+ return getterTwoClasses(l, object);
}
ReturnedValue Lookup::getter2(Lookup *l, const ValueRef object)
@@ -330,10 +374,60 @@ ReturnedValue Lookup::getter2(Lookup *l, const ValueRef object)
}
}
}
- l->getter = getterGeneric;
- return getterGeneric(l, object);
+ l->getter = getterFallback;
+ return getterFallback(l, object);
+}
+
+ReturnedValue Lookup::getter0getter0(Lookup *l, const ValueRef object)
+{
+ if (object->isManaged()) {
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Object *o = object->objectValue();
+ if (l->classList[0] == o->internalClass)
+ return o->memberData[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass)
+ return o->memberData[l->index2].asReturnedValue();
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, object);
+}
+
+ReturnedValue Lookup::getter0getter1(Lookup *l, const ValueRef object)
+{
+ if (object->isManaged()) {
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Object *o = object->objectValue();
+ if (l->classList[0] == o->internalClass)
+ return o->memberData[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass &&
+ l->classList[3] == o->prototype()->internalClass)
+ return o->prototype()->memberData[l->index2].asReturnedValue();
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, object);
+}
+
+ReturnedValue Lookup::getter1getter1(Lookup *l, const ValueRef object)
+{
+ if (object->isManaged()) {
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Object *o = object->objectValue();
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype()->internalClass)
+ return o->prototype()->memberData[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass &&
+ l->classList[3] == o->prototype()->internalClass)
+ return o->prototype()->memberData[l->index2].asReturnedValue();
+ return getterFallback(l, object);
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, object);
}
+
ReturnedValue Lookup::getterAccessor0(Lookup *l, const ValueRef object)
{
if (object->isManaged()) {
@@ -351,8 +445,8 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, const ValueRef object)
return getter->call(callData);
}
}
- l->getter = getterGeneric;
- return getterGeneric(l, object);
+ l->getter = getterFallback;
+ return getterFallback(l, object);
}
ReturnedValue Lookup::getterAccessor1(Lookup *l, const ValueRef object)
@@ -373,8 +467,8 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, const ValueRef object)
return getter->call(callData);
}
}
- l->getter = getterGeneric;
- return getterGeneric(l, object);
+ l->getter = getterFallback;
+ return getterFallback(l, object);
}
ReturnedValue Lookup::getterAccessor2(Lookup *l, const ValueRef object)
@@ -400,11 +494,10 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, const ValueRef object)
}
}
}
- l->getter = getterGeneric;
- return getterGeneric(l, object);
+ l->getter = getterFallback;
+ return getterFallback(l, object);
}
-
ReturnedValue Lookup::primitiveGetter0(Lookup *l, const ValueRef object)
{
if (object->type() == l->type) {
@@ -625,24 +718,52 @@ void Lookup::setterGeneric(Lookup *l, const ValueRef object, const ValueRef valu
o->setLookup(l, value);
}
+void Lookup::setterTwoClasses(Lookup *l, const ValueRef object, const ValueRef value)
+{
+ Lookup l1 = *l;
+
+ if (Object *o = object->asObject()) {
+ o->setLookup(l, value);
+
+ if (l->setter == Lookup::setter0) {
+ l->setter = setter0setter0;
+ l->classList[1] = l1.classList[0];
+ l->index2 = l1.index;
+ return;
+ }
+ }
+
+ l->setter = setterFallback;
+ setterFallback(l, object, value);
+}
+
+void Lookup::setterFallback(Lookup *l, const ValueRef object, const ValueRef value)
+{
+ QV4::Scope scope(l->name->engine());
+ QV4::ScopedObject o(scope, object->toObject(scope.engine->currentContext()));
+ if (o) {
+ QV4::ScopedString s(scope, l->name);
+ o->put(s, value);
+ }
+}
+
void Lookup::setter0(Lookup *l, const ValueRef object, const ValueRef value)
{
- Object *o = object->asObject();
+ Object *o = static_cast<Object *>(object->asManaged());
if (o && o->internalClass == l->classList[0]) {
o->memberData[l->index] = *value;
return;
}
- l->setter = setterGeneric;
- setterGeneric(l, object, value);
+ setterTwoClasses(l, object, value);
}
void Lookup::setterInsert0(Lookup *l, const ValueRef object, const ValueRef value)
{
- Object *o = object->asObject();
+ Object *o = static_cast<Object *>(object->asManaged());
if (o && o->internalClass == l->classList[0]) {
if (!o->prototype()) {
- if (l->index >= o->memberDataAlloc)
+ if (l->index >= o->memberData.size())
o->ensureMemberIndex(l->index);
o->memberData[l->index] = *value;
o->internalClass = l->classList[3];
@@ -650,17 +771,17 @@ void Lookup::setterInsert0(Lookup *l, const ValueRef object, const ValueRef valu
}
}
- l->setter = setterGeneric;
- setterGeneric(l, object, value);
+ l->setter = setterFallback;
+ setterFallback(l, object, value);
}
void Lookup::setterInsert1(Lookup *l, const ValueRef object, const ValueRef value)
{
- Object *o = object->asObject();
+ Object *o = static_cast<Object *>(object->asManaged());
if (o && o->internalClass == l->classList[0]) {
Object *p = o->prototype();
if (p && p->internalClass == l->classList[1]) {
- if (l->index >= o->memberDataAlloc)
+ if (l->index >= o->memberData.size())
o->ensureMemberIndex(l->index);
o->memberData[l->index] = *value;
o->internalClass = l->classList[3];
@@ -668,19 +789,19 @@ void Lookup::setterInsert1(Lookup *l, const ValueRef object, const ValueRef valu
}
}
- l->setter = setterGeneric;
- setterGeneric(l, object, value);
+ l->setter = setterFallback;
+ setterFallback(l, object, value);
}
void Lookup::setterInsert2(Lookup *l, const ValueRef object, const ValueRef value)
{
- Object *o = object->asObject();
+ Object *o = static_cast<Object *>(object->asManaged());
if (o && o->internalClass == l->classList[0]) {
Object *p = o->prototype();
if (p && p->internalClass == l->classList[1]) {
p = p->prototype();
if (p && p->internalClass == l->classList[2]) {
- if (l->index >= o->memberDataAlloc)
+ if (l->index >= o->memberData.size())
o->ensureMemberIndex(l->index);
o->memberData[l->index] = *value;
o->internalClass = l->classList[3];
@@ -689,8 +810,27 @@ void Lookup::setterInsert2(Lookup *l, const ValueRef object, const ValueRef valu
}
}
- l->setter = setterGeneric;
- setterGeneric(l, object, value);
+ l->setter = setterFallback;
+ setterFallback(l, object, value);
+}
+
+void Lookup::setter0setter0(Lookup *l, const ValueRef object, const ValueRef value)
+{
+ Object *o = static_cast<Object *>(object->asManaged());
+ if (o) {
+ if (o->internalClass == l->classList[0]) {
+ o->memberData[l->index] = *value;
+ return;
+ }
+ if (o->internalClass == l->classList[1]) {
+ o->memberData[l->index2] = *value;
+ return;
+ }
+ }
+
+ l->setter = setterFallback;
+ setterFallback(l, object, value);
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 7f107bf8eb..3dd2c7f6ce 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -71,7 +71,10 @@ struct Lookup {
unsigned type;
};
};
- int level;
+ union {
+ int level;
+ uint index2;
+ };
uint index;
String *name;
@@ -84,9 +87,15 @@ struct Lookup {
static void indexedSetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v);
static ReturnedValue getterGeneric(Lookup *l, const ValueRef object);
+ static ReturnedValue getterTwoClasses(Lookup *l, const ValueRef object);
+ static ReturnedValue getterFallback(Lookup *l, const ValueRef object);
+
static ReturnedValue getter0(Lookup *l, const ValueRef object);
static ReturnedValue getter1(Lookup *l, const ValueRef object);
static ReturnedValue getter2(Lookup *l, const ValueRef object);
+ static ReturnedValue getter0getter0(Lookup *l, const ValueRef object);
+ static ReturnedValue getter0getter1(Lookup *l, const ValueRef object);
+ static ReturnedValue getter1getter1(Lookup *l, const ValueRef object);
static ReturnedValue getterAccessor0(Lookup *l, const ValueRef object);
static ReturnedValue getterAccessor1(Lookup *l, const ValueRef object);
static ReturnedValue getterAccessor2(Lookup *l, const ValueRef object);
@@ -107,10 +116,13 @@ struct Lookup {
static ReturnedValue globalGetterAccessor2(Lookup *l, ExecutionContext *ctx);
static void setterGeneric(Lookup *l, const ValueRef object, const ValueRef value);
+ static void setterTwoClasses(Lookup *l, const ValueRef object, const ValueRef value);
+ static void setterFallback(Lookup *l, const ValueRef object, const ValueRef value);
static void setter0(Lookup *l, const ValueRef object, const ValueRef value);
static void setterInsert0(Lookup *l, const ValueRef object, const ValueRef value);
static void setterInsert1(Lookup *l, const ValueRef object, const ValueRef value);
static void setterInsert2(Lookup *l, const ValueRef object, const ValueRef value);
+ static void setter0setter0(Lookup *l, const ValueRef object, const ValueRef value);
ReturnedValue lookup(ValueRef thisObject, Object *obj, PropertyAttributes *attrs);
ReturnedValue lookup(Object *obj, PropertyAttributes *attrs);
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 8c6f2daf9b..06d3e4884b 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -111,7 +111,6 @@ struct ObjectVTable
ManagedVTable managedVTable;
ReturnedValue (*call)(Managed *, CallData *data);
ReturnedValue (*construct)(Managed *, CallData *data);
- void (*collectDeletables)(Managed *, GCDeletable **deletable);
ReturnedValue (*get)(Managed *, const StringRef name, bool *hasProperty);
ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty);
void (*put)(Managed *, const StringRef name, const ValueRef value);
@@ -153,7 +152,6 @@ const QV4::ObjectVTable classname::static_vtbl = \
DEFINE_MANAGED_VTABLE_INT(classname), \
call, \
construct, \
- 0, \
get, \
getIndexed, \
put, \
@@ -174,7 +172,6 @@ const QV4::ObjectVTable classname::static_vtbl = \
DEFINE_MANAGED_VTABLE_INT(name), \
call, \
construct, \
- 0, \
get, \
getIndexed, \
put, \
@@ -189,28 +186,8 @@ const QV4::ObjectVTable classname::static_vtbl = \
advanceIterator \
}
-#define DEFINE_MANAGED_VTABLE_WITH_DELETABLES(classname) \
-const QV4::ObjectVTable classname::static_vtbl = \
-{ \
- DEFINE_MANAGED_VTABLE_INT(classname), \
- call, \
- construct, \
- collectDeletables, \
- get, \
- getIndexed, \
- put, \
- putIndexed, \
- query, \
- queryIndexed, \
- deleteProperty, \
- deleteIndexedProperty, \
- getLookup, \
- setLookup, \
- getLength, \
- advanceIterator \
-}
-struct Q_QML_EXPORT Managed
+struct Q_QML_PRIVATE_EXPORT Managed
{
V4_MANAGED
enum {
diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h
index 9ddb57eaaf..a868e70c9a 100644
--- a/src/qml/jsruntime/qv4math_p.h
+++ b/src/qml/jsruntime/qv4math_p.h
@@ -73,7 +73,8 @@ static inline QMLJS_READONLY Value add_int32(int a, int b)
);
if (!overflow)
return Primitive::fromInt32(aa);
- return Primitive::fromDouble((double)a + (double)b);
+ qint64 result = static_cast<qint64>(a) + b;
+ return Primitive::fromDouble(result);
}
static inline QMLJS_READONLY Value sub_int32(int a, int b)
@@ -89,7 +90,8 @@ static inline QMLJS_READONLY Value sub_int32(int a, int b)
);
if (!overflow)
return Primitive::fromInt32(aa);
- return Primitive::fromDouble((double)a - (double)b);
+ qint64 result = static_cast<qint64>(a) - b;
+ return Primitive::fromDouble(result);
}
static inline QMLJS_READONLY Value mul_int32(int a, int b)
@@ -105,14 +107,15 @@ static inline QMLJS_READONLY Value mul_int32(int a, int b)
);
if (!overflow)
return Primitive::fromInt32(aa);
- return Primitive::fromDouble((double)a * (double)b);
+ qint64 result = static_cast<qint64>(a) * b;
+ return Primitive::fromDouble(result);
}
#else
static inline QMLJS_READONLY Value add_int32(int a, int b)
{
- qint64 result = a + b;
+ qint64 result = static_cast<qint64>(a) + b;
if (result > INT_MAX || result < INT_MIN)
return Primitive::fromDouble(result);
return Primitive::fromInt32(static_cast<int>(result));
@@ -120,7 +123,7 @@ static inline QMLJS_READONLY Value add_int32(int a, int b)
static inline QMLJS_READONLY Value sub_int32(int a, int b)
{
- qint64 result = a - b;
+ qint64 result = static_cast<qint64>(a) - b;
if (result > INT_MAX || result < INT_MIN)
return Primitive::fromDouble(result);
return Primitive::fromInt32(static_cast<int>(result));
@@ -128,7 +131,7 @@ static inline QMLJS_READONLY Value sub_int32(int a, int b)
static inline QMLJS_READONLY Value mul_int32(int a, int b)
{
- qint64 result = a * b;
+ qint64 result = static_cast<qint64>(a) * b;
if (result > INT_MAX || result < INT_MIN)
return Primitive::fromDouble(result);
return Primitive::fromInt32(static_cast<int>(result));
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
new file mode 100644
index 0000000000..aeb4c38a8e
--- /dev/null
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4memberdata_p.h"
+#include "qv4mm_p.h"
+
+using namespace QV4;
+
+const ManagedVTable MemberData::static_vtbl =
+{
+ MemberData::IsExecutionContext,
+ MemberData::IsString,
+ MemberData::IsObject,
+ MemberData::IsFunctionObject,
+ MemberData::IsErrorObject,
+ MemberData::IsArrayData,
+ 0,
+ MemberData::MyType,
+ "MemberData",
+ destroy,
+ markObjects,
+ isEqualTo
+};
+
+
+
+void MemberData::markObjects(Managed *that, ExecutionEngine *e)
+{
+ MemberData *m = static_cast<MemberData *>(that);
+ for (uint i = 0; i < m->size; ++i)
+ m->data[i].mark(e);
+}
+
+void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx)
+{
+ uint s = size();
+ if (idx >= s) {
+ int newAlloc = qMax((uint)4, 2*idx);
+ uint alloc = sizeof(MemberData) + (newAlloc)*sizeof(Value);
+ MemberData *newMemberData = reinterpret_cast<MemberData *>(e->memoryManager->allocManaged(alloc));
+ if (d())
+ memcpy(newMemberData, d(), sizeof(MemberData) + s*sizeof(Value));
+ else
+ new (newMemberData) MemberData(e->memberDataClass);
+ newMemberData->size = newAlloc;
+ m = newMemberData;
+ }
+}
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
new file mode 100644
index 0000000000..03aa75a365
--- /dev/null
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4MEMBERDATA_H
+#define QV4MEMBERDATA_H
+
+#include "qv4global_p.h"
+#include "qv4managed_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct MemberData : Managed
+{
+ V4_MANAGED
+ uint size;
+ Value data[1];
+
+ MemberData(QV4::InternalClass *ic) : Managed(ic) {}
+ Value &operator[] (uint idx) { return data[idx]; }
+
+ static void markObjects(Managed *that, ExecutionEngine *e);
+};
+
+struct Members : Value
+{
+ void ensureIndex(QV4::ExecutionEngine *e, uint idx);
+ Value &operator[] (uint idx) const { return static_cast<MemberData *>(managed())->data[idx]; }
+ inline uint size() const { return d() ? d()->size : 0; }
+ inline MemberData *d() const { return static_cast<MemberData *>(managed()); }
+ Value *data() const { return static_cast<MemberData *>(managed())->data; }
+
+ void mark(ExecutionEngine *e) const {
+ MemberData *m = d();
+ if (m)
+ m->mark(e);
+ }
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index 30a8a47ec8..ca2ccd33f7 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -76,74 +76,12 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
using namespace WTF;
-static const std::size_t CHUNK_SIZE = 1024*32;
-
-#if OS(WINCE)
-void* g_stackBase = 0;
-
-inline bool isPageWritable(void* page)
-{
- MEMORY_BASIC_INFORMATION memoryInformation;
- DWORD result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation));
-
- // return false on error, including ptr outside memory
- if (result != sizeof(memoryInformation))
- return false;
-
- DWORD protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE);
- return protect == PAGE_READWRITE
- || protect == PAGE_WRITECOPY
- || protect == PAGE_EXECUTE_READWRITE
- || protect == PAGE_EXECUTE_WRITECOPY;
-}
-
-static void* getStackBase(void* previousFrame)
-{
- // find the address of this stack frame by taking the address of a local variable
- bool isGrowingDownward;
- void* thisFrame = (void*)(&isGrowingDownward);
-
- isGrowingDownward = previousFrame < &thisFrame;
- static DWORD pageSize = 0;
- if (!pageSize) {
- SYSTEM_INFO systemInfo;
- GetSystemInfo(&systemInfo);
- pageSize = systemInfo.dwPageSize;
- }
-
- // scan all of memory starting from this frame, and return the last writeable page found
- register char* currentPage = (char*)((DWORD)thisFrame & ~(pageSize - 1));
- if (isGrowingDownward) {
- while (currentPage > 0) {
- // check for underflow
- if (currentPage >= (char*)pageSize)
- currentPage -= pageSize;
- else
- currentPage = 0;
- if (!isPageWritable(currentPage))
- return currentPage + pageSize;
- }
- return 0;
- } else {
- while (true) {
- // guaranteed to complete because isPageWritable returns false at end of memory
- currentPage += pageSize;
- if (!isPageWritable(currentPage))
- return currentPage;
- }
- }
-}
-#endif
-
struct MemoryManager::Data
{
- bool enableGC;
bool gcBlocked;
- bool scribble;
bool aggressiveGC;
- bool exactGC;
+ bool gcStats;
ExecutionEngine *engine;
- quintptr *stackTop;
enum { MaxItemSize = 512 };
Managed *smallItems[MaxItemSize/16];
@@ -153,6 +91,7 @@ struct MemoryManager::Data
int totalItems;
int totalAlloc;
uint maxShift;
+ std::size_t maxChunkSize;
struct Chunk {
PageAllocation memory;
int chunkSize;
@@ -172,35 +111,40 @@ struct MemoryManager::Data
LargeItem *largeItems;
+ GCDeletable *deletable;
// statistics:
#ifdef DETAILED_MM_STATS
QVector<unsigned> allocSizeCounters;
#endif // DETAILED_MM_STATS
- Data(bool enableGC)
- : enableGC(enableGC)
- , gcBlocked(false)
+ Data()
+ : gcBlocked(false)
, engine(0)
- , stackTop(0)
, totalItems(0)
, totalAlloc(0)
- , maxShift(10)
+ , maxShift(6)
+ , maxChunkSize(32*1024)
, largeItems(0)
+ , deletable(0)
{
memset(smallItems, 0, sizeof(smallItems));
memset(nChunks, 0, sizeof(nChunks));
memset(availableItems, 0, sizeof(availableItems));
memset(allocCount, 0, sizeof(allocCount));
- scribble = !qgetenv("QV4_MM_SCRIBBLE").isEmpty();
aggressiveGC = !qgetenv("QV4_MM_AGGRESSIVE_GC").isEmpty();
- exactGC = qgetenv("QV4_MM_CONSERVATIVE_GC").isEmpty();
+ gcStats = !qgetenv("QV4_MM_STATS").isEmpty();
QByteArray overrideMaxShift = qgetenv("QV4_MM_MAXBLOCK_SHIFT");
bool ok;
uint override = overrideMaxShift.toUInt(&ok);
if (ok && override <= 11 && override > 0)
maxShift = override;
+
+ QByteArray maxChunkString = qgetenv("QV4_MM_MAX_CHUNK_SIZE");
+ std::size_t tmpMaxChunkSize = maxChunkString.toUInt(&ok);
+ if (ok)
+ maxChunkSize = tmpMaxChunkSize;
}
~Data()
@@ -210,10 +154,6 @@ struct MemoryManager::Data
}
};
-#define SCRIBBLE(obj, c, size) \
- if (m_d->scribble) \
- ::memset((void *)(obj + 1), c, size - sizeof(Managed));
-
namespace QV4 {
@@ -225,58 +165,13 @@ bool operator<(const MemoryManager::Data::Chunk &a, const MemoryManager::Data::C
} // namespace QV4
MemoryManager::MemoryManager()
- : m_d(new Data(true))
+ : m_d(new Data)
, m_persistentValues(0)
, m_weakValues(0)
{
- setEnableGC(true);
#ifdef V4_USE_VALGRIND
VALGRIND_CREATE_MEMPOOL(this, 0, true);
#endif
-
-#if OS(QNX)
- // TLS is at the top of each thread's stack,
- // so the stack base for thread is the result of __tls()
- m_d->stackTop = reinterpret_cast<quintptr *>(
- (((quintptr)__tls() + __PAGESIZE - 1) & ~(__PAGESIZE - 1)));
-#elif USE(PTHREADS)
-# if OS(DARWIN)
- void *st = pthread_get_stackaddr_np(pthread_self());
- m_d->stackTop = static_cast<quintptr *>(st);
-# else
- void* stackBottom = 0;
- pthread_attr_t attr;
-#if HAVE(PTHREAD_NP_H) && OS(FREEBSD)
- if (pthread_attr_get_np(pthread_self(), &attr) == 0) {
-#else
- if (pthread_getattr_np(pthread_self(), &attr) == 0) {
-#endif
- size_t stackSize = 0;
- pthread_attr_getstack(&attr, &stackBottom, &stackSize);
- pthread_attr_destroy(&attr);
-
- m_d->stackTop = static_cast<quintptr *>(stackBottom) + stackSize/sizeof(quintptr);
- } else {
- // can't scan the native stack so have to rely on exact gc
- m_d->stackTop = 0;
- m_d->exactGC = true;
- }
-# endif
-#elif OS(WINCE)
- if (false && g_stackBase) {
- // This code path is disabled as we have no way of initializing it yet
- m_d->stackTop = static_cast<quintptr *>(g_stackBase);
- } else {
- int dummy;
- m_d->stackTop = static_cast<quintptr *>(getStackBase(&dummy));
- }
-#elif OS(WINDOWS)
- PNT_TIB tib = (PNT_TIB)NtCurrentTeb();
- m_d->stackTop = static_cast<quintptr*>(tib->StackBase);
-#else
-# error "Unsupported platform: no way to get the top-of-stack."
-#endif
-
}
Managed *MemoryManager::alloc(std::size_t size)
@@ -316,11 +211,11 @@ Managed *MemoryManager::alloc(std::size_t size)
// no free item available, allocate a new chunk
{
- // allocate larger chunks at a time to avoid excessive GC, but cap at maximum chunk size (32MB by default)
+ // allocate larger chunks at a time to avoid excessive GC, but cap at maximum chunk size (2MB by default)
uint shift = ++m_d->nChunks[pos];
if (shift > m_d->maxShift)
shift = m_d->maxShift;
- std::size_t allocSize = CHUNK_SIZE*(size_t(1) << shift);
+ std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize);
Data::Chunk allocation;
allocation.memory = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
@@ -329,9 +224,7 @@ Managed *MemoryManager::alloc(std::size_t size)
std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end());
char *chunk = (char *)allocation.memory.base();
char *end = chunk + allocation.memory.size() - size;
-#ifndef QT_NO_DEBUG
- memset(chunk, 0, allocation.memory.size());
-#endif
+
Managed **last = &m_d->smallItems[pos];
while (chunk <= end) {
Managed *o = reinterpret_cast<Managed *>(chunk);
@@ -382,37 +275,6 @@ void MemoryManager::mark()
collectFromJSStack();
- if (!m_d->exactGC) {
- // push all caller saved registers to the stack, so we can find the objects living in these registers
-#if COMPILER(MSVC) && !OS(WINRT) // WinRT must use exact GC
-# if CPU(X86_64)
- HANDLE thread = GetCurrentThread();
- WOW64_CONTEXT ctxt;
- /*bool success =*/ Wow64GetThreadContext(thread, &ctxt);
-# elif CPU(X86)
- HANDLE thread = GetCurrentThread();
- CONTEXT ctxt;
- /*bool success =*/ GetThreadContext(thread, &ctxt);
-# endif // CPU
-#elif COMPILER(CLANG) || COMPILER(GCC)
-# if CPU(X86_64)
- quintptr regs[5];
- asm(
- "mov %%rbp, %0\n"
- "mov %%r12, %1\n"
- "mov %%r13, %2\n"
- "mov %%r14, %3\n"
- "mov %%r15, %4\n"
- : "=m" (regs[0]), "=m" (regs[1]), "=m" (regs[2]), "=m" (regs[3]), "=m" (regs[4])
- :
- :
- );
-# endif // CPU
-#endif // COMPILER
-
- collectFromStack();
- }
-
// Preserve QObject ownership rules within JavaScript: A parent with c++ ownership
// keeps all of its children alive in JavaScript.
@@ -483,11 +345,8 @@ void MemoryManager::sweep(bool lastSweep)
}
}
- GCDeletable *deletable = 0;
- GCDeletable **firstDeletable = &deletable;
-
for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i)
- sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize, &deletable);
+ sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize);
Data::LargeItem *i = m_d->largeItems;
Data::LargeItem **last = &m_d->largeItems;
@@ -500,13 +359,16 @@ void MemoryManager::sweep(bool lastSweep)
i = i->next;
continue;
}
+ if (m->internalClass->vtable->destroy)
+ m->internalClass->vtable->destroy(m);
*last = i->next;
free(i);
i = *last;
}
- deletable = *firstDeletable;
+ GCDeletable *deletable = m_d->deletable;
+ m_d->deletable = 0;
while (deletable) {
GCDeletable *next = deletable->next;
deletable->lastCall = lastSweep;
@@ -515,7 +377,7 @@ void MemoryManager::sweep(bool lastSweep)
}
}
-void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable)
+void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size)
{
// qDebug("chunkStart @ %p, size=%x, pos=%x (%x)", chunkStart, size, size>>4, m_d->smallItems[size >> 4]);
Managed **f = &m_d->smallItems[size >> 4];
@@ -538,10 +400,8 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size,
#ifdef V4_USE_VALGRIND
VALGRIND_ENABLE_ERROR_REPORTING;
#endif
- Object *o = m->asObject();
- if (o && o->vtable()->collectDeletables)
- o->vtable()->collectDeletables(m, deletable);
- m->internalClass->vtable->destroy(m);
+ if (m->internalClass->vtable->destroy)
+ m->internalClass->vtable->destroy(m);
memset(m, 0, size);
m->setNextFree(*f);
@@ -550,7 +410,6 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size,
VALGRIND_MEMPOOL_FREE(this, m);
#endif
*f = m;
- SCRIBBLE(m, 0x99, size);
}
}
}
@@ -571,32 +430,57 @@ void MemoryManager::setGCBlocked(bool blockGC)
void MemoryManager::runGC()
{
- if (!m_d->enableGC || m_d->gcBlocked) {
+ if (m_d->gcBlocked) {
// qDebug() << "Not running GC.";
return;
}
-// QTime t; t.start();
-
-// qDebug() << ">>>>>>>>runGC";
-
- mark();
-// std::cerr << "GC: marked " << marks
-// << " objects in " << t.elapsed()
-// << "ms" << std::endl;
+ if (!m_d->gcStats) {
+ mark();
+ sweep();
+ } else {
+ int totalMem = 0;
+ for (int i = 0; i < m_d->heapChunks.size(); ++i)
+ totalMem += m_d->heapChunks.at(i).memory.size();
+
+ QTime t;
+ t.start();
+ mark();
+ int markTime = t.elapsed();
+ t.restart();
+ int usedBefore = getUsedMem();
+ sweep();
+ int usedAfter = getUsedMem();
+ int sweepTime = t.elapsed();
+
+ qDebug() << "========== GC ==========";
+ qDebug() << "Marked object in" << markTime << "ms.";
+ qDebug() << "Sweeped object in" << sweepTime << "ms.";
+ qDebug() << "Allocated" << totalMem << "bytes in" << m_d->heapChunks.size() << "chunks.";
+ qDebug() << "Used memory before GC:" << usedBefore;
+ qDebug() << "Used memory after GC:" << usedAfter;
+ qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
+ qDebug() << "======== End GC ========";
+ }
-// t.restart();
- /*std::size_t freedCount =*/ sweep();
-// std::cerr << "GC: sweep freed " << freedCount
-// << " objects in " << t.elapsed()
-// << "ms" << std::endl;
memset(m_d->allocCount, 0, sizeof(m_d->allocCount));
m_d->totalAlloc = 0;
}
-void MemoryManager::setEnableGC(bool enableGC)
+uint MemoryManager::getUsedMem()
{
- m_d->enableGC = enableGC;
+ uint usedMem = 0;
+ for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) {
+ char *chunkStart = reinterpret_cast<char *>(i->memory.base());
+ char *chunkEnd = chunkStart + i->memory.size() - i->chunkSize;
+ for (char *chunk = chunkStart; chunk <= chunkEnd; chunk += i->chunkSize) {
+ Managed *m = reinterpret_cast<Managed *>(chunk);
+ Q_ASSERT((qintptr) chunk % 16 == 0);
+ if (m->inUse)
+ usedMem += i->chunkSize;
+ }
+ }
+ return usedMem;
}
MemoryManager::~MemoryManager()
@@ -636,6 +520,12 @@ void MemoryManager::dumpStats() const
#endif // DETAILED_MM_STATS
}
+void MemoryManager::registerDeletable(GCDeletable *d)
+{
+ d->next = m_d->deletable;
+ m_d->deletable = d;
+}
+
ExecutionEngine *MemoryManager::engine() const
{
return m_d->engine;
@@ -653,57 +543,6 @@ void MemoryManager::willAllocate(std::size_t size)
#endif // DETAILED_MM_STATS
-void MemoryManager::collectFromStack() const
-{
- quintptr valueOnStack = 0;
-
- if (!m_d->heapChunks.count())
- return;
-
- quintptr *current = (&valueOnStack) + 1;
-// qDebug() << "collectFromStack";// << top << current << &valueOnStack;
-
-#if V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_DEFINED(current, (m_d->stackTop - current)*sizeof(quintptr));
-#endif
-
- char** heapChunkBoundaries = (char**)alloca(m_d->heapChunks.count() * 2 * sizeof(char*));
- char** heapChunkBoundariesEnd = heapChunkBoundaries + 2 * m_d->heapChunks.count();
- int i = 0;
- for (QVector<Data::Chunk>::Iterator it = m_d->heapChunks.begin(), end =
- m_d->heapChunks.end(); it != end; ++it) {
- heapChunkBoundaries[i++] = reinterpret_cast<char*>(it->memory.base()) - 1;
- heapChunkBoundaries[i++] = reinterpret_cast<char*>(it->memory.base()) + it->memory.size() - it->chunkSize;
- }
- Q_ASSERT(i == m_d->heapChunks.count() * 2);
-
- for (; current < m_d->stackTop; ++current) {
- char* genericPtr = reinterpret_cast<char *>(*current);
-
- if (genericPtr < *heapChunkBoundaries || genericPtr > *(heapChunkBoundariesEnd - 1))
- continue;
- int index = std::lower_bound(heapChunkBoundaries, heapChunkBoundariesEnd, genericPtr) - heapChunkBoundaries;
- // An odd index means the pointer is _before_ the end of a heap chunk and therefore valid.
- Q_ASSERT(index >= 0 && index < m_d->heapChunks.count() * 2);
- if (index & 1) {
- int size = m_d->heapChunks.at(index >> 1).chunkSize;
- Managed *m = reinterpret_cast<Managed *>(genericPtr);
-// qDebug() << " inside" << size;
-
- if (((quintptr)m - (quintptr)heapChunkBoundaries[index-1] - 1 ) % size)
- // wrongly aligned value, skip it
- continue;
-
- if (!m->inUse)
- // Skip pointers to already freed objects, they are bogus as well
- continue;
-
-// qDebug() << " marking";
- m->mark(m_d->engine);
- }
- }
-}
-
void MemoryManager::collectFromJSStack() const
{
Value *v = engine()->jsStackBase;
diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h
index 67fc87330b..47020c12f0 100644
--- a/src/qml/jsruntime/qv4mm_p.h
+++ b/src/qml/jsruntime/qv4mm_p.h
@@ -107,11 +107,12 @@ public:
void setGCBlocked(bool blockGC);
void runGC();
- void setEnableGC(bool enableGC);
void setExecutionEngine(ExecutionEngine *engine);
void dumpStats() const;
+ void registerDeletable(GCDeletable *d);
+
protected:
/// expects size to be aligned
// TODO: try to inline
@@ -124,11 +125,11 @@ protected:
#endif // DETAILED_MM_STATS
private:
- void collectFromStack() const;
void collectFromJSStack() const;
void mark();
void sweep(bool lastSweep = false);
- void sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable);
+ void sweep(char *chunkStart, std::size_t chunkSize, size_t size);
+ uint getUsedMem();
protected:
QScopedPointer<Data> m_d;
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index f5c1be767f..c8d360d511 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -48,6 +48,7 @@
#include "qv4mm_p.h"
#include "qv4lookup_p.h"
#include "qv4scopedvalue_p.h"
+#include "qv4memberdata_p.h"
#include <private/qqmljsengine_p.h>
#include <private/qqmljslexer_p.h>
@@ -71,26 +72,24 @@ DEFINE_OBJECT_VTABLE(Object);
Object::Object(ExecutionEngine *engine)
: Managed(engine->objectClass)
- , memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
{
}
Object::Object(InternalClass *ic)
: Managed(ic)
- , memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
{
Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl);
- if (internalClass->size >= memberDataAlloc) {
- memberDataAlloc = internalClass->size;
- memberData = new Value[memberDataAlloc];
+ Q_ASSERT(!memberData.d());
+ if (internalClass->size) {
+ Scope scope(engine());
+ ScopedObject protectThis(scope, this);
+ memberData.ensureIndex(engine(), internalClass->size);
}
}
Object::~Object()
{
- if (memberData != inlineProperties)
- delete [] memberData;
_data = 0;
}
@@ -222,24 +221,14 @@ void Object::markObjects(Managed *that, ExecutionEngine *e)
{
Object *o = static_cast<Object *>(that);
- for (uint i = 0; i < o->internalClass->size; ++i)
- o->memberData[i].mark(e);
+ o->memberData.mark(e);
if (o->arrayData)
o->arrayData->mark(e);
}
void Object::ensureMemberIndex(uint idx)
{
- if (idx >= memberDataAlloc) {
- int newAlloc = qMax((uint)8, 2*memberDataAlloc);
- Value *newMemberData = new Value[newAlloc];
- memcpy(newMemberData, memberData, sizeof(Value)*memberDataAlloc);
- memset(newMemberData + memberDataAlloc, 0, sizeof(Value)*(newAlloc - memberDataAlloc));
- memberDataAlloc = newAlloc;
- if (memberData != inlineProperties)
- delete [] memberData;
- memberData = newMemberData;
- }
+ memberData.ensureIndex(engine(), idx);
}
void Object::insertMember(const StringRef s, const Property &p, PropertyAttributes attributes)
@@ -485,6 +474,8 @@ ReturnedValue Object::getLookup(Managed *m, Lookup *l)
l->getter = Lookup::getter1;
else if (l->level == 2)
l->getter = Lookup::getter2;
+ else
+ l->getter = Lookup::getterFallback;
return v;
} else {
if (l->level == 0)
@@ -493,6 +484,8 @@ ReturnedValue Object::getLookup(Managed *m, Lookup *l)
l->getter = Lookup::getterAccessor1;
else if (l->level == 2)
l->getter = Lookup::getterAccessor2;
+ else
+ l->getter = Lookup::getterFallback;
return v;
}
}
@@ -544,8 +537,11 @@ void Object::setLookup(Managed *m, Lookup *l, const ValueRef value)
}
o = o->prototype();
l->classList[2] = o->internalClass;
- if (!o->prototype())
+ if (!o->prototype()) {
l->setter = Lookup::setterInsert2;
+ return;
+ }
+ l->setter = Lookup::setterGeneric;
}
void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *pd, PropertyAttributes *attrs)
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 89dbde5c82..40f38ee347 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -50,6 +50,7 @@
#include "qv4property_p.h"
#include "qv4internalclass_p.h"
#include "qv4arraydata_p.h"
+#include "qv4memberdata_p.h"
#include <QtCore/QString>
#include <QtCore/QHash>
@@ -107,17 +108,11 @@ struct Q_QML_EXPORT Object: Managed {
enum {
IsObject = true
};
- uint memberDataAlloc;
- Value *memberData;
+ Members memberData;
ArrayData *arrayData;
- enum {
- InlinePropertySize = 4
- };
- Value inlineProperties[InlinePropertySize];
-
- Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData + index); }
+ Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData.data() + index); }
Object(ExecutionEngine *engine);
Object(InternalClass *internalClass);
@@ -415,11 +410,13 @@ inline ArrayObject *value_cast(const Value &v) {
return v.asArrayObject();
}
+#ifndef V4_BOOTSTRAP
template<>
inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v)
{
return v.toObject(e->currentContext())->asReturnedValue();
}
+#endif
struct ObjectRef : public ManagedRef
{
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 1cfd2d88ec..b61be913a6 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -64,6 +64,7 @@
#include <private/qv4jsonobject_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qv4scopedvalue_p.h>
+#include <private/qv4mm_p.h>
#include <QtQml/qjsvalue.h>
#include <QtCore/qjsonarray.h>
@@ -681,9 +682,16 @@ void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value)
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
if (!setQmlProperty(v4->currentContext(), qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) {
- QString error = QLatin1String("Cannot assign to non-existent property \"") +
- name->toQString() + QLatin1Char('\"');
- v4->currentContext()->throwError(error);
+ QQmlData *ddata = QQmlData::get(that->m_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) {
+ QString error = QLatin1String("Cannot assign to non-existent property \"") +
+ name->toQString() + QLatin1Char('\"');
+ v4->currentContext()->throwError(error);
+ } else {
+ QV4::Object::put(m, name, value);
+ }
}
}
@@ -1004,10 +1012,13 @@ namespace {
};
}
-void QObjectWrapper::collectDeletables(Managed *m, GCDeletable **deletable)
+void QObjectWrapper::destroy(Managed *that)
{
- QObjectWrapper *This = static_cast<QObjectWrapper*>(m);
- QPointer<QObject> &object = This->m_object;
+ QObjectWrapper *This = static_cast<QObjectWrapper*>(that);
+ QPointer<QObject> object = This->m_object;
+ ExecutionEngine *engine = This->engine();
+ This->~QObjectWrapper();
+ This = 0;
if (!object)
return;
@@ -1019,12 +1030,11 @@ void QObjectWrapper::collectDeletables(Managed *m, GCDeletable **deletable)
return;
QObjectDeleter *deleter = new QObjectDeleter(object);
- object = 0;
- deleter->next = *deletable;
- *deletable = deleter;
+ engine->memoryManager->registerDeletable(deleter);
}
-DEFINE_MANAGED_VTABLE_WITH_DELETABLES(QObjectWrapper);
+
+DEFINE_OBJECT_VTABLE(QObjectWrapper);
// XXX TODO: Need to review all calls to QQmlEngine *engine() to confirm QObjects work
// correctly in a worker thread
@@ -1315,6 +1325,11 @@ static const QQmlPropertyData * RelatedMethod(QObject *object,
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)
+ return 0;
+
QMetaMethod method = mo->method(current->overrideIndex);
dummy.load(method);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index b11f0af93f..0af01c5614 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -117,11 +117,7 @@ private:
static PropertyAttributes query(const Managed *, StringRef name);
static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes);
static void markObjects(Managed *that, QV4::ExecutionEngine *e);
- static void collectDeletables(Managed *m, GCDeletable **deletable);
- static void destroy(Managed *that)
- {
- static_cast<QObjectWrapper *>(that)->~QObjectWrapper();
- }
+ static void destroy(Managed *that);
static ReturnedValue method_connect(CallContext *ctx);
static ReturnedValue method_disconnect(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index daf85c0f7d..956d1c594e 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -243,7 +243,7 @@ RegExpCtor::RegExpCtor(ExecutionContext *scope)
void RegExpCtor::clearLastMatch()
{
lastMatch = Primitive::nullValue();
- lastInput = engine()->newIdentifier(QString());
+ lastInput = engine()->id_empty;
lastMatchStart = 0;
lastMatchEnd = 0;
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 8b345f53ee..e44d1a07a6 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -41,6 +41,7 @@
#include "qv4global_p.h"
#include "qv4runtime_p.h"
+#ifndef V4_BOOTSTRAP
#include "qv4object_p.h"
#include "qv4jsir_p.h"
#include "qv4objectproto_p.h"
@@ -54,6 +55,7 @@
#include <private/qqmlcontextwrapper_p.h>
#include "qv4qobjectwrapper_p.h"
#include <private/qv8engine_p.h>
+#endif
#include <QtCore/qmath.h>
#include <QtCore/qnumeric.h>
@@ -63,7 +65,7 @@
#include <typeinfo>
#include <stdlib.h>
-#include "../../../3rdparty/double-conversion/double-conversion.h"
+#include "../../3rdparty/double-conversion/double-conversion.h"
QT_BEGIN_NAMESPACE
@@ -207,6 +209,7 @@ void RuntimeCounters::count(const char *func, uint tag1, uint tag2)
#endif // QV4_COUNT_RUNTIME_FUNCTIONS
+#ifndef V4_BOOTSTRAP
void RuntimeHelpers::numberToString(QString *result, double num, int radix)
{
Q_ASSERT(result);
@@ -215,7 +218,7 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
*result = QStringLiteral("NaN");
return;
} else if (qIsInf(num)) {
- *result = QLatin1String(num < 0 ? "-Infinity" : "Infinity");
+ *result = num < 0 ? QStringLiteral("-Infinity") : QStringLiteral("Infinity");
return;
}
@@ -264,7 +267,7 @@ ReturnedValue Runtime::closure(ExecutionContext *ctx, int functionId)
{
QV4::Function *clos = ctx->compilationUnit->runtimeFunctions[functionId];
Q_ASSERT(clos);
- FunctionObject *f = FunctionObject::creatScriptFunction(ctx, clos);
+ FunctionObject *f = FunctionObject::createScriptFunction(ctx, clos);
return f->asReturnedValue();
}
@@ -300,6 +303,9 @@ ReturnedValue Runtime::deleteName(ExecutionContext *ctx, const StringRef name)
QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
{
+ // As nothing in this method can call into the memory manager, avoid using a Scope
+ // for performance reasons
+
FunctionObject *f = right->asFunctionObject();
if (!f)
return ctx->throwTypeError();
@@ -307,23 +313,20 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef
if (f->subtype == FunctionObject::BoundFunction)
f = static_cast<BoundFunction *>(f)->target;
- Scope scope(ctx->engine);
- ScopedObject v(scope, left);
+ Object *v = left->asObject();
if (!v)
return Encode(false);
- Scoped<Object> o(scope, f->protoProperty());
- if (!o) {
- scope.engine->currentContext()->throwTypeError();
- return Encode(false);
- }
+ Object *o = QV4::Value::fromReturnedValue(f->protoProperty()).asObject();
+ if (!o)
+ return ctx->throwTypeError();
while (v) {
v = v->prototype();
- if (! v)
+ if (!v)
break;
- else if (o.getPointer() == v)
+ else if (o == v)
return Encode(true);
}
@@ -414,10 +417,7 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint)
return ctx->throwTypeError();
}
-Bool Runtime::toBoolean(const ValueRef value)
-{
- return value->toBoolean();
-}
+
Returned<Object> *RuntimeHelpers::convertToObject(ExecutionContext *ctx, const ValueRef value)
{
@@ -632,7 +632,7 @@ ReturnedValue Runtime::foreachIterator(ExecutionContext *ctx, const ValueRef in)
Scope scope(ctx);
Scoped<Object> o(scope, (Object *)0);
if (!in->isNullOrUndefined())
- o = in;
+ o = in->toObject(ctx);
Scoped<Object> it(scope, ctx->engine->newForEachIteratorObject(ctx, o));
return it.asReturnedValue();
}
@@ -677,6 +677,8 @@ ReturnedValue Runtime::getActivationProperty(ExecutionContext *ctx, const String
return ctx->getProperty(name);
}
+#endif // V4_BOOTSTRAP
+
uint RuntimeHelpers::equalHelper(const ValueRef x, const ValueRef y)
{
Q_ASSERT(x->type() != y->type() || (x->isManaged() && (x->isString() != y->isString())));
@@ -697,14 +699,20 @@ uint RuntimeHelpers::equalHelper(const ValueRef x, const ValueRef y)
return Runtime::compareEqual(Primitive::fromDouble((double) x->booleanValue()), y);
} else if (y->isBoolean()) {
return Runtime::compareEqual(x, Primitive::fromDouble((double) y->booleanValue()));
- } else if ((x->isNumber() || x->isString()) && y->isObject()) {
- Scope scope(y->objectValue()->engine());
- ScopedValue py(scope, RuntimeHelpers::toPrimitive(y, PREFERREDTYPE_HINT));
- return Runtime::compareEqual(x, py);
- } else if (x->isObject() && (y->isNumber() || y->isString())) {
- Scope scope(x->objectValue()->engine());
- ScopedValue px(scope, RuntimeHelpers::toPrimitive(x, PREFERREDTYPE_HINT));
- return Runtime::compareEqual(px, y);
+ } else {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
+ if ((x->isNumber() || x->isString()) && y->isObject()) {
+ Scope scope(y->objectValue()->engine());
+ ScopedValue py(scope, RuntimeHelpers::toPrimitive(y, PREFERREDTYPE_HINT));
+ return Runtime::compareEqual(x, py);
+ } else if (x->isObject() && (y->isNumber() || y->isString())) {
+ Scope scope(x->objectValue()->engine());
+ ScopedValue px(scope, RuntimeHelpers::toPrimitive(x, PREFERREDTYPE_HINT));
+ return Runtime::compareEqual(px, y);
+ }
+#endif
}
return false;
@@ -732,15 +740,25 @@ QV4::Bool Runtime::compareGreaterThan(const QV4::ValueRef l, const QV4::ValueRef
return l->integerValue() > r->integerValue();
if (l->isNumber() && r->isNumber())
return l->asDouble() > r->asDouble();
- if (l->isString() && r->isString())
+ if (l->isString() && r->isString()) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+ return false;
+#else
return r->stringValue()->compare(l->stringValue());
+#endif
+ }
if (l->isObject() || r->isObject()) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
QV4::ExecutionEngine *e = (l->isObject() ? l->objectValue() : r->objectValue())->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT));
QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT));
return Runtime::compareGreaterThan(pl, pr);
+#endif
}
double dl = RuntimeHelpers::toNumber(l);
@@ -755,15 +773,25 @@ QV4::Bool Runtime::compareLessThan(const QV4::ValueRef l, const QV4::ValueRef r)
return l->integerValue() < r->integerValue();
if (l->isNumber() && r->isNumber())
return l->asDouble() < r->asDouble();
- if (l->isString() && r->isString())
+ if (l->isString() && r->isString()) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+ return false;
+#else
return l->stringValue()->compare(r->stringValue());
+#endif
+ }
if (l->isObject() || r->isObject()) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
QV4::ExecutionEngine *e = (l->isObject() ? l->objectValue() : r->objectValue())->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT));
QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT));
return Runtime::compareLessThan(pl, pr);
+#endif
}
double dl = RuntimeHelpers::toNumber(l);
@@ -778,15 +806,25 @@ QV4::Bool Runtime::compareGreaterEqual(const QV4::ValueRef l, const QV4::ValueRe
return l->integerValue() >= r->integerValue();
if (l->isNumber() && r->isNumber())
return l->asDouble() >= r->asDouble();
- if (l->isString() && r->isString())
+ if (l->isString() && r->isString()) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+ return false;
+#else
return !l->stringValue()->compare(r->stringValue());
+#endif
+ }
if (l->isObject() || r->isObject()) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
QV4::ExecutionEngine *e = (l->isObject() ? l->objectValue() : r->objectValue())->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT));
QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT));
return Runtime::compareGreaterEqual(pl, pr);
+#endif
}
double dl = RuntimeHelpers::toNumber(l);
@@ -801,15 +839,25 @@ QV4::Bool Runtime::compareLessEqual(const QV4::ValueRef l, const QV4::ValueRef r
return l->integerValue() <= r->integerValue();
if (l->isNumber() && r->isNumber())
return l->asDouble() <= r->asDouble();
- if (l->isString() && r->isString())
+ if (l->isString() && r->isString()) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+ return false;
+#else
return !r->stringValue()->compare(l->stringValue());
+#endif
+ }
if (l->isObject() || r->isObject()) {
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
QV4::ExecutionEngine *e = (l->isObject() ? l->objectValue() : r->objectValue())->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT));
QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT));
return Runtime::compareLessEqual(pl, pr);
+#endif
}
double dl = RuntimeHelpers::toNumber(l);
@@ -817,7 +865,7 @@ QV4::Bool Runtime::compareLessEqual(const QV4::ValueRef l, const QV4::ValueRef r
return dl <= dr;
}
-
+#ifndef V4_BOOTSTRAP
ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData)
{
Scope scope(context);
@@ -1144,6 +1192,8 @@ QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionContext *ctx)
return (new (c->engine->memoryManager) ArgumentsObject(c))->asReturnedValue();
}
+#endif // V4_BOOTSTRAP
+
QV4::ReturnedValue Runtime::increment(const QV4::ValueRef value)
{
TRACE1(value);
@@ -1168,6 +1218,8 @@ QV4::ReturnedValue Runtime::decrement(const QV4::ValueRef value)
}
}
+#ifndef V4_BOOTSTRAP
+
QV4::ReturnedValue RuntimeHelpers::toString(QV4::ExecutionContext *ctx, const QV4::ValueRef value)
{
if (value->isString())
@@ -1187,6 +1239,8 @@ QV4::ReturnedValue RuntimeHelpers::toObject(QV4::ExecutionContext *ctx, const QV
return Encode(o);
}
+#endif // V4_BOOTSTRAP
+
ReturnedValue Runtime::toDouble(const ValueRef value)
{
TRACE1(value);
@@ -1217,6 +1271,8 @@ unsigned Runtime::doubleToUInt(const double &d)
return Primitive::toUInt32(d);
}
+#ifndef V4_BOOTSTRAP
+
ReturnedValue Runtime::regexpLiteral(ExecutionContext *ctx, int id)
{
return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
@@ -1230,6 +1286,8 @@ ReturnedValue Runtime::getQmlIdArray(NoThrowContext *ctx)
ReturnedValue Runtime::getQmlContextObject(NoThrowContext *ctx)
{
QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
+ if (!context)
+ return Encode::undefined();
return QObjectWrapper::wrap(ctx->engine, context->contextObject);
}
@@ -1277,6 +1335,8 @@ void Runtime::setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object
ReturnedValue Runtime::getQmlImportedScripts(NoThrowContext *ctx)
{
QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
+ if (!context)
+ return Encode::undefined();
return context->importedScripts.value();
}
@@ -1297,6 +1357,8 @@ void Runtime::convertThisToObject(ExecutionContext *ctx)
}
}
+#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 4e28441e62..0979105680 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -103,7 +103,7 @@ struct NoThrowContext : public ExecutionContext
{
};
-struct Q_QML_EXPORT Runtime {
+struct Q_QML_PRIVATE_EXPORT Runtime {
// call
static ReturnedValue callGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData);
static ReturnedValue callActivationProperty(ExecutionContext *, const StringRef name, CallDataRef callData);
@@ -232,7 +232,7 @@ struct Q_QML_EXPORT Runtime {
static void setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value);
};
-struct Q_QML_EXPORT RuntimeHelpers {
+struct Q_QML_PRIVATE_EXPORT RuntimeHelpers {
static ReturnedValue objectDefaultValue(Object *object, int typeHint);
static ReturnedValue toPrimitive(const ValueRef value, int typeHint);
@@ -255,6 +255,7 @@ struct Q_QML_EXPORT RuntimeHelpers {
// type conversion and testing
+#ifndef V4_BOOTSTRAP
inline ReturnedValue RuntimeHelpers::toPrimitive(const ValueRef value, int typeHint)
{
Object *o = value->asObject();
@@ -262,6 +263,7 @@ inline ReturnedValue RuntimeHelpers::toPrimitive(const ValueRef value, int typeH
return value.asReturnedValue();
return RuntimeHelpers::objectDefaultValue(o, typeHint);
}
+#endif
inline double RuntimeHelpers::toNumber(const ValueRef value)
{
@@ -338,6 +340,7 @@ inline ReturnedValue Runtime::bitAnd(const ValueRef left, const ValueRef right)
return Encode(lval & rval);
}
+#ifndef V4_BOOTSTRAP
inline ReturnedValue Runtime::add(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
{
TRACE2(left, right);
@@ -349,6 +352,7 @@ inline ReturnedValue Runtime::add(ExecutionContext *ctx, const ValueRef left, co
return RuntimeHelpers::addHelper(ctx, left, right);
}
+#endif // V4_BOOTSTRAP
inline ReturnedValue Runtime::sub(const ValueRef left, const ValueRef right)
{
@@ -461,6 +465,24 @@ inline ReturnedValue Runtime::lessEqual(const ValueRef left, const ValueRef righ
return Encode(r);
}
+inline Bool Runtime::compareEqual(const ValueRef left, const ValueRef right)
+{
+ TRACE2(left, right);
+
+ if (left->rawValue() == right->rawValue())
+ // NaN != NaN
+ return !left->isNaN();
+
+ if (left->type() == right->type()) {
+ if (!left->isManaged())
+ return false;
+ if (left->isString() == right->isString())
+ return left->managed()->isEqualTo(right->managed());
+ }
+
+ return RuntimeHelpers::equalHelper(left, right);
+}
+
inline ReturnedValue Runtime::equal(const ValueRef left, const ValueRef right)
{
TRACE2(left, right);
@@ -493,24 +515,6 @@ inline ReturnedValue Runtime::strictNotEqual(const ValueRef left, const ValueRef
return Encode(r);
}
-inline Bool Runtime::compareEqual(const ValueRef left, const ValueRef right)
-{
- TRACE2(left, right);
-
- if (left->rawValue() == right->rawValue())
- // NaN != NaN
- return !left->isNaN();
-
- if (left->type() == right->type()) {
- if (!left->isManaged())
- return false;
- if (left->isString() == right->isString())
- return left->managed()->isEqualTo(right->managed());
- }
-
- return RuntimeHelpers::equalHelper(left, right);
-}
-
inline Bool Runtime::compareNotEqual(const ValueRef left, const ValueRef right)
{
TRACE2(left, right);
@@ -532,6 +536,7 @@ inline Bool Runtime::compareStrictNotEqual(const ValueRef left, const ValueRef r
return ! RuntimeHelpers::strictEqual(left, right);
}
+#ifndef V4_BOOTSTRAP
inline Bool Runtime::compareInstanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
{
TRACE2(left, right);
@@ -550,6 +555,13 @@ inline uint Runtime::compareIn(ExecutionContext *ctx, const ValueRef left, const
return v->booleanValue();
}
+#endif // V4_BOOTSTRAP
+
+inline Bool Runtime::toBoolean(const ValueRef value)
+{
+ return value->toBoolean();
+}
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index ebcc8bbefa..36f61a1df5 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -54,6 +54,7 @@
#include <private/qqmlengine_p.h>
#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
+#include <private/qqmlcontextwrapper_p.h>
#include <QtCore/QDebug>
#include <QtCore/QString>
@@ -61,7 +62,7 @@
using namespace QV4;
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml)
- : FunctionObject(scope, scope->engine->id_eval)
+ : FunctionObject(scope, scope->engine->id_eval, /*createProto = */ false)
, qml(qml)
, qmlContext(0)
{
@@ -69,8 +70,9 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec
setVTable(staticVTable());
function = f;
- function->compilationUnit->ref();
- needsActivation = function->needsActivation();
+ if (function)
+ function->compilationUnit->ref();
+ needsActivation = function ? function->needsActivation() : false;
Scope s(scope);
ScopedValue protectThis(s, this);
@@ -82,7 +84,7 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec
}
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
- : FunctionObject(scope, scope->engine->id_eval)
+ : FunctionObject(scope, scope->engine->id_eval, /*createProto = */ false)
, qml(qml)
, qmlContext(0)
{
@@ -108,7 +110,8 @@ ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
Scope scope(engine);
QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
- Q_ASSERT(This->function);
+ if (!This->function)
+ return QV4::Encode::undefined();
CallContext *ctx = This->qmlContext;
std::fill(ctx->locals, ctx->locals + ctx->function->varCount(), Primitive::undefinedValue());
@@ -129,6 +132,38 @@ void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e)
wrapper->qmlContext->mark(e);
}
+static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex)
+{
+ QV4::CallContext *signalEmittingContext = ctx->parent->asCallContext();
+ Q_ASSERT(signalEmittingContext);
+ return signalEmittingContext->argument(parameterIndex);
+}
+
+Returned<FunctionObject> *QmlBindingWrapper::createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error)
+{
+ ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine);
+ QV4::Scope valueScope(engine);
+ QV4::ScopedObject qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine->v8Engine, qmlContext, scopeObject));
+ QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (engine->memoryManager) QV4::QmlBindingWrapper(engine->rootContext, qmlScopeObject));
+
+ if (!signalParameters.isEmpty()) {
+ if (error)
+ QQmlPropertyCache::signalParameterStringForJS(qmlContext->engine, signalParameters, error);
+ QV4::ScopedProperty p(valueScope);
+ QV4::ScopedString s(valueScope);
+ int index = 0;
+ foreach (const QByteArray &param, signalParameters) {
+ p->setGetter(new (engine->memoryManager) QV4::IndexedBuiltinFunction(wrapper->context(), index++, signalParameterGetter));
+ p->setSetter(0);
+ s = engine->newString(QString::fromUtf8(param));
+ qmlScopeObject->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
+ }
+ }
+
+ QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapper->context(), runtimeFunction));
+ return function->asReturned<FunctionObject>();
+}
+
DEFINE_OBJECT_VTABLE(QmlBindingWrapper);
struct CompilationUnitHolder : public QV4::Object
@@ -307,13 +342,11 @@ Function *Script::function()
return vmFunction;
}
-CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors)
+QV4::CompiledData::CompilationUnit *Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors)
{
using namespace QQmlJS;
using namespace QQmlJS::AST;
- IR::Module module(engine->debugger != 0);
-
QQmlJS::Engine ee;
QQmlJS::Lexer lexer(&ee);
lexer.setCode(source, /*line*/1, /*qml mode*/true);
@@ -351,18 +384,17 @@ CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const
}
QQmlJS::Codegen cg(/*strict mode*/false);
- cg.generateFromProgram(url.toString(), source, program, &module, QQmlJS::Codegen::EvalCode);
- errors = cg.errors();
+ cg.generateFromProgram(url.toString(), source, program, module, QQmlJS::Codegen::EvalCode);
+ errors = cg.qmlErrors();
if (!errors.isEmpty()) {
if (reportedErrors)
- *reportedErrors << cg.errors();
+ *reportedErrors << errors;
return 0;
}
- Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, &module, &jsGenerator));
+ QScopedPointer<EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, module, unitGenerator));
isel->setUseFastLookups(false);
- return isel->compile();
+ return isel->compile(/*generate unit data*/false);
}
ReturnedValue Script::qmlBinding()
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 8afdb6126f..de582f9674 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -49,6 +49,8 @@
QT_BEGIN_NAMESPACE
+class QQmlContextData;
+
namespace QV4 {
struct ExecutionContext;
@@ -65,6 +67,8 @@ struct QmlBindingWrapper : FunctionObject {
CallContext *context() const { return qmlContext; }
+ static Returned<FunctionObject> *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0);
+
private:
Object *qml;
CallContext *qmlContext;
@@ -100,7 +104,7 @@ struct Q_QML_EXPORT Script {
Function *function();
- static CompiledData::CompilationUnit *precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0);
+ static QV4::CompiledData::CompilationUnit *precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject);
};
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 1c915914b5..d9aa881f21 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -40,10 +40,13 @@
****************************************************************************/
#include "qv4string_p.h"
+#include "qv4value_inl_p.h"
+#ifndef V4_BOOTSTRAP
#include "qv4identifiertable_p.h"
#include "qv4runtime_p.h"
#include "qv4objectproto_p.h"
#include "qv4stringobject_p.h"
+#endif
#include <QtCore/QHash>
using namespace QV4;
@@ -74,6 +77,8 @@ static uint toArrayIndex(const QChar *ch, const QChar *end, bool *ok)
return i;
}
+#ifndef V4_BOOTSTRAP
+
static uint toArrayIndex(const char *ch, const char *end, bool *ok)
{
*ok = false;
@@ -106,7 +111,6 @@ const ObjectVTable String::static_vtbl =
DEFINE_MANAGED_VTABLE_INT(String),
0,
0,
- 0 /*collectDeletables*/,
get,
getIndexed,
put,
@@ -408,13 +412,16 @@ uint String::createHashValue(const char *ch, int length)
return h;
}
+uint String::getLength(const Managed *m)
+{
+ return static_cast<const String *>(m)->length();
+}
+
+#endif // V4_BOOTSTRAP
+
uint String::toArrayIndex(const QString &str)
{
bool ok;
return ::toArrayIndex(str.constData(), str.constData() + str.length(), &ok);
}
-uint String::getLength(const Managed *m)
-{
- return static_cast<const String *>(m)->length();
-}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index ade64d1352..ed2a4e3646 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -51,7 +51,8 @@ namespace QV4 {
struct ExecutionEngine;
struct Identifier;
-struct Q_QML_EXPORT String : public Managed {
+struct Q_QML_PRIVATE_EXPORT String : public Managed {
+#ifndef V4_BOOTSTRAP
// ### FIXME: Should this be a V4_OBJECT
V4_OBJECT
Q_MANAGED_TYPE(String)
@@ -143,8 +144,6 @@ struct Q_QML_EXPORT String : public Managed {
return len;
}
- static uint toArrayIndex(const QString &str);
-
union {
mutable QStringData *_text;
mutable String *left;
@@ -174,8 +173,13 @@ protected:
private:
QChar *recursiveAppend(QChar *ch) const;
+#endif
+
+public:
+ static uint toArrayIndex(const QString &str);
};
+#ifndef V4_BOOTSTRAP
template<>
inline String *value_cast(const Value &v) {
return v.asString();
@@ -188,6 +192,7 @@ inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v)
}
DEFINE_REF(String, Managed);
+#endif
}
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index f26c77e5bf..7c38ae4f01 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -450,7 +450,7 @@ static void appendReplacementString(QString *result, const QString &input, const
uint substStart = JSC::Yarr::offsetNoMatch;
uint substEnd = JSC::Yarr::offsetNoMatch;
if (ch == '$') {
- *result += QLatin1Char(ch);
+ *result += QChar(ch);
continue;
} else if (ch == '&') {
substStart = matchOffsets[0];
@@ -463,7 +463,8 @@ static void appendReplacementString(QString *result, const QString &input, const
substEnd = input.length();
} else if (ch >= '1' && ch <= '9') {
uint capture = ch - '0';
- if (capture > 0 && capture < static_cast<uint>(captureCount)) {
+ Q_ASSERT(capture > 0);
+ if (capture < static_cast<uint>(captureCount)) {
substStart = matchOffsets[capture * 2];
substEnd = matchOffsets[capture * 2 + 1];
}
@@ -498,8 +499,8 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
int numCaptures = 0;
int numStringMatches = 0;
- uint allocatedMatchOffsets = 32;
- uint _matchOffsets[32];
+ uint allocatedMatchOffsets = 64;
+ uint _matchOffsets[64];
uint *matchOffsets = _matchOffsets;
uint nMatchOffsets = 0;
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index fa16662b46..e9246f7a14 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -39,9 +39,11 @@
**
****************************************************************************/
#include <qv4engine_p.h>
+#ifndef V4_BOOTSTRAP
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
#include "qv4mm_p.h"
+#endif
#include <wtf/MathExtras.h>
@@ -87,6 +89,9 @@ double Value::toNumberImpl() const
case QV4::Value::Undefined_Type:
return std::numeric_limits<double>::quiet_NaN();
case QV4::Value::Managed_Type:
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
if (isString())
return RuntimeHelpers::stringToNumber(stringValue()->toQString());
{
@@ -95,6 +100,7 @@ double Value::toNumberImpl() const
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ValueRef::fromRawValue(this), NUMBER_HINT));
return prim->toNumber();
}
+#endif
case QV4::Value::Null_Type:
case QV4::Value::Boolean_Type:
case QV4::Value::Integer_Type:
@@ -104,6 +110,7 @@ double Value::toNumberImpl() const
}
}
+#ifndef V4_BOOTSTRAP
QString Value::toQStringNoThrow() const
{
switch (type()) {
@@ -192,6 +199,7 @@ QString Value::toQString() const
}
} // switch
}
+#endif // V4_BOOTSTRAP
bool Value::sameValue(Value other) const {
if (val == other.val)
@@ -263,6 +271,7 @@ double Primitive::toInteger(double number)
return std::signbit(number) ? -v : v;
}
+#ifndef V4_BOOTSTRAP
String *Value::toString(ExecutionEngine *e) const
{
return toString(e->currentContext());
@@ -282,3 +291,4 @@ Object *Value::toObject(ExecutionContext *ctx) const
return RuntimeHelpers::convertToObject(ctx, ValueRef::fromRawValue(this))->getPointer();
}
+#endif // V4_BOOTSTRAP
diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h
index 35508f442a..1fe9e1c165 100644
--- a/src/qml/jsruntime/qv4value_inl_p.h
+++ b/src/qml/jsruntime/qv4value_inl_p.h
@@ -180,14 +180,19 @@ inline bool Value::toBoolean() const
case Value::Integer_Type:
return (bool)int_32;
case Value::Managed_Type:
+#ifdef V4_BOOTSTRAP
+ Q_UNIMPLEMENTED();
+#else
if (isString())
return stringValue()->toQString().length() > 0;
+#endif
return true;
default: // double
return doubleValue() && !std::isnan(doubleValue());
}
}
+#ifndef V4_BOOTSTRAP
inline uint Value::asArrayIndex() const
{
#if QT_POINTER_SIZE == 8
@@ -278,6 +283,8 @@ inline ErrorObject *Value::asErrorObject() const
template<typename T>
inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; }
+#endif
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 27c81d59a5..29cb8b42ed 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -64,7 +64,7 @@ struct Returned : private T
using T::asReturnedValue;
};
-struct Q_QML_EXPORT Value
+struct Q_QML_PRIVATE_EXPORT Value
{
/*
We use two different ways of encoding JS values. One for 32bit and one for 64bit systems.
@@ -119,20 +119,21 @@ struct Q_QML_EXPORT Value
#if QT_POINTER_SIZE == 4
enum Masks {
- NaN_Mask = 0x7ff80000,
- NotDouble_Mask = 0x7ffc0000,
- Type_Mask = 0xffff8000,
- Immediate_Mask = NotDouble_Mask | 0x00008000,
- IsNullOrUndefined_Mask = Immediate_Mask | 0x20000,
+ SilentNaNBit = 0x00040000,
+ NaN_Mask = 0x7ff80000,
+ NotDouble_Mask = 0x7ffa0000,
+ Type_Mask = 0xffffc000,
+ Immediate_Mask = NotDouble_Mask | 0x00004000 | SilentNaNBit,
+ IsNullOrUndefined_Mask = Immediate_Mask | 0x08000,
Tag_Shift = 32
};
enum ValueType {
Undefined_Type = Immediate_Mask | 0x00000,
- Null_Type = Immediate_Mask | 0x10000,
- Boolean_Type = Immediate_Mask | 0x20000,
- Integer_Type = Immediate_Mask | 0x30000,
- Managed_Type = NotDouble_Mask | 0x00000,
- Empty_Type = NotDouble_Mask | 0x30000
+ Null_Type = Immediate_Mask | 0x10000,
+ Boolean_Type = Immediate_Mask | 0x08000,
+ Integer_Type = Immediate_Mask | 0x18000,
+ Managed_Type = NotDouble_Mask | 0x00000 | SilentNaNBit,
+ Empty_Type = NotDouble_Mask | 0x18000 | SilentNaNBit
};
enum ImmediateFlags {
@@ -241,8 +242,8 @@ struct Q_QML_EXPORT Value
static inline bool bothDouble(Value a, Value b) {
return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask;
}
- double doubleValue() const { return dbl; }
- void setDouble(double d) { dbl = d; }
+ double doubleValue() const { Q_ASSERT(isDouble()); return dbl; }
+ void setDouble(double d) { dbl = d; Q_ASSERT(isDouble()); }
bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
#endif
inline bool isString() const;
@@ -372,7 +373,7 @@ inline String *Value::asString() const
return 0;
}
-struct Q_QML_EXPORT Primitive : public Value
+struct Q_QML_PRIVATE_EXPORT Primitive : public Value
{
inline static Primitive emptyValue();
static inline Primitive fromBoolean(bool b);
diff --git a/src/qml/parser/qqmljsglobal_p.h b/src/qml/parser/qqmljsglobal_p.h
index c53e12ea56..1cf63820c3 100644
--- a/src/qml/parser/qqmljsglobal_p.h
+++ b/src/qml/parser/qqmljsglobal_p.h
@@ -62,9 +62,9 @@
// QmlDevTools is a static library
# define QML_PARSER_EXPORT
# elif defined(QT_BUILD_QML_LIB)
-# define QML_PARSER_EXPORT Q_AUTOTEST_EXPORT
+# define QML_PARSER_EXPORT Q_DECL_EXPORT
# else
-# define QML_PARSER_EXPORT
+# define QML_PARSER_EXPORT Q_DECL_IMPORT
# endif
#endif // QT_CREATOR
diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h
index 29103930ad..1809f500e3 100644
--- a/src/qml/parser/qqmljsmemorypool_p.h
+++ b/src/qml/parser/qqmljsmemorypool_p.h
@@ -65,6 +65,8 @@ QT_QML_BEGIN_NAMESPACE
namespace QQmlJS {
+class Managed;
+
class QML_PARSER_EXPORT MemoryPool : public QSharedData
{
MemoryPool(const MemoryPool &other);
@@ -110,6 +112,28 @@ public:
template <typename _Tp> _Tp *New() { return new (this->allocate(sizeof(_Tp))) _Tp(); }
+ template <typename PoolContentType, typename Visitor>
+ void visitManagedPool(Visitor &visitor)
+ {
+ for (int i = 0; i <= _blockCount; ++i) {
+ char *p = _blocks[i];
+ char *end = p + BLOCK_SIZE;
+ if (i == _blockCount) {
+ Q_ASSERT(_ptr <= end);
+ end = _ptr;
+ }
+
+ Q_ASSERT(p <= end);
+
+ const qptrdiff increment = (sizeof(PoolContentType) + 7) & ~7;
+
+ while (p + increment <= end) {
+ visitor(reinterpret_cast<PoolContentType*>(p));
+ p += increment;
+ }
+ }
+ }
+
private:
void *allocate_helper(size_t size)
{
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index c49463c913..700e5c3324 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -127,6 +127,7 @@ QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q)
: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false),
m_mainThreadWaiting(false), mainSync(0), m_mainObject(this)
{
+ setObjectName(QStringLiteral("QQmlThread"));
}
bool QQmlThreadPrivate::event(QEvent *e)
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 33d8be37d1..013f757c90 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -1,4 +1,12 @@
SOURCES += \
+ $$PWD/qqmldirparser.cpp \
+
+HEADERS += \
+ $$PWD/qqmldirparser_p.h \
+
+!qmldevtools_build {
+
+SOURCES += \
$$PWD/qqmlopenmetaobject.cpp \
$$PWD/qqmlvmemetaobject.cpp \
$$PWD/qqmlengine.cpp \
@@ -20,7 +28,6 @@ SOURCES += \
$$PWD/qqmltypeloader.cpp \
$$PWD/qqmlinfo.cpp \
$$PWD/qqmlerror.cpp \
- $$PWD/qqmlscript.cpp \
$$PWD/qqmlvaluetype.cpp \
$$PWD/qqmlaccessors.cpp \
$$PWD/qqmlxmlhttprequest.cpp \
@@ -32,7 +39,6 @@ SOURCES += \
$$PWD/qqmltypenamecache.cpp \
$$PWD/qqmlscriptstring.cpp \
$$PWD/qqmlnetworkaccessmanagerfactory.cpp \
- $$PWD/qqmldirparser.cpp \
$$PWD/qqmlextensionplugin.cpp \
$$PWD/qqmlimport.cpp \
$$PWD/qqmllist.cpp \
@@ -91,7 +97,6 @@ HEADERS += \
$$PWD/qqmllist_p.h \
$$PWD/qqmldata_p.h \
$$PWD/qqmlerror.h \
- $$PWD/qqmlscript_p.h \
$$PWD/qqmlvaluetype_p.h \
$$PWD/qqmlaccessors_p.h \
$$PWD/qqmlxmlhttprequest_p.h \
@@ -104,7 +109,6 @@ HEADERS += \
$$PWD/qqmlscriptstring.h \
$$PWD/qqmlguard_p.h \
$$PWD/qqmlnetworkaccessmanagerfactory.h \
- $$PWD/qqmldirparser_p.h \
$$PWD/qqmlextensioninterface.h \
$$PWD/qqmlimport_p.h \
$$PWD/qqmlextensionplugin.h \
@@ -135,3 +139,5 @@ HEADERS += \
include(ftw/ftw.pri)
include(v8/v8.pri)
+
+}
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 6479aedd1b..721f2cc5a8 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -91,13 +91,13 @@ class QQmlPropertyValueInterceptor;
const char *className = T::staticMetaObject.className(); \
const int nameLen = int(strlen(className)); \
QVarLengthArray<char,48> pointerName(nameLen+2); \
- memcpy(pointerName.data(), className, nameLen); \
+ memcpy(pointerName.data(), className, size_t(nameLen)); \
pointerName[nameLen] = '*'; \
pointerName[nameLen+1] = '\0'; \
const int listLen = int(strlen("QQmlListProperty<")); \
QVarLengthArray<char,64> listName(listLen + nameLen + 2); \
- memcpy(listName.data(), "QQmlListProperty<", listLen); \
- memcpy(listName.data()+listLen, className, nameLen); \
+ memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \
+ memcpy(listName.data()+listLen, className, size_t(nameLen)); \
listName[listLen+nameLen] = '>'; \
listName[listLen+nameLen+1] = '\0';
diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h
index 7354f9af1e..0bc0b6f199 100644
--- a/src/qml/qml/qqmlabstractbinding_p.h
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -149,7 +149,6 @@ private:
friend class QQmlComponentPrivate;
friend class QQmlValueTypeProxyBinding;
friend class QQmlPropertyPrivate;
- friend class QQmlVME;
friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>;
friend class QV4Bindings;
friend class QQmlObjectCreator;
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp
index 127dad86ce..3aea9c83cc 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.cpp
+++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp
@@ -84,8 +84,8 @@
/*!
\fn QUrl QQmlAbstractUrlInterceptor::intercept(const QUrl& url, DataType type)
- A pure virtual function where you can intercept the url. The returned value is taken as the
- new value for the url. The type of url being intercepted is given by the type variable.
+ A pure virtual function where you can intercept the \a url. The returned value is taken as the
+ new value for the url. The type of url being intercepted is given by the \a type variable.
Your implementation of this function must be thread-safe, as it can be called from multiple threads
at the same time.
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 295461ba26..571d78312e 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -88,11 +88,8 @@ QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt)
if (QQmlCompiledData *cdata = typeData->compiledData()) {
QV4::ExecutionEngine *v4 = engine->v4engine();
QV4::Scope valueScope(v4);
- QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(v4->v8Engine, ctxtdata, obj));
- QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject));
- QV4::ExecutionContext *qmlContext = wrapper->context();
QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]];
- QV4::ScopedValue function(valueScope, QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction));
+ QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, obj, runtimeFunction));
rv = new QQmlBinding(function, obj, ctxtdata);
}
@@ -128,31 +125,33 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
return;
QString url;
- QString code;
-
- int id = scriptPrivate->bindingId;
- if (id >= 0) {
- QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
- QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
- if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
- QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
- Q_ASSERT(typeData);
-
- if (QQmlCompiledData *cdata = typeData->compiledData()) {
- code = cdata->primitives.at(id);
- url = cdata->name;
- }
+ QV4::Function *runtimeFunction = 0;
+
+ QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
+ if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
+ QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
+ Q_ASSERT(typeData);
- typeData->release();
+ if (QQmlCompiledData *cdata = typeData->compiledData()) {
+ url = cdata->name;
+ if (scriptPrivate->bindingId != QQmlBinding::Invalid)
+ runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
}
- } else
- code = scriptPrivate->script;
+
+ typeData->release();
+ }
setNotifyOnValueChanged(true);
QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
setScopeObject(obj ? obj : scriptPrivate->scope);
- v4function = qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber);
+ if (runtimeFunction) {
+ v4function = QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction);
+ } else {
+ QString code = scriptPrivate->script;
+ v4function = qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber);
+ }
}
QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt)
@@ -215,7 +214,7 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
QV4::ScopedFunctionObject f(scope, v4function.value());
Q_ASSERT(f);
if (f->bindingKeyFlag) {
- QQmlSourceLocation loc = f->as<QQmlBindingFunction>()->bindingLocation;
+ QQmlSourceLocation loc = f->as<QV4::QQmlBindingFunction>()->bindingLocation;
url = loc.sourceFile;
lineNumber = loc.line;
columnNumber = loc.column;
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 6237459aac..876f367097 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -52,6 +52,7 @@
#include "qqmlglobal_p.h"
#include <private/qqmlprofiler_p.h>
#include <private/qv4debugservice_p.h>
+#include <private/qqmlcompiler_p.h>
#include "qqmlinfo.h"
#include <private/qv4value_inl_p.h>
@@ -59,6 +60,7 @@
#include <QtCore/qstringbuilder.h>
#include <QtCore/qdebug.h>
+
QT_BEGIN_NAMESPACE
static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = {
@@ -105,6 +107,28 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
init(ctxt, scope);
}
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction)
+ : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
+ m_target(target),
+ m_index(index),
+ m_extra(0)
+{
+ setExpressionFunctionValid(true);
+ setInvalidParameterName(false);
+
+ // It's important to call init first, because m_index gets remapped in case of cloned signals.
+ init(ctxt, scope);
+
+ QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
+ QString error;
+ m_v8function = QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error);
+ if (!error.isEmpty()) {
+ qmlInfo(scopeObject()) << error;
+ setInvalidParameterName(true);
+ } else
+ setInvalidParameterName(false);
+}
+
void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope)
{
setNotifyOnValueChanged(false);
@@ -221,7 +245,7 @@ void QQmlBoundSignalExpression::evaluate(void **a)
m_extra->m_parameterString.clear();
m_v8function = evalFunction(context(), scopeObject(), expression,
- m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_v8qmlscope);
+ m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope);
if (m_v8function.isNullOrUndefined()) {
ep->dereferenceScarceResources();
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index 6df6da4214..43ff71f682 100644
--- a/src/qml/qml/qqmlboundsignal_p.h
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -78,6 +78,8 @@ public:
QQmlBoundSignalExpression(QObject *target, int index,
QQmlContextData *ctxt, QObject *scope, const QV4::ValueRef &function);
+ QQmlBoundSignalExpression(QObject *target, int index,
+ QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction);
// "inherited" from QQmlJavaScriptExpression.
static QString expressionIdentifier(QQmlJavaScriptExpression *);
@@ -104,7 +106,6 @@ private:
bool invalidParameterName() const { return m_extra.flag2(); }
void setInvalidParameterName(bool v) { m_extra.setFlag2Value(v); }
- QV4::PersistentValue m_v8qmlscope;
QV4::PersistentValue m_v8function;
QObject *m_target;
@@ -119,6 +120,7 @@ private:
QString m_parameterString;
QString m_expression;
QQmlSourceLocation m_sourceLocation;
+ QV4::PersistentValue m_v8qmlscope;
};
// We store some flag bits in the following flag pointers.
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index 59c56bf513..a352e5ad1d 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -61,8 +61,6 @@ QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
rootPropertyCache(0), compilationUnit(0), qmlUnit(0), totalBindingsCount(0), totalParserStatusCount(0)
{
Q_ASSERT(engine);
-
- bytecode.reserve(1024);
}
void QQmlCompiledData::destroy()
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 98d308aa5c..f3b6f621ce 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -55,13 +55,11 @@
#include "qqml.h"
#include "qqmlerror.h"
-#include "qqmlscript_p.h"
#include "qqmlengine_p.h"
#include <private/qbitfield_p.h>
#include "qqmlpropertycache_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmltypeloader_p.h"
-#include <private/qqmlcodegenerator_p.h>
#include "private/qv4identifier_p.h"
#include <private/qqmljsastfwd_p.h>
#include "qqmlcustomparser_p.h"
@@ -129,15 +127,10 @@ public:
QHash<int, TypeReference*> resolvedTypes;
QQmlPropertyCache *rootPropertyCache;
- QList<QString> primitives;
- QVector<QByteArray> datas;
- QByteArray bytecode;
+ QVector<QByteArray> metaObjects;
QVector<QQmlPropertyCache *> propertyCaches;
- QList<QVector<QQmlContextData::ObjectIdMapping> > contextCaches;
QList<QQmlScriptData *> scripts;
- QList<QUrl> urls;
- // --- new compiler
QV4::CompiledData::CompilationUnit *compilationUnit;
QV4::CompiledData::QmlUnit *qmlUnit;
// index in first hash is component index, hash inside maps from object index in that scope to integer id
@@ -156,11 +149,14 @@ public:
int totalObjectCount; // Number of objects explicitly instantiated
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
- bool isCompositeType() const { return !datas.at(qmlUnit->indexOfRootObject).isEmpty(); }
+ bool isCompositeType() const { return !metaObjects.at(qmlUnit->indexOfRootObject).isEmpty(); }
bool isInitialized() const { return hasEngine(); }
void initialize(QQmlEngine *);
+ QV4::Function *functionForBindingId(int bindingId) const
+ { return compilationUnit->runtimeFunctions[customParserBindings[bindingId]]; }
+
protected:
virtual void destroy(); // From QQmlRefCount
virtual void clear(); // From QQmlCleanup
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 77d02e071f..39a7d8905d 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -51,7 +51,6 @@
#include "qqmlengine.h"
#include "qqmlbinding_p.h"
#include "qqmlglobal_p.h"
-#include "qqmlscript_p.h"
#include <private/qqmlenginedebugservice_p.h>
#include "qqmlincubator.h"
#include "qqmlincubator_p.h"
@@ -264,14 +263,14 @@ V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
*/
/*!
- \qmlattachedsignal Component::onCompleted()
+ \qmlattachedsignal Component::completed()
Emitted after component "startup" has completed. This can be used to
execute script code at startup, once the full QML environment has been
established.
- The \c {Component::onCompleted} attached property can be declared on
- any object. The order of running the \c onCompleted scripts is
+ The corresponding handler is \c onCompleted. It can be declared on
+ any object. The order of running the \c onCompleted handlers is
undefined.
\qml
@@ -285,16 +284,16 @@ V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
*/
/*!
- \qmlattachedsignal Component::onDestruction()
+ \qmlattachedsignal Component::destruction()
Emitted as the component begins destruction. This can be used to undo
- work done in the onCompleted signal, or other imperative code in your
- application.
+ work done in response to the \l {completed}{completed()} signal, or other
+ imperative code in your application.
- The \c {Component::onDestruction} attached property can be declared on
+ The corresponding handler is \c onDestruction. It can be declared on
any object. However, it applies to the destruction of the component as
a whole, and not the destruction of the specific object. The order of
- running the \c onDestruction scripts is undefined.
+ running the \c onDestruction handlers is undefined.
\qml
Rectangle {
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index 4aa0daf47e..9be1990adc 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -127,7 +127,6 @@ private:
QQmlComponent(QQmlEngine *, QQmlCompiledData *, int, QObject *parent);
Q_DISABLE_COPY(QQmlComponent)
- friend class QQmlVME;
friend class QQmlTypeData;
friend class QQmlObjectCreator;
};
diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h
index ae416dcb1c..4fb77a1a4d 100644
--- a/src/qml/qml/qqmlcomponentattached_p.h
+++ b/src/qml/qml/qqmlcomponentattached_p.h
@@ -73,7 +73,6 @@ Q_SIGNALS:
void destruction();
private:
- friend class QQmlVME;
friend class QQmlContextData;
};
diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h
index e191807cf4..828ae8c523 100644
--- a/src/qml/qml/qqmlcontext.h
+++ b/src/qml/qml/qqmlcontext.h
@@ -88,7 +88,6 @@ public:
QUrl baseUrl() const;
private:
- friend class QQmlVME;
friend class QQmlEngine;
friend class QQmlEnginePrivate;
friend class QQmlExpression;
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index 464bee82c0..2d544b1633 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -59,7 +59,6 @@
#include "qqmltypenamecache_p.h"
#include "qqmlnotifier_p.h"
#include "qqmllist.h"
-#include "qqmlscript_p.h"
#include <QtCore/qhash.h>
#include <QtQml/qjsvalue.h>
@@ -106,7 +105,6 @@ public:
static QObject *context_at(QQmlListProperty<QObject> *, int);
};
-class QQmlVME;
class QQmlComponentAttached;
class QQmlGuardedContextData;
class Q_QML_PRIVATE_EXPORT QQmlContextData
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index e72e90296f..a5574b706a 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -94,7 +94,7 @@ ReturnedValue QmlContextWrapper::urlScope(QV8Engine *v8, const QUrl &url)
context->isInternal = true;
context->isJSContext = true;
- Scoped<QmlContextWrapper> w(scope, new (v4->memoryManager) QmlContextWrapper(v8, context, 0));
+ Scoped<QmlContextWrapper> w(scope, new (v4->memoryManager) QmlContextWrapper(v8, context, 0, true));
w->isNullWrapper = true;
return w.asReturnedValue();
}
@@ -387,6 +387,7 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C
capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings);
}
+ Q_ASSERT(qmlContext->contextObject);
const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
for (int i = 0; i < contextPropertyDependencyCount; ++i) {
@@ -460,6 +461,9 @@ ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasPr
return Encode::undefined();
}
+ if (hasProperty)
+ *hasProperty = true;
+
ExecutionEngine *v4 = m->engine();
QQmlEnginePrivate *ep = v4->v8Engine->engine() ? QQmlEnginePrivate::get(v4->v8Engine->engine()) : 0;
if (ep)
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 16e3abf3a0..75acbdb778 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -47,8 +47,6 @@
QT_BEGIN_NAMESPACE
-using namespace QQmlScript;
-
/*!
\class QQmlCustomParser
\brief The QQmlCustomParser class allows you to add new arbitrary types to QML.
@@ -102,7 +100,7 @@ void QQmlCustomParser::clearErrors()
An error is generated referring to the \a location in the source file.
*/
-void QQmlCustomParser::error(const CompiledData::Location &location, const QString &description)
+void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
error.setLine(location.line);
@@ -144,11 +142,6 @@ QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledD
return compiler->bindingIdentifier(binding, this);
}
-QQmlJS::AST::Node *QQmlCustomParser::astForBinding(int objectIndex, int scriptIndex) const
-{
- return compiler->astForBinding(objectIndex, scriptIndex);
-}
-
struct StaticQtMetaObject : public QObject
{
static const QMetaObject *get()
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 8d98cf6423..2ce6375870 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -55,7 +55,6 @@
#include "qqmlmetatype_p.h"
#include "qqmlerror.h"
-#include "qqmlscript_p.h"
#include "qqmlbinding_p.h"
#include <QtCore/qbytearray.h>
@@ -63,6 +62,8 @@
QT_BEGIN_NAMESPACE
+class QQmlCompiledData;
+
struct QQmlCustomParserCompilerBackend
{
virtual ~QQmlCustomParserCompilerBackend() {}
@@ -72,8 +73,6 @@ struct QQmlCustomParserCompilerBackend
const QMetaObject *resolveType(const QString& name) const;
virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; }
-
- virtual QQmlJS::AST::Node *astForBinding(int, int) const { return 0; }
};
class Q_QML_PRIVATE_EXPORT QQmlCustomParser
@@ -93,8 +92,8 @@ public:
void clearErrors();
Flags flags() const { return m_flags; }
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings) = 0;
- virtual void setCustomData(QObject *, const QByteArray &)=0;
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) = 0;
+ virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata) = 0;
QList<QQmlError> errors() const { return exceptions; }
@@ -111,8 +110,6 @@ protected:
QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding);
- QQmlJS::AST::Node *astForBinding(int objectIndex, int scriptIndex) const;
-
private:
QList<QQmlError> exceptions;
QQmlCustomParserCompilerBackend *compiler;
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index c1d0132c61..a2b4b5edd0 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -41,9 +41,7 @@
#include "qqmldirparser_p.h"
#include "qqmlerror.h"
-#include "qqmlglobal_p.h"
-#include <QtQml/qqmlfile.h>
#include <QtCore/QtDebug>
QT_BEGIN_NAMESPACE
@@ -281,10 +279,10 @@ bool QQmlDirParser::parse(const QString &source)
void QQmlDirParser::reportError(quint16 line, quint16 column, const QString &description)
{
- QQmlError error;
- error.setLine(line);
- error.setColumn(column);
- error.setDescription(description);
+ QQmlJS::DiagnosticMessage error;
+ error.loc.startLine = line;
+ error.loc.startColumn = column;
+ error.message = description;
_errors.append(error);
}
@@ -296,25 +294,41 @@ bool QQmlDirParser::hasError() const
return false;
}
+#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+QList<QQmlJS::DiagnosticMessage> QQmlDirParser::errors(const QString &uri) const
+{
+ QList<QQmlJS::DiagnosticMessage> errors = _errors;
+ for (int i = 0; i < errors.size(); ++i) {
+ QQmlJS::DiagnosticMessage &msg = errors[i];
+ msg.message.replace(QLatin1String("$$URI$$"), uri);
+ }
+ return errors;
+}
+#else
void QQmlDirParser::setError(const QQmlError &e)
{
_errors.clear();
- _errors.append(e);
+ reportError(e.line(), e.column(), e.description());
}
QList<QQmlError> QQmlDirParser::errors(const QString &uri) const
{
QUrl url(uri);
- QList<QQmlError> errors = _errors;
- for (int i = 0; i < errors.size(); ++i) {
- QQmlError &e = errors[i];
- QString description = e.description();
+ QList<QQmlError> errors;
+ for (int i = 0; i < _errors.size(); ++i) {
+ const QQmlJS::DiagnosticMessage &msg = _errors.at(i);
+ QQmlError e;
+ QString description = msg.message;
description.replace(QLatin1String("$$URI$$"), uri);
e.setDescription(description);
e.setUrl(url);
+ e.setLine(msg.loc.startLine);
+ e.setColumn(msg.loc.startColumn);
+ errors << e;
}
return errors;
}
+#endif
QString QQmlDirParser::typeNamespace() const
{
@@ -331,7 +345,7 @@ QList<QQmlDirParser::Plugin> QQmlDirParser::plugins() const
return _plugins;
}
-QHash<QHashedStringRef,QQmlDirParser::Component> QQmlDirParser::components() const
+QHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const
{
return _components;
}
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
index e3607d1e72..bcdb366c6c 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -56,13 +56,14 @@
#include <QtCore/QUrl>
#include <QtCore/QHash>
#include <QtCore/QDebug>
-#include <private/qhashedstring_p.h>
+#include <private/qqmljsengine_p.h>
+#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
class QQmlError;
class QQmlEngine;
-class Q_AUTOTEST_EXPORT QQmlDirParser
+class Q_QML_PRIVATE_EXPORT QQmlDirParser
{
Q_DISABLE_COPY(QQmlDirParser)
@@ -73,8 +74,12 @@ public:
bool parse(const QString &source);
bool hasError() const;
+#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+ QList<QQmlJS::DiagnosticMessage> errors(const QString &uri) const;
+#else
void setError(const QQmlError &);
QList<QQmlError> errors(const QString &uri) const;
+#endif
QString typeNamespace() const;
void setTypeNamespace(const QString &s);
@@ -121,7 +126,7 @@ public:
int minorVersion;
};
- QHash<QHashedStringRef,Component> components() const;
+ QHash<QString,Component> components() const;
QList<Script> scripts() const;
QList<Plugin> plugins() const;
@@ -142,9 +147,9 @@ private:
void reportError(quint16 line, quint16 column, const QString &message);
private:
- QList<QQmlError> _errors;
+ QList<QQmlJS::DiagnosticMessage> _errors;
QString _typeNamespace;
- QHash<QHashedStringRef,Component> _components; // multi hash
+ QHash<QString,Component> _components; // multi hash
QList<Script> _scripts;
QList<Plugin> _plugins;
#ifdef QT_CREATOR
@@ -152,7 +157,7 @@ private:
#endif
};
-typedef QHash<QHashedStringRef,QQmlDirParser::Component> QQmlDirComponents;
+typedef QHash<QString,QQmlDirParser::Component> QQmlDirComponents;
typedef QList<QQmlDirParser::Script> QQmlDirScripts;
typedef QList<QQmlDirParser::Plugin> QQmlDirPlugins;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index d927a8c628..d378d77bb0 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -109,7 +109,9 @@
#include <qlibrary.h>
#include <windows.h>
-#define CSIDL_APPDATA 0x001a // <username>\Application Data
+#ifndef CSIDL_APPDATA
+# define CSIDL_APPDATA 0x001a // <username>\Application Data
+#endif
#endif
Q_DECLARE_METATYPE(QQmlProperty)
@@ -2302,12 +2304,23 @@ static inline QString shellNormalizeFileName(const QString &name)
{
const QString nativeSeparatorName(QDir::toNativeSeparators(name));
const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16());
+// The correct declaration of the SHGetPathFromIDList symbol is
+// being used in mingw-w64 as of r6215, which is a v3 snapshot.
+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
+ ITEMIDLIST file;
+ if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL)))
+ return name;
+ TCHAR buffer[MAX_PATH];
+ if (!SHGetPathFromIDList(&file, buffer))
+ return name;
+#else
PIDLIST_ABSOLUTE file;
if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL)))
return name;
TCHAR buffer[MAX_PATH];
if (!SHGetPathFromIDList(file, buffer))
return name;
+#endif
QString canonicalName = QString::fromWCharArray(buffer);
// Upper case drive letter
if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':'))
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 56c80dc2cd..5767ca90f0 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -69,6 +69,7 @@
#include "qqmldirparser_p.h"
#include <private/qintrusivelist_p.h>
#include <private/qrecyclepool_p.h>
+#include <private/qfieldlist_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index b64dd9bd39..4dc3704bbb 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -78,17 +78,10 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb
expressionFunctionValid = false;
}
-void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
- QObject *me, const QString &srcUrl,
- quint16 lineNumber, quint16 columnNumber)
+void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFunction, QObject *me)
{
- url = srcUrl;
- line = lineNumber;
- column = columnNumber;
-
- expression = expr;
-
- expressionFunctionValid = false;
+ expressionFunctionValid = true;
+ function = QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction);
QQmlAbstractExpression::setContext(ctxt);
setScopeObject(me);
@@ -156,9 +149,9 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt
if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
return;
- bool defaultConstruction = true;
QQmlContextData *evalCtxtData = QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context);
QObject *scopeObject = scope ? scope : scriptPrivate->scope;
+ QV4::Function *runtimeFunction = 0;
if (scriptPrivate->context) {
QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
@@ -168,23 +161,22 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt
Q_ASSERT(typeData);
if (QQmlCompiledData *cdata = typeData->compiledData()) {
- int id = scriptPrivate->bindingId;
- if (id >= 0) {
- defaultConstruction = false;
- d->init(evalCtxtData, cdata->primitives.at(id), scopeObject,
- cdata->name, scriptPrivate->lineNumber, scriptPrivate->columnNumber);
- } else {
- d->url = cdata->name;
- d->line = scriptPrivate->lineNumber;
- d->column = scriptPrivate->columnNumber;
- }
+ d->url = cdata->name;
+ d->line = scriptPrivate->lineNumber;
+ d->column = scriptPrivate->columnNumber;
+
+ if (scriptPrivate->bindingId != QQmlBinding::Invalid)
+ runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
}
typeData->release();
}
}
- if (defaultConstruction)
+ if (runtimeFunction) {
+ d->expression = scriptPrivate->script;
+ d->init(evalCtxtData, runtimeFunction, scopeObject);
+ } else
d->init(evalCtxtData, scriptPrivate->script, scopeObject);
}
diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h
index b702a37ee0..185b9542c5 100644
--- a/src/qml/qml/qqmlexpression.h
+++ b/src/qml/qml/qqmlexpression.h
@@ -98,7 +98,6 @@ private:
Q_DECLARE_PRIVATE(QQmlExpression)
friend class QQmlDebugger;
friend class QQmlContext;
- friend class QQmlVME;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index e84d193837..5488459962 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -77,7 +77,7 @@ public:
~QQmlExpressionPrivate();
void init(QQmlContextData *, const QString &, QObject *);
- void init(QQmlContextData *, const QString &, QObject *, const QString &, quint16, quint16);
+ void init(QQmlContextData *, QV4::Function *runtimeFunction, QObject *);
QVariant value(bool *isUndefined = 0);
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index 76de2dfe34..f3d1ba9d41 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -77,7 +77,7 @@ QT_BEGIN_NAMESPACE
as a new QML element. It provides the current time through \c hour and \c minute
properties, like this:
- \snippet plugins/plugin.cpp 0
+ \snippet qmlextensionplugins/plugin.cpp 0
\dots
To make this class available as a QML type, create a plugin that registers
@@ -85,7 +85,7 @@ QT_BEGIN_NAMESPACE
module will be named \c TimeExample (as defined in the project
file further below).
- \snippet plugins/plugin.cpp plugin
+ \snippet qmlextensionplugins/plugin.cpp plugin
This registers the \c TimeModel class with the 1.0 version of this
plugin library, as a QML type called \c Time. The Q_ASSERT statement
@@ -109,14 +109,14 @@ QT_BEGIN_NAMESPACE
should be bundled with the plugin, so it needs to be specified in the \c qmldir
file:
- \quotefile plugins/imports/TimeExample/qmldir
+ \quotefile qmlextensionplugins/imports/TimeExample/qmldir
Once the project is built and installed, the new \c Time element can be
used by any QML component that imports the \c TimeExample module:
- \snippet plugins/plugins.qml 0
+ \snippet qmlextensionplugins/plugins.qml 0
- The full source code is available in the \l {qml/plugins}{plugins example}.
+ The full source code is available in the \l {qml/qmlextensionplugins}{plugins example}.
The \l {Writing QML Extensions with C++} tutorial also contains a chapter
on creating QML plugins.
diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp
index be9b011dda..6728fa10a7 100644
--- a/src/qml/qml/qqmlfile.cpp
+++ b/src/qml/qml/qqmlfile.cpp
@@ -666,18 +666,13 @@ QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
static QString toLocalFile(const QString &url)
{
- if (!url.startsWith(QLatin1String("file://"), Qt::CaseInsensitive))
+ const QUrl file(url);
+ if (!file.isLocalFile())
return QString();
- QString file = url.mid(7);
-
//XXX TODO: handle windows hostnames: "//servername/path/to/file.txt"
- // magic for drives on windows
- if (file.length() > 2 && file.at(0) == QLatin1Char('/') && file.at(2) == QLatin1Char(':'))
- file.remove(0, 1);
-
- return file;
+ return file.toLocalFile();
}
/*!
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index a18b8327b1..187c3656c6 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -152,8 +152,8 @@ void QQmlFileSelector::setSelector(QFileSelector *selector)
}
/*!
- Adds extra selectors to the current QFileSelector being used. Use this when
- extra selectors are all you need to avoid having to create your own
+ Adds extra selectors contained in \a strings to the current QFileSelector being used.
+ Use this when extra selectors are all you need to avoid having to create your own
QFileSelector instance.
*/
void QQmlFileSelector::setExtraSelectors(QStringList &strings)
@@ -163,7 +163,7 @@ void QQmlFileSelector::setExtraSelectors(QStringList &strings)
}
/*!
- Gets the QQmlFileSelector currently active on the target engine.
+ Gets the QQmlFileSelector currently active on the target \a engine.
*/
QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine)
{
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index cae8365598..c0b21a943f 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -296,7 +296,7 @@ public:
QQmlImportNamespace::Import *addImportToNamespace(QQmlImportNamespace *nameSpace,
const QString &uri, const QString &url,
- int vmaj, int vmin, QQmlScript::Import::Type type,
+ int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence = false);
bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri,
@@ -624,12 +624,13 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
}
}
- QQmlDirComponents::ConstIterator it = qmlDirComponents.find(type), end = qmlDirComponents.end();
+ const QString typeStr = type.toString();
+ QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end();
if (it != end) {
QString componentUrl;
bool isCompositeSingleton = false;
QQmlDirComponents::ConstIterator candidate = end;
- for ( ; it != end && it.key() == type; ++it) {
+ for ( ; it != end && it.key() == typeStr; ++it) {
const QQmlDirParser::Component &c = *it;
// importing version -1 means import ALL versions
@@ -1211,7 +1212,7 @@ QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix)
QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
const QString &uri, const QString &url, int vmaj, int vmin,
- QQmlScript::Import::Type type,
+ QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence)
{
Q_ASSERT(nameSpace);
@@ -1224,7 +1225,7 @@ QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImport
import->url = url;
import->majversion = vmaj;
import->minversion = vmin;
- import->isLibrary = (type == QQmlScript::Import::Library);
+ import->isLibrary = (type == QV4::CompiledData::Import::ImportLibrary);
if (lowPrecedence)
nameSpace->imports.append(import);
@@ -1245,7 +1246,7 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
- QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QQmlScript::Import::Library, errors);
+ QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
Q_ASSERT(inserted);
if (!incomplete) {
@@ -1375,7 +1376,7 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
if (!url.endsWith(Slash) && !url.endsWith(Backslash))
url += Slash;
- QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QQmlScript::Import::File, errors, isImplicitImport);
+ QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
Q_ASSERT(inserted);
if (!incomplete && !qmldirIdentifier.isEmpty()) {
@@ -1578,8 +1579,7 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
QQmlImportDatabase::~QQmlImportDatabase()
{
- qDeleteAll(qmldirCache);
- qmldirCache.clear();
+ clearDirCache();
}
/*!
@@ -1814,7 +1814,7 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
fileImportPath = paths;
// Our existing cached paths may have been invalidated
- qmldirCache.clear();
+ clearDirCache();
}
/*!
@@ -2024,4 +2024,20 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr
#endif
}
+void QQmlImportDatabase::clearDirCache()
+{
+ QStringHash<QmldirCache *>::ConstIterator itr = qmldirCache.begin();
+ while (itr != qmldirCache.end()) {
+ QmldirCache *cache = *itr;
+ do {
+ QmldirCache *nextCache = cache->next;
+ delete cache;
+ cache = nextCache;
+ } while (cache);
+
+ ++itr;
+ }
+ qmldirCache.clear();
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index b19e777852..3c9452963c 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -47,8 +47,8 @@
#include <QtCore/qset.h>
#include <QtCore/qstringlist.h>
#include <private/qqmldirparser_p.h>
-#include <private/qqmlscript_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qhashedstring_p.h>
//
// W A R N I N G
@@ -174,6 +174,7 @@ private:
const QString &typeNamespace, QList<QQmlError> *errors);
bool registerPluginTypes(QObject *instance, const QString &basePath,
const QString &uri, const QString &typeNamespace, QList<QQmlError> *errors);
+ void clearDirCache();
struct QmldirCache {
int versionMajor;
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 4c9c99f1f6..4cdeb19719 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -169,6 +169,20 @@ void QQmlIncubatorPrivate::clear()
nextWaitingFor.remove();
waitingOnMe = 0;
}
+
+ // if we're waiting on any incubators then they should be cleared too.
+ while (waitingFor.first()) {
+ QQmlIncubator * i = static_cast<QQmlIncubatorPrivate*>(waitingFor.first())->q;
+ if (i)
+ i->clear();
+ }
+
+ bool guardOk = vmeGuard.isOK();
+
+ vmeGuard.clear();
+ if (creator && guardOk)
+ creator->clear();
+ creator.reset(0);
}
/*!
@@ -393,7 +407,7 @@ void QQmlIncubationController::incubateFor(int msecs)
/*!
Incubate objects while the bool pointed to by \a flag is true, or until there are no
-more objects to incubate, or up to msecs if msecs is not zero.
+more objects to incubate, or up to \a msecs if \a msecs is not zero.
Generally this method is used in conjunction with a thread or a UNIX signal that sets
the bool pointed to by \a flag to false when it wants incubation to be interrupted.
@@ -562,20 +576,6 @@ void QQmlIncubator::clear()
d->clear();
- // if we're waiting on any incubators then they should be cleared too.
- while (d->waitingFor.first()) {
- QQmlIncubator * i = static_cast<QQmlIncubatorPrivate*>(d->waitingFor.first())->q;
- if (i)
- i->clear();
- }
-
- bool guardOk = d->vmeGuard.isOK();
-
- d->vmeGuard.clear();
- if (d->creator && guardOk)
- d->creator->clear();
- d->creator.reset(0);
-
Q_ASSERT(d->compiledData == 0);
Q_ASSERT(d->waitingOnMe.data() == 0);
Q_ASSERT(d->waitingFor.isEmpty());
@@ -687,7 +687,7 @@ void QQmlIncubator::statusChanged(Status status)
}
/*!
-Called after the object is first created, but before property bindings are
+Called after the \a object is first created, but before property bindings are
evaluated and, if applicable, QQmlParserStatus::componentComplete() is
called. This is equivalent to the point between QQmlComponent::beginCreate()
and QQmlComponent::endCreate(), and can be used to assign initial values
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index b233b6e98c..560a4c8afd 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -218,7 +218,6 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n)
}
/*! \internal
- \reimp
\a n is in the signal index range (see QObjectPrivate::signalIndex()).
*/
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 0d60fee5d0..fd50e2dbbc 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -129,13 +129,21 @@ ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProper
QV4::ExecutionEngine *e = m->engine();
QmlListWrapper *w = m->as<QmlListWrapper>();
- if (!w)
+ if (!w) {
+ if (hasProperty)
+ *hasProperty = false;
return e->currentContext()->throwTypeError();
+ }
quint32 count = w->property.count ? w->property.count(&w->property) : 0;
- if (index < count && w->property.at)
+ if (index < count && w->property.at) {
+ if (hasProperty)
+ *hasProperty = true;
return QV4::QObjectWrapper::wrap(e, w->property.at(&w->property, index));
+ }
+ if (hasProperty)
+ *hasProperty = false;
return Primitive::undefinedValue().asReturnedValue();
}
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index fc9e2fc42a..178280b27c 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -290,8 +290,11 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte
tm = r->locale.toTime(dateString, enumFormat);
}
- QDateTime dt = QDateTime::currentDateTime();
- dt.setTime(tm);
+ QDateTime dt;
+ if (tm.isValid()) {
+ dt = QDateTime::currentDateTime();
+ dt.setTime(tm);
+ }
return QV4::Encode(engine->newDateObject(dt));
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 90d3ca3308..42f67f3345 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -106,6 +106,7 @@ struct QQmlMetaTypeData
QBitArray lists;
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
+ QQmlPrivate::QmlUnitCacheLookupFunction lookupCachedQmlUnit;
QSet<QString> protectedNamespaces;
@@ -142,6 +143,7 @@ static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
}
QQmlMetaTypeData::QQmlMetaTypeData()
+ : lookupCachedQmlUnit(0)
{
}
@@ -1344,6 +1346,15 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
return index;
}
+int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
+{
+ if (hookRegistration.version > 0)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ data->lookupCachedQmlUnit = hookRegistration.lookupCachedQmlUnit;
+ return 0;
+}
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
@@ -1363,6 +1374,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
return registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
} else if (type == CompositeSingletonRegistration) {
return registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
+ } else if (type == QmlUnitCacheHookRegistration) {
+ return registerQmlUnitCacheHook(*reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
}
return -1;
}
@@ -1865,26 +1878,13 @@ QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
return retn;
}
-int QQmlMetaType::QQuickAnchorLineMetaTypeId()
+const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri)
{
- static int id = 0;
- if (!id) {
- id = QMetaType::type("QQuickAnchorLine");
- }
- return id;
-}
-
-QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
-
-void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
-{
- anchorLineCompareFunction = fun;
-}
-
-bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
-{
- Q_ASSERT(anchorLineCompareFunction != 0);
- return anchorLineCompareFunction(p1, p2);
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ if (data->lookupCachedQmlUnit)
+ return data->lookupCachedQmlUnit(uri);
+ return 0;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 019e6b8821..715ff80c46 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -120,10 +120,7 @@ public:
static QList<QQmlPrivate::AutoParentFunction> parentFunctions();
- static int QQuickAnchorLineMetaTypeId();
- typedef bool (*CompareFunction)(const void *, const void *);
- static void setQQuickAnchorLineCompareFunction(CompareFunction);
- static bool QQuickAnchorLineCompare(const void *p1, const void *p2);
+ static const QQmlPrivate::CachedQmlUnit *findCachedCompilationUnit(const QUrl &uri);
static bool namespaceContainsRegistrations(const QString &);
@@ -133,9 +130,6 @@ public:
static QStringList typeRegistrationFailures();
static QReadWriteLock *typeRegistrationLock();
-
-private:
- static CompareFunction anchorLineCompareFunction;
};
struct QQmlMetaTypeData;
@@ -240,6 +234,7 @@ private:
friend int registerInterface(const QQmlPrivate::RegisterInterface &);
friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &);
friend int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &);
+ friend int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &);
friend Q_QML_EXPORT void qmlClearTypeRegistrations();
QQmlType(int, const QQmlPrivate::RegisterInterface &);
QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 50fe5861a6..2ebf90c9be 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -85,7 +85,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
, compiledData(compiledData)
, resolvedTypes(compiledData->resolvedTypes)
, propertyCaches(compiledData->propertyCaches)
- , vmeMetaObjectData(compiledData->datas)
+ , vmeMetaObjectData(compiledData->metaObjects)
, activeVMEDataForRootContext(activeVMEDataForRootContext)
{
init(parentContext);
@@ -98,7 +98,10 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount);
sharedState->creationContext = creationContext;
sharedState->rootContext = 0;
- sharedState->profiler.profiler = QQmlEnginePrivate::get(engine)->profiler;
+
+ QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler;
+ Q_QML_PROFILE_IF_ENABLED(profiler,
+ sharedState->profiler.init(profiler, compiledData->totalParserStatusCount));
}
QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState)
@@ -106,7 +109,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
, compiledData(compiledData)
, resolvedTypes(compiledData->resolvedTypes)
, propertyCaches(compiledData->propertyCaches)
- , vmeMetaObjectData(compiledData->datas)
+ , vmeMetaObjectData(compiledData->metaObjects)
, activeVMEDataForRootContext(0)
{
init(parentContext);
@@ -213,7 +216,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
context->importedScripts = sharedState->creationContext->importedScripts;
}
- QObject *instance = createInstance(objectToCreate, parent);
+ QObject *instance = createInstance(objectToCreate, parent, /*isContextObject*/true);
if (instance) {
QQmlData *ddata = QQmlData::get(instance);
Q_ASSERT(ddata);
@@ -221,12 +224,8 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
ddata->compiledData->release();
ddata->compiledData = compiledData;
ddata->compiledData->addref();
-
- context->contextObject = instance;
}
- Q_QML_VME_PROFILE(sharedState->profiler, stop());
-
phase = CreatingObjectsPhase2;
if (interrupt && interrupt->shouldInterrupt())
@@ -241,6 +240,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
{
QQmlData *declarativeData = QQmlData::get(instance);
context = declarativeData->deferredData->context;
+ sharedState->rootContext = context;
const int objectIndex = declarativeData->deferredData->deferredIdx;
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
@@ -704,7 +704,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
if (!name.isEmpty()) {
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
|| binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- property = PropertyResolver(_propertyCache).signal(name, /*notInRevision*/0, _qobject, context);
+ property = QmlIR::PropertyResolver(_propertyCache).signal(name, /*notInRevision*/0, _qobject, context);
else
property = _propertyCache->property(name, _qobject, context);
} else
@@ -745,7 +745,7 @@ bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4
// ### resolve this at compile time
if (property && property->propType == qMetaTypeId<QQmlScriptString>()) {
QQmlScriptString ss(binding->valueAsScriptString(&qmlUnit->header), context->asQQmlContext(), _scopeObject);
- ss.d.data()->bindingId = QQmlBinding::Invalid;
+ ss.d.data()->bindingId = binding->value.compiledScriptIndex;
ss.d.data()->lineNumber = binding->location.line;
ss.d.data()->columnNumber = binding->location.column;
ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
@@ -820,7 +820,7 @@ bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4
QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
QV4::Scope scope(_qmlContext);
- QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction, /*createProto*/ false));
+ QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(_qmlContext, runtimeFunction, /*createProto*/ false));
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex);
@@ -998,7 +998,7 @@ void QQmlObjectCreator::setupFunctions()
if (!property->isVMEFunction())
continue;
- function = QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction);
+ function = QV4::FunctionObject::createScriptFunction(_qmlContext, runtimeFunction);
_vmeMetaObject->setVmeMethod(property->coreIndex, function);
}
}
@@ -1013,8 +1013,9 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location,
errors << error;
}
-QObject *QQmlObjectCreator::createInstance(int index, QObject *parent)
+QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
{
+ QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler);
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
bool isComponent = false;
@@ -1024,21 +1025,23 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent)
QQmlParserStatus *parserStatus = 0;
bool installPropertyCache = true;
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
if (compiledData->isComponent(index)) {
isComponent = true;
QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
+ Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(QStringLiteral("<component>"),
+ context->url, obj->location.line, obj->location.column));
QQmlComponentPrivate::get(component)->creationContext = context;
instance = component;
ddata = QQmlData::get(instance, /*create*/true);
} else {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
-
QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
installPropertyCache = !typeRef->isFullyDynamicType;
QQmlType *type = typeRef->type;
if (type) {
- Q_QML_VME_PROFILE(sharedState->profiler, start(type->qmlTypeName(), context->url, obj->location.line, obj->location.column));
+ Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(type->qmlTypeName(),
+ context->url, obj->location.line, obj->location.column));
instance = type->create();
if (!instance) {
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
@@ -1060,23 +1063,23 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent)
sharedState->allCreatedObjects.push(instance);
} else {
Q_ASSERT(typeRef->component);
+ Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->name,
+ context->url, obj->location.line, obj->location.column));
if (typeRef->component->qmlUnit->isSingleton())
{
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
return 0;
}
- Q_QML_VME_PROFILE(sharedState->profiler, startBackground(typeRef->component->name));
+
QQmlObjectCreator subCreator(context, typeRef->component, sharedState.data());
instance = subCreator.create();
- Q_QML_VME_PROFILE(sharedState->profiler, foreground(context->url, obj->location.line, obj->location.column));
if (!instance) {
errors += subCreator.errors;
return 0;
}
}
- // ### use no-event variant
if (parent)
- instance->setParent(parent);
+ QQml_setParent_noEvent(instance, parent);
ddata = QQmlData::get(instance, /*create*/true);
ddata->lineNumber = obj->location.line;
@@ -1102,6 +1105,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent)
if (parserStatus) {
parserStatus->classBegin();
+ // push() the profiler state here, together with the parserStatus, as we'll pop() them
+ // together, too.
+ Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(profiler));
sharedState->allParserStatusCallbacks.push(parserStatus);
parserStatus->d = &sharedState->allParserStatusCallbacks.top();
}
@@ -1110,11 +1116,16 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent)
if (idEntry != objectIndexToId.constEnd())
context->setIdProperty(idEntry.value(), instance);
+ // Register the context object in the context early on in order for pending binding
+ // initialization to find it available.
+ if (isContextObject)
+ context->contextObject = instance;
+
QBitArray bindingsToSkip;
if (customParser) {
QHash<int, QQmlCompiledData::CustomParserData>::ConstIterator entry = compiledData->customParserData.find(index);
if (entry != compiledData->customParserData.constEnd()) {
- customParser->setCustomData(instance, entry->compilationArtifact);
+ customParser->setCustomData(instance, entry->compilationArtifact, compiledData);
bindingsToSkip = entry->bindings;
}
}
@@ -1122,7 +1133,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent)
if (isComponent)
return instance;
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index);
Q_ASSERT(!cache.isNull());
if (installPropertyCache) {
if (ddata->propertyCache)
@@ -1183,7 +1194,7 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later
QQmlTrace trace("VME Component Complete");
while (!sharedState->allParserStatusCallbacks.isEmpty()) {
- Q_QML_VME_PROFILE(sharedState->profiler, pop());
+ QQmlObjectCompletionProfiler profiler(&sharedState->profiler);
QQmlParserStatus *status = sharedState->allParserStatusCallbacks.pop();
if (status && status->d) {
@@ -1194,7 +1205,6 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
return 0;
}
- Q_QML_VME_PROFILE(sharedState->profiler, clear());
}
{
@@ -1243,20 +1253,12 @@ void QQmlObjectCreator::clear()
while (!sharedState->allCreatedObjects.isEmpty())
delete sharedState->allCreatedObjects.pop();
- // If profiling is switched off during a VME run and then switched back on
- // before or during the next run background ranges from the first run will
- // be reported in the second run because we don't clear() here. We accept
- // that as the collected data will be incomplete anyway and because not
- // calling clear() here is benefitial for the non-profiling case.
- Q_QML_VME_PROFILE(sharedState->profiler, clear(true));
-
phase = Done;
}
bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip)
{
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
- Q_QML_VME_PROFILE(sharedState->profiler, push());
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
@@ -1270,7 +1272,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
QV4::Scope valueScope(v4);
QV4::ScopedValue scopeObjectProtector(valueScope);
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index);
QQmlVMEMetaObject *vmeMetaObject = 0;
const QByteArray data = vmeMetaObjectData.value(index);
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 9fd52a9f48..379a3b2970 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -96,7 +96,7 @@ private:
void init(QQmlContextData *parentContext);
- QObject *createInstance(int index, QObject *parent = 0);
+ QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false);
bool populateInstance(int index, QObject *instance,
QObject *bindingTarget, QQmlPropertyData *valueTypeProperty,
diff --git a/src/qml/qml/qqmlparserstatus.h b/src/qml/qml/qqmlparserstatus.h
index 4e611f82b1..92b320ec0c 100644
--- a/src/qml/qml/qqmlparserstatus.h
+++ b/src/qml/qml/qqmlparserstatus.h
@@ -58,7 +58,6 @@ public:
virtual void componentComplete()=0;
private:
- friend class QQmlVME;
friend class QQmlComponent;
friend class QQmlComponentPrivate;
friend class QQmlEnginePrivate;
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index 04862379be..8ee4a542de 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -60,23 +60,27 @@ QQmlPlatform::~QQmlPlatform()
QString QQmlPlatform::os()
{
#if defined(Q_OS_ANDROID)
- return QLatin1String("android");
+ return QStringLiteral("android");
#elif defined(Q_OS_BLACKBERRY)
- return QLatin1String("blackberry");
+ return QStringLiteral("blackberry");
#elif defined(Q_OS_IOS)
- return QLatin1String("ios");
+ return QStringLiteral("ios");
#elif defined(Q_OS_MAC)
- return QLatin1String("osx");
+ return QStringLiteral("osx");
#elif defined(Q_OS_WINCE)
- return QLatin1String("wince");
+ return QStringLiteral("wince");
+#elif defined(Q_OS_WINPHONE)
+ return QStringLiteral("winphone");
+#elif defined(Q_OS_WINRT)
+ return QStringLiteral("winrt");
#elif defined(Q_OS_WIN)
- return QLatin1String("windows");
+ return QStringLiteral("windows");
#elif defined(Q_OS_LINUX)
- return QLatin1String("linux");
+ return QStringLiteral("linux");
#elif defined(Q_OS_UNIX)
- return QLatin1String("unix");
+ return QStringLiteral("unix");
#else
- return QLatin1String("unknown");
+ return QStringLiteral("unknown");
#endif
}
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index 90e7961e6b..5460c99f1d 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -61,6 +61,22 @@
QT_BEGIN_NAMESPACE
+namespace QQmlPrivate {
+struct CachedQmlUnit;
+}
+
+namespace QV4 {
+struct ExecutionEngine;
+namespace CompiledData {
+struct QmlUnit;
+struct CompilationUnit;
+}
+typedef CompiledData::CompilationUnit *(*CompilationUnitFactoryFunction)();
+}
+namespace QmlIR {
+struct Document;
+typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *);
+}
typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *);
@@ -268,13 +284,26 @@ namespace QQmlPrivate
const char *typeName;
};
+ struct CachedQmlUnit {
+ const QV4::CompiledData::QmlUnit *qmlData;
+ QV4::CompilationUnitFactoryFunction createCompilationUnit;
+ QmlIR::IRLoaderFunction loadIR;
+ };
+
+ typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url);
+ struct RegisterQmlUnitCacheHook {
+ int version;
+ QmlUnitCacheLookupFunction lookupCachedQmlUnit;
+ };
+
enum RegistrationType {
TypeRegistration = 0,
InterfaceRegistration = 1,
AutoParentRegistration = 2,
SingletonRegistration = 3,
CompositeRegistration = 4,
- CompositeSingletonRegistration = 5
+ CompositeSingletonRegistration = 5,
+ QmlUnitCacheHookRegistration = 6
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 0bbcafda54..1075b53c5e 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1403,6 +1403,12 @@ bool QQmlPropertyPrivate::write(QObject *object,
v = value;
if (v.convert(propertyType)) {
ok = true;
+ } else if (v.isValid() && value.isNull()) {
+ // For historical reasons converting a null QVariant to another type will do the trick
+ // but return false anyway. This is caught with the above condition and considered a
+ // successful conversion.
+ Q_ASSERT(v.userType() == propertyType);
+ ok = true;
} else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
if (con) {
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
deleted file mode 100644
index cf56d5701d..0000000000
--- a/src/qml/qml/qqmlscript.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlscript_p.h"
-
-#include <private/qqmljsengine_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsmemorypool_p.h>
-#include <private/qqmljsastvisitor_p.h>
-#include <private/qqmljsast_p.h>
-
-#include <QStack>
-#include <QStringList>
-#include <QCoreApplication>
-#include <QtDebug>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QQmlJS;
-using namespace QQmlScript;
-
-static void replaceWithSpace(QString &str, int idx, int n)
-{
- QChar *data = str.data() + idx;
- const QChar space(QLatin1Char(' '));
- for (int ii = 0; ii < n; ++ii)
- *data++ = space;
-}
-
-static QQmlScript::LocationSpan
-locationFromLexer(const QQmlJS::Lexer &lex, int startLine, int startColumn, int startOffset)
-{
- QQmlScript::LocationSpan l;
-
- l.start.line = startLine; l.start.column = startColumn;
- l.end.line = lex.tokenEndLine(); l.end.column = lex.tokenEndColumn();
- l.range.offset = startOffset;
- l.range.length = lex.tokenOffset() + lex.tokenLength() - startOffset;
-
- return l;
-}
-
-/*
-Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas
-are:
- library
-*/
-QQmlScript::Object::ScriptBlock::Pragmas QQmlScript::Parser::extractPragmas(QString &script)
-{
- QQmlScript::Object::ScriptBlock::Pragmas rv = QQmlScript::Object::ScriptBlock::None;
-
- const QString pragma(QLatin1String("pragma"));
- const QString library(QLatin1String("library"));
-
- QQmlJS::Lexer l(0);
- l.setCode(script, 0);
-
- int token = l.lex();
-
- while (true) {
- if (token != QQmlJSGrammar::T_DOT)
- return rv;
-
- int startOffset = l.tokenOffset();
- int startLine = l.tokenStartLine();
-
- token = l.lex();
-
- if (token != QQmlJSGrammar::T_PRAGMA ||
- l.tokenStartLine() != startLine ||
- script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
- return rv;
-
- token = l.lex();
-
- if (token != QQmlJSGrammar::T_IDENTIFIER ||
- l.tokenStartLine() != startLine)
- return rv;
-
- QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
- int endOffset = l.tokenLength() + l.tokenOffset();
-
- token = l.lex();
- if (l.tokenStartLine() == startLine)
- return rv;
-
- if (pragmaValue == library) {
- rv |= QQmlScript::Object::ScriptBlock::Shared;
- replaceWithSpace(script, startOffset, endOffset - startOffset);
- } else {
- return rv;
- }
- }
- return rv;
-}
-
-#define CHECK_LINE if (l.tokenStartLine() != startLine) return rv;
-#define CHECK_TOKEN(t) if (token != QQmlJSGrammar:: t) return rv;
-
-static const int uriTokens[] = {
- QQmlJSGrammar::T_IDENTIFIER,
- QQmlJSGrammar::T_PROPERTY,
- QQmlJSGrammar::T_SIGNAL,
- QQmlJSGrammar::T_READONLY,
- QQmlJSGrammar::T_ON,
- QQmlJSGrammar::T_BREAK,
- QQmlJSGrammar::T_CASE,
- QQmlJSGrammar::T_CATCH,
- QQmlJSGrammar::T_CONTINUE,
- QQmlJSGrammar::T_DEFAULT,
- QQmlJSGrammar::T_DELETE,
- QQmlJSGrammar::T_DO,
- QQmlJSGrammar::T_ELSE,
- QQmlJSGrammar::T_FALSE,
- QQmlJSGrammar::T_FINALLY,
- QQmlJSGrammar::T_FOR,
- QQmlJSGrammar::T_FUNCTION,
- QQmlJSGrammar::T_IF,
- QQmlJSGrammar::T_IN,
- QQmlJSGrammar::T_INSTANCEOF,
- QQmlJSGrammar::T_NEW,
- QQmlJSGrammar::T_NULL,
- QQmlJSGrammar::T_RETURN,
- QQmlJSGrammar::T_SWITCH,
- QQmlJSGrammar::T_THIS,
- QQmlJSGrammar::T_THROW,
- QQmlJSGrammar::T_TRUE,
- QQmlJSGrammar::T_TRY,
- QQmlJSGrammar::T_TYPEOF,
- QQmlJSGrammar::T_VAR,
- QQmlJSGrammar::T_VOID,
- QQmlJSGrammar::T_WHILE,
- QQmlJSGrammar::T_CONST,
- QQmlJSGrammar::T_DEBUGGER,
- QQmlJSGrammar::T_RESERVED_WORD,
- QQmlJSGrammar::T_WITH,
-
- QQmlJSGrammar::EOF_SYMBOL
-};
-static inline bool isUriToken(int token)
-{
- const int *current = uriTokens;
- while (*current != QQmlJSGrammar::EOF_SYMBOL) {
- if (*current == token)
- return true;
- ++current;
- }
- return false;
-}
-
-static void extractVersion(QStringRef string, int *maj, int *min)
-{
- *maj = -1; *min = -1;
-
- if (!string.isEmpty()) {
-
- int dot = string.indexOf(QLatin1Char('.'));
-
- if (dot < 0) {
- *maj = string.toInt();
- *min = 0;
- } else {
- *maj = string.left(dot).toInt();
- *min = string.mid(dot + 1).toInt();
- }
- }
-}
-
-QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QString &script, QQmlError *error)
-{
- Q_ASSERT(error);
-
- JavaScriptMetaData rv;
-
- QQmlScript::Object::ScriptBlock::Pragmas &pragmas = rv.pragmas;
-
- const QString js(QLatin1String(".js"));
- const QString library(QLatin1String("library"));
-
- QQmlJS::Lexer l(0);
- l.setCode(script, 0);
-
- int token = l.lex();
-
- while (true) {
- if (token != QQmlJSGrammar::T_DOT)
- return rv;
-
- int startOffset = l.tokenOffset();
- int startLine = l.tokenStartLine();
- int startColumn = l.tokenStartColumn();
-
- QQmlError importError;
- importError.setLine(startLine + 1); // 0-based, adjust to be 1-based
-
- token = l.lex();
-
- CHECK_LINE;
-
- if (token == QQmlJSGrammar::T_IMPORT) {
-
- // .import <URI> <Version> as <Identifier>
- // .import <file.js> as <Identifier>
-
- token = l.lex();
-
- CHECK_LINE;
-
- if (token == QQmlJSGrammar::T_STRING_LITERAL) {
-
- QString file = l.tokenText();
-
- if (!file.endsWith(js)) {
- importError.setDescription(QCoreApplication::translate("QQmlParser","Imported file must be a script"));
- importError.setColumn(l.tokenStartColumn());
- *error = importError;
- return rv;
- }
-
- bool invalidImport = false;
-
- token = l.lex();
-
- if ((token != QQmlJSGrammar::T_AS) || (l.tokenStartLine() != startLine)) {
- invalidImport = true;
- } else {
- token = l.lex();
-
- if ((token != QQmlJSGrammar::T_IDENTIFIER) || (l.tokenStartLine() != startLine))
- invalidImport = true;
- }
-
-
- if (invalidImport) {
- importError.setDescription(QCoreApplication::translate("QQmlParser","File import requires a qualifier"));
- importError.setColumn(l.tokenStartColumn());
- *error = importError;
- return rv;
- }
-
- int endOffset = l.tokenLength() + l.tokenOffset();
-
- QString importId = script.mid(l.tokenOffset(), l.tokenLength());
-
- QQmlScript::LocationSpan location =
- locationFromLexer(l, startLine, startColumn, startOffset);
-
- token = l.lex();
-
- if (!importId.at(0).isUpper() || (l.tokenStartLine() == startLine)) {
- importError.setDescription(QCoreApplication::translate("QQmlParser","Invalid import qualifier"));
- importError.setColumn(l.tokenStartColumn());
- *error = importError;
- return rv;
- }
-
- replaceWithSpace(script, startOffset, endOffset - startOffset);
-
- Import import;
- import.type = Import::Script;
- import.uri = file;
- import.qualifier = importId;
- import.location = location;
-
- rv.imports << import;
- } else {
- // URI
- QString uri;
-
- while (true) {
- if (!isUriToken(token)) {
- importError.setDescription(QCoreApplication::translate("QQmlParser","Invalid module URI"));
- importError.setColumn(l.tokenStartColumn());
- *error = importError;
- return rv;
- }
-
- uri.append(l.tokenText());
-
- token = l.lex();
- CHECK_LINE;
- if (token != QQmlJSGrammar::T_DOT)
- break;
-
- uri.append(QLatin1Char('.'));
-
- token = l.lex();
- CHECK_LINE;
- }
-
- if (token != QQmlJSGrammar::T_NUMERIC_LITERAL) {
- importError.setDescription(QCoreApplication::translate("QQmlParser","Module import requires a version"));
- importError.setColumn(l.tokenStartColumn());
- *error = importError;
- return rv;
- }
-
- int vmaj, vmin;
- extractVersion(QStringRef(&script, l.tokenOffset(), l.tokenLength()),
- &vmaj, &vmin);
-
- bool invalidImport = false;
-
- token = l.lex();
-
- if ((token != QQmlJSGrammar::T_AS) || (l.tokenStartLine() != startLine)) {
- invalidImport = true;
- } else {
- token = l.lex();
-
- if ((token != QQmlJSGrammar::T_IDENTIFIER) || (l.tokenStartLine() != startLine))
- invalidImport = true;
- }
-
-
- if (invalidImport) {
- importError.setDescription(QCoreApplication::translate("QQmlParser","Module import requires a qualifier"));
- importError.setColumn(l.tokenStartColumn());
- *error = importError;
- return rv;
- }
-
- int endOffset = l.tokenLength() + l.tokenOffset();
-
- QString importId = script.mid(l.tokenOffset(), l.tokenLength());
-
- QQmlScript::LocationSpan location =
- locationFromLexer(l, startLine, startColumn, startOffset);
-
- token = l.lex();
-
- if (!importId.at(0).isUpper() || (l.tokenStartLine() == startLine)) {
- importError.setDescription(QCoreApplication::translate("QQmlParser","Invalid import qualifier"));
- importError.setColumn(l.tokenStartColumn());
- *error = importError;
- return rv;
- }
-
- replaceWithSpace(script, startOffset, endOffset - startOffset);
-
- Import import;
- import.type = Import::Library;
- import.uri = uri;
- import.majorVersion = vmaj;
- import.minorVersion = vmin;
- import.qualifier = importId;
- import.location = location;
-
- rv.imports << import;
- }
- } else if (token == QQmlJSGrammar::T_PRAGMA) {
- token = l.lex();
-
- CHECK_TOKEN(T_IDENTIFIER);
- CHECK_LINE;
-
- QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
- int endOffset = l.tokenLength() + l.tokenOffset();
-
- if (pragmaValue == library) {
- pragmas |= QQmlScript::Object::ScriptBlock::Shared;
- replaceWithSpace(script, startOffset, endOffset - startOffset);
- } else {
- return rv;
- }
-
- token = l.lex();
- if (l.tokenStartLine() == startLine)
- return rv;
-
- } else {
- return rv;
- }
- }
- return rv;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h
deleted file mode 100644
index 15446c089f..0000000000
--- a/src/qml/qml/qqmlscript_p.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QQMLSCRIPT_P_H
-#define QQMLSCRIPT_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 <QtQml/qqmlerror.h>
-
-#include <private/qfieldlist_p.h>
-#include <private/qhashfield_p.h>
-#include <private/qqmlpool_p.h>
-#include <private/qqmlpropertycache_p.h>
-
-#include <QtCore/QList>
-#include <QtCore/QUrl>
-
-QT_BEGIN_NAMESPACE
-
-
-class QByteArray;
-class QQmlPropertyCache;
-namespace QQmlJS { class Engine; namespace AST { class Node; class StringLiteral; class UiProgram; class FunctionDeclaration; } }
-
-namespace QQmlScript {
-
-struct Location
-{
- Location() : line(0), column(0) {}
- quint16 line;
- quint16 column;
-
- inline bool operator<(const Location &other) {
- return line < other.line ||
- (line == other.line && column < other.column);
- }
-};
-
-struct LocationRange
-{
- LocationRange() : offset(0), length(0) {}
- quint32 offset;
- quint32 length;
-};
-
-struct LocationSpan
-{
- Location start;
- Location end;
- LocationRange range;
-
- bool operator<(LocationSpan &o) const {
- return (start.line < o.start.line) ||
- (start.line == o.start.line && start.column < o.start.column);
- }
-};
-
-class Import
-{
-public:
- Import() : type(Library), majorVersion(-1), minorVersion(-1) {}
-
- enum Type { Library, File, Script };
- Type type;
-
- QString uri;
- QString qualifier;
-
- int majorVersion;
- int minorVersion;
-
- QQmlScript::LocationSpan location;
-};
-
-class Pragma
-{
-public:
- Pragma() : type(Singleton) {}
-
- enum Type { Singleton };
- Type type;
-
- QQmlScript::LocationSpan location;
-};
-
-class Object;
-class TypeReference : public QQmlPool::Class
-{
-public:
- // type as it has been referenced in Qml
- QString name;
-};
-
-class Object : public QQmlPool::Class
-{
-public:
- // Script blocks that were nested under this object
- struct ScriptBlock {
- enum Pragma {
- None = 0x00000000,
- Shared = 0x00000001
- };
- Q_DECLARE_FLAGS(Pragmas, Pragma)
-
- QString code;
- QString file;
- Pragmas pragmas;
- };
-};
-
-class Q_QML_PRIVATE_EXPORT Parser
-{
-public:
- class JavaScriptMetaData {
- public:
- JavaScriptMetaData()
- : pragmas(QQmlScript::Object::ScriptBlock::None) {}
-
- QQmlScript::Object::ScriptBlock::Pragmas pragmas;
- QList<Import> imports;
- };
-
- static QQmlScript::Object::ScriptBlock::Pragmas extractPragmas(QString &);
- static JavaScriptMetaData extractMetaData(QString &, QQmlError *error);
-};
-
-}
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlScript::Object::ScriptBlock::Pragmas)
-
-QT_END_NAMESPACE
-
-#endif // QQMLSCRIPT_P_H
diff --git a/src/qml/qml/qqmlscriptstring.h b/src/qml/qml/qqmlscriptstring.h
index 9817fdc92c..2c10df6efc 100644
--- a/src/qml/qml/qqmlscriptstring.h
+++ b/src/qml/qml/qqmlscriptstring.h
@@ -77,7 +77,6 @@ private:
friend class QQmlObjectCreator;
friend class QQmlScriptStringPrivate;
- friend class QQmlVME;
friend class QQmlExpression;
friend class QQmlBinding;
};
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 5c48304b56..7fc08bd114 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -51,7 +51,6 @@
#include <private/qqmlcomponent_p.h>
#include <private/qqmlprofiler_p.h>
#include <private/qqmlmemoryprofiler_p.h>
-#include <private/qqmlcodegenerator_p.h>
#include <private/qqmltypecompiler_p.h>
#include <QtCore/qdir.h>
@@ -148,6 +147,7 @@ public:
void loadAsync(QQmlDataBlob *b);
void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
+ void loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
void callCompleted(QQmlDataBlob *b);
void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
void initializeEngine(QQmlExtensionInterface *, const char *);
@@ -158,6 +158,7 @@ protected:
private:
void loadThread(QQmlDataBlob *b);
void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
+ void loadWithCachedUnitThread(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
void callCompletedMain(QQmlDataBlob *b);
void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
@@ -778,6 +779,12 @@ void QQmlDataLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteA
postMethodToThread(&This::loadWithStaticDataThread, b, d);
}
+void QQmlDataLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
void QQmlDataLoaderThread::callCompleted(QQmlDataBlob *b)
{
b->addref();
@@ -816,6 +823,12 @@ void QQmlDataLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByte
b->release();
}
+void QQmlDataLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit)
+{
+ m_loader->loadWithCachedUnitThread(b, unit);
+ b->release();
+}
+
void QQmlDataLoaderThread::callCompletedMain(QQmlDataBlob *b)
{
QML_MEMORY_SCOPE_URL(b->url());
@@ -966,6 +979,28 @@ void QQmlDataLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &da
}
}
+void QQmlDataLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataLoader::loadWithUnitFcatory(%s, data): %s thread", qPrintable(blob->m_url.toString()),
+ m_thread->isThisThread()?"Compile":"Engine");
+#endif
+
+ blob->startLoading(this);
+
+ if (m_thread->isThisThread()) {
+ unlock();
+ loadWithCachedUnitThread(blob, unit);
+ lock();
+ } else {
+ unlock();
+ m_thread->loadWithCachedUnit(blob, unit);
+ lock();
+ if (!blob->isCompleteOrError())
+ blob->m_data.setIsAsync(true);
+ }
+}
+
void QQmlDataLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArray &data)
{
ASSERT_LOADTHREAD();
@@ -973,6 +1008,13 @@ void QQmlDataLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArr
setData(blob, data);
}
+void QQmlDataLoader::loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+{
+ ASSERT_LOADTHREAD();
+
+ setCachedUnit(blob, unit);
+}
+
void QQmlDataLoader::loadThread(QQmlDataBlob *blob)
{
ASSERT_LOADTHREAD();
@@ -1166,6 +1208,24 @@ void QQmlDataLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d)
blob->tryDone();
}
+void QQmlDataLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+{
+ QML_MEMORY_SCOPE_URL(blob->url());
+ blob->m_inCallback = true;
+
+ blob->initializeFromCachedUnit(unit);
+
+ if (!blob->isError() && !blob->isWaiting())
+ blob->allDependenciesDone();
+
+ if (blob->status() != QQmlDataBlob::Error)
+ blob->m_data.setStatus(QQmlDataBlob::WaitingForDependencies);
+
+ blob->m_inCallback = false;
+
+ blob->tryDone();
+}
+
void QQmlDataLoader::shutdownThread()
{
if (!m_thread->isShutdown())
@@ -1173,7 +1233,7 @@ void QQmlDataLoader::shutdownThread()
}
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
- : QQmlDataBlob(url, type), m_typeLoader(loader), m_imports(loader), m_isSingleton(false)
+ : QQmlDataBlob(url, type), m_typeLoader(loader), m_importCache(loader), m_isSingleton(false)
{
}
@@ -1183,7 +1243,7 @@ QQmlTypeLoader::Blob::~Blob()
m_qmldirs.at(ii)->release();
}
-bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QQmlScript::Import *import, int priority, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors)
{
QQmlQmldirData *data = typeLoader()->getQmldir(url);
@@ -1204,17 +1264,17 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QQmlScript::Import
return true;
}
-bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QQmlScript::Import *import, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
{
QString qmldirIdentifier = data->url().toString();
QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1);
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
- if (!m_imports.updateQmldirContent(typeLoader()->importDatabase(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors))
+ if (!m_importCache.updateQmldirContent(typeLoader()->importDatabase(), stringAt(import->uriIndex), stringAt(import->qualifierIndex), qmldirIdentifier, qmldirUrl, errors))
return false;
- QHash<const QQmlScript::Import *, int>::iterator it = m_unresolvedImports.find(import);
+ QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import);
if (it != m_unresolvedImports.end()) {
*it = data->priority();
}
@@ -1222,7 +1282,8 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QQmlScript::
// Release this reference at destruction
m_qmldirs << data;
- if (!import->qualifier.isEmpty()) {
+ const QString &importQualifier = stringAt(import->qualifierIndex);
+ if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier, qmldirUrl);
@@ -1231,43 +1292,45 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QQmlScript::
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
addDependency(blob);
- scriptImported(blob, import->location.start, script.nameSpace, import->qualifier);
+ scriptImported(blob, import->location, script.nameSpace, importQualifier);
}
}
return true;
}
-bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
- if (import.type == QQmlScript::Import::Script) {
- QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
+ const QString &importUri = stringAt(import->uriIndex);
+ const QString &importQualifier = stringAt(import->qualifierIndex);
+ if (import->type == QV4::CompiledData::Import::ImportScript) {
+ QUrl scriptUrl = finalUrl().resolved(QUrl(importUri));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
addDependency(blob);
- scriptImported(blob, import.location.start, import.qualifier, QString());
- } else if (import.type == QQmlScript::Import::Library) {
+ scriptImported(blob, import->location, importQualifier, QString());
+ } else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
QString qmldirFilePath;
QString qmldirUrl;
- if (QQmlMetaType::isLockedModule(import.uri, import.majorVersion)) {
+ if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) {
//Locked modules are checked first, to save on filesystem checks
- if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion,
- import.minorVersion, QString(), QString(), false, errors))
+ if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ import->minorVersion, QString(), QString(), false, errors))
return false;
- } else if (m_imports.locateQmldir(importDatabase, import.uri, import.majorVersion, import.minorVersion,
+ } else if (m_importCache.locateQmldir(importDatabase, importUri, import->majorVersion, import->minorVersion,
&qmldirFilePath, &qmldirUrl)) {
// This is a local library import
- if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion,
- import.minorVersion, qmldirFilePath, qmldirUrl, false, errors))
+ if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ import->minorVersion, qmldirFilePath, qmldirUrl, false, errors))
return false;
- if (!import.qualifier.isEmpty()) {
+ if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath, qmldirUrl);
@@ -1276,34 +1339,34 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
addDependency(blob);
- scriptImported(blob, import.location.start, script.nameSpace, import.qualifier);
+ scriptImported(blob, import->location, script.nameSpace, importQualifier);
}
}
} else {
// Is this a module?
- if (QQmlMetaType::isAnyModule(import.uri)) {
- if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion,
- import.minorVersion, QString(), QString(), false, errors))
+ if (QQmlMetaType::isAnyModule(importUri)) {
+ if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ import->minorVersion, QString(), QString(), false, errors))
return false;
} else {
// We haven't yet resolved this import
- m_unresolvedImports.insert(&import, 0);
+ m_unresolvedImports.insert(import, 0);
// Query any network import paths for this library
QStringList remotePathList = importDatabase->importPathList(QQmlImportDatabase::Remote);
if (!remotePathList.isEmpty()) {
// Add this library and request the possible locations for it
- if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion,
- import.minorVersion, QString(), QString(), true, errors))
+ if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ import->minorVersion, QString(), QString(), true, errors))
return false;
// Probe for all possible locations
int priority = 0;
for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) {
foreach (const QString &path, remotePathList) {
- QString qmldirUrl = QQmlImports::completeQmldirPath(import.uri, path, import.majorVersion, import.minorVersion,
+ QString qmldirUrl = QQmlImports::completeQmldirPath(importUri, path, import->majorVersion, import->minorVersion,
static_cast<QQmlImports::ImportVersion>(version));
- if (!fetchQmldir(QUrl(qmldirUrl), &import, ++priority, errors))
+ if (!fetchQmldir(QUrl(qmldirUrl), import, ++priority, errors))
return false;
}
}
@@ -1311,25 +1374,25 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm
}
}
} else {
- Q_ASSERT(import.type == QQmlScript::Import::File);
+ Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile);
bool incomplete = false;
QUrl qmldirUrl;
- if (import.qualifier.isEmpty()) {
- qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
+ 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;
}
}
- if (!m_imports.addFileImport(importDatabase, import.uri, import.qualifier, import.majorVersion,
- import.minorVersion, incomplete, errors))
+ if (!m_importCache.addFileImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ import->minorVersion, incomplete, errors))
return false;
if (incomplete) {
- if (!fetchQmldir(qmldirUrl, &import, 1, errors))
+ if (!fetchQmldir(qmldirUrl, import, 1, errors))
return false;
}
}
@@ -1337,11 +1400,11 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm
return true;
}
-bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
- if (pragma.type == QQmlScript::Pragma::Singleton) {
+ if (pragma.type == QmlIR::Pragma::PragmaSingleton) {
QUrl myUrl = finalUrl();
QQmlType *ret = QQmlMetaType::qmlType(myUrl, true);
@@ -1349,8 +1412,8 @@ bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQm
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.start.line);
- error.setColumn(pragma.location.start.column);
+ error.setLine(pragma.location.line);
+ error.setColumn(pragma.location.column);
errors->prepend(error);
return false;
}
@@ -1359,8 +1422,8 @@ bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQm
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.start.line);
- error.setColumn(pragma.location.start.column);
+ error.setLine(pragma.location.line);
+ error.setColumn(pragma.location.column);
errors->prepend(error);
return false;
}
@@ -1371,8 +1434,8 @@ bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQm
QQmlError error;
error.setDescription(QLatin1String("Invalid pragma"));
error.setUrl(finalUrl());
- error.setLine(pragma.location.start.line);
- error.setColumn(pragma.location.start.column);
+ error.setLine(pragma.location.line);
+ error.setColumn(pragma.location.column);
errors->prepend(error);
return false;
}
@@ -1395,15 +1458,15 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
if (blob->type() == QQmlDataBlob::QmldirFile) {
QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob);
- const QQmlScript::Import *import = data->import();
+ const QV4::CompiledData::Import *import = data->import();
QList<QQmlError> errors;
if (!qmldirDataAvailable(data, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
- error.setUrl(m_imports.baseUrl());
- error.setLine(import->location.start.line);
- error.setColumn(import->location.start.column);
+ 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);
}
@@ -1414,7 +1477,7 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
{
bool resolve = true;
- const QQmlScript::Import *import = data->import();
+ const QV4::CompiledData::Import *import = data->import();
data->setImport(0);
int priority = data->priority();
@@ -1422,7 +1485,7 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
if (import) {
// Do we need to resolve this import?
- QHash<const QQmlScript::Import *, int>::iterator it = m_unresolvedImports.find(import);
+ QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import);
if (it != m_unresolvedImports.end()) {
resolve = (*it == 0) || (*it > priority);
}
@@ -1537,7 +1600,11 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
typeData = new QQmlTypeData(url, this);
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
- QQmlDataLoader::load(typeData, mode);
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) {
+ QQmlDataLoader::loadWithCachedUnit(typeData, cachedUnit);
+ } else {
+ QQmlDataLoader::load(typeData, mode);
+ }
}
typeData->addref();
@@ -1575,7 +1642,12 @@ QQmlScriptBlob *QQmlTypeLoader::getScript(const QUrl &url)
if (!scriptBlob) {
scriptBlob = new QQmlScriptBlob(url, this);
m_scriptCache.insert(url, scriptBlob);
- QQmlDataLoader::load(scriptBlob);
+
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) {
+ QQmlDataLoader::loadWithCachedUnit(scriptBlob, cachedUnit);
+ } else {
+ QQmlDataLoader::load(scriptBlob);
+ }
}
scriptBlob->addref();
@@ -1985,7 +2057,6 @@ QQmlTypeData::~QQmlTypeData()
if (m_compiledData)
m_compiledData->release();
- delete m_implicitImport;
}
const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
@@ -2045,7 +2116,7 @@ void QQmlTypeData::done()
const TypeReference &type = *it;
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
if (type.typeData && type.typeData->isError()) {
- QString typeName = parsedQML->jsGenerator.strings.at(it.key());
+ QString typeName = m_document->stringAt(it.key());
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
@@ -2092,7 +2163,8 @@ void QQmlTypeData::done()
if (!isError())
compile();
- parsedQML.reset();
+ m_document.reset();
+ m_implicitImport = 0;
}
void QQmlTypeData::completed()
@@ -2108,14 +2180,14 @@ bool QQmlTypeData::loadImplicitImport()
{
m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error)
- m_imports.setBaseUrl(finalUrl(), finalUrlString());
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
// For local urls, add an implicit import "." as most overridden lookup.
// This will also trigger the loading of the qmldir and the import of any native
// types from available plugins.
QList<QQmlError> implicitImportErrors;
- m_imports.addImplicitImport(importDatabase, &implicitImportErrors);
+ m_importCache.addImplicitImport(importDatabase, &implicitImportErrors);
if (!implicitImportErrors.isEmpty()) {
setError(implicitImportErrors);
@@ -2133,14 +2205,37 @@ void QQmlTypeData::dataReceived(const Data &data)
if (data.isFile()) preparseData = data.asFile()->metaData(QLatin1String("qml:preparse"));
QQmlEngine *qmlEngine = typeLoader()->engine();
- parsedQML.reset(new QtQml::ParsedQML(QV8Engine::getV4(qmlEngine)->debugger != 0));
- QQmlCodeGenerator compiler(QV8Engine::get(qmlEngine)->illegalNames());
- if (!compiler.generateFromQml(code, finalUrl(), finalUrlString(), parsedQML.data())) {
- setError(compiler.errors);
+ m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0));
+ QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames());
+ if (!compiler.generateFromQml(code, finalUrlString(), finalUrlString(), m_document.data())) {
+ QList<QQmlError> errors;
+ foreach (const QQmlJS::DiagnosticMessage &msg, compiler.errors) {
+ QQmlError e;
+ e.setUrl(finalUrl());
+ e.setLine(msg.loc.startLine);
+ e.setColumn(msg.loc.startColumn);
+ e.setDescription(msg.message);
+ errors << e;
+ }
+ setError(errors);
return;
}
- m_imports.setBaseUrl(finalUrl(), finalUrlString());
+ 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();
+}
+
+void QQmlTypeData::continueLoadFromIR()
+{
+ m_document->collectTypeReferences();
+ 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
@@ -2151,9 +2246,10 @@ void QQmlTypeData::dataReceived(const Data &data)
if (!loadImplicitImport())
return;
// This qmldir is for the implicit import
- m_implicitImport = new QQmlScript::Import;
- m_implicitImport->uri = QLatin1String(".");
- m_implicitImport->qualifier = QString();
+ 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;
QList<QQmlError> errors;
@@ -2167,62 +2263,21 @@ void QQmlTypeData::dataReceived(const Data &data)
QList<QQmlError> errors;
- // ### convert to use new data structure once old compiler is gone.
- if (m_newImports.isEmpty()) {
- m_newImports.reserve(parsedQML->imports.size());
- foreach (QV4::CompiledData::Import *i, parsedQML->imports) {
- QQmlScript::Import import;
- import.uri = parsedQML->stringAt(i->uriIndex);
- import.qualifier = parsedQML->stringAt(i->qualifierIndex);
- import.majorVersion = i->majorVersion;
- import.minorVersion = i->minorVersion;
- import.location.start.line = i->location.line;
- import.location.start.column = i->location.column;
-
- switch (i->type) {
- case QV4::CompiledData::Import::ImportFile: import.type = QQmlScript::Import::File; break;
- case QV4::CompiledData::Import::ImportLibrary: import.type = QQmlScript::Import::Library; break;
- case QV4::CompiledData::Import::ImportScript: import.type = QQmlScript::Import::Script; break;
- default: break;
- }
-
-
- m_newImports << import;
- }
- }
-
- foreach (const QQmlScript::Import &import, m_newImports) {
+ foreach (const QV4::CompiledData::Import *import, m_document->imports) {
if (!addImport(import, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
- error.setUrl(m_imports.baseUrl());
- error.setLine(import.location.start.line);
- error.setColumn(import.location.start.column);
+ 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;
}
}
- // ### convert to use new data structure once old compiler is gone.
- if (m_newPragmas.isEmpty()) {
- m_newPragmas.reserve(parsedQML->pragmas.size());
- foreach (QtQml::Pragma *p, parsedQML->pragmas) {
- QQmlScript::Pragma pragma;
- pragma.location.start.line = p->location.line;
- pragma.location.start.column = p->location.column;
-
- switch (p->type) {
- case QtQml::Pragma::PragmaSingleton: pragma.type = QQmlScript::Pragma::Singleton; break;
- default: break;
- }
-
- m_newPragmas << pragma;
- }
- }
-
- foreach (const QQmlScript::Pragma &pragma, m_newPragmas) {
- if (!addPragma(pragma, &errors)) {
+ foreach (QmlIR::Pragma *pragma, m_document->pragmas) {
+ if (!addPragma(*pragma, &errors)) {
Q_ASSERT(errors.size());
setError(errors);
return;
@@ -2235,16 +2290,16 @@ void QQmlTypeData::allDependenciesDone()
if (!m_typesResolved) {
// Check that all imports were resolved
QList<QQmlError> errors;
- QHash<const QQmlScript::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
+ QHash<const QV4::CompiledData::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
for ( ; it != end; ++it) {
if (*it == 0) {
// This import was not resolved
- foreach (const QQmlScript::Import *import, m_unresolvedImports.keys()) {
+ foreach (const QV4::CompiledData::Import *import, m_unresolvedImports.keys()) {
QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
- error.setUrl(m_imports.baseUrl());
- error.setLine(import->location.start.line);
- error.setColumn(import->location.start.column);
+ error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(stringAt(import->uriIndex)));
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
errors.prepend(error);
}
}
@@ -2267,6 +2322,11 @@ void QQmlTypeData::downloadProgressChanged(qreal p)
}
}
+QString QQmlTypeData::stringAt(int index) const
+{
+ return m_document->jsGenerator.stringTable.stringForIndex(index);
+}
+
void QQmlTypeData::compile()
{
Q_ASSERT(m_compiledData == 0);
@@ -2277,7 +2337,7 @@ void QQmlTypeData::compile()
QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, m_compiledData->name);
- QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, parsedQML.data());
+ QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data());
if (!compiler.compile()) {
setError(compiler.compilationErrors());
m_compiledData->release();
@@ -2288,7 +2348,7 @@ void QQmlTypeData::compile()
void QQmlTypeData::resolveTypes()
{
// Add any imported scripts to our resolved set
- foreach (const QQmlImports::ScriptReference &script, m_imports.resolvedScripts())
+ foreach (const QQmlImports::ScriptReference &script, m_importCache.resolvedScripts())
{
QQmlScriptBlob *blob = typeLoader()->getScript(script.location);
addDependency(blob);
@@ -2309,13 +2369,12 @@ void QQmlTypeData::resolveTypes()
}
// Lets handle resolved composite singleton types
- foreach (const QQmlImports::CompositeSingletonReference &csRef, m_imports.resolvedCompositeSingletons()) {
+ foreach (const QQmlImports::CompositeSingletonReference &csRef, m_importCache.resolvedCompositeSingletons()) {
TypeReference ref;
- QQmlScript::TypeReference parserRef;
- parserRef.name = csRef.typeName;
+ QString typeName = csRef.typeName;
if (!csRef.prefix.isEmpty()) {
- parserRef.name.prepend(csRef.prefix + QLatin1Char('.'));
+ typeName.prepend(csRef.prefix + QLatin1Char('.'));
// Add a reference to the enclosing namespace
m_namespaces.insert(csRef.prefix);
}
@@ -2323,7 +2382,7 @@ void QQmlTypeData::resolveTypes()
int majorVersion = -1;
int minorVersion = -1;
- if (!resolveType(&parserRef, majorVersion, minorVersion, ref))
+ if (!resolveType(typeName, majorVersion, minorVersion, ref))
return;
if (ref.type->isCompositeSingleton()) {
@@ -2335,15 +2394,7 @@ void QQmlTypeData::resolveTypes()
}
}
- QV4::CompiledData::TypeReferenceMap typeReferences;
- QStringList names;
- if (parsedQML) {
- typeReferences = parsedQML->typeReferences;
- names = parsedQML->jsGenerator.strings;
- } else {
- // ### collect from available QV4::CompiledData::QmlUnit
- }
- for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = typeReferences.constBegin(), end = typeReferences.constEnd();
+ for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_document->typeReferences.constBegin(), end = m_document->typeReferences.constEnd();
unresolvedRef != end; ++unresolvedRef) {
TypeReference ref; // resolved reference
@@ -2355,15 +2406,15 @@ void QQmlTypeData::resolveTypes()
QQmlImportNamespace *typeNamespace = 0;
QList<QQmlError> errors;
- const QString name = names.at(unresolvedRef.key());
- bool typeFound = m_imports.resolveType(name, &ref.type,
+ const QString name = stringAt(unresolvedRef.key());
+ bool typeFound = m_importCache.resolveType(name, &ref.type,
&majorVersion, &minorVersion, &typeNamespace, &errors);
if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
// Lazy loading of implicit import
if (loadImplicitImport()) {
// Try again to find the type
errors.clear();
- typeFound = m_imports.resolveType(name, &ref.type,
+ typeFound = m_importCache.resolveType(name, &ref.type,
&majorVersion, &minorVersion, &typeNamespace, &errors);
} else {
return; //loadImplicitImport() hit an error, and called setError already
@@ -2385,7 +2436,7 @@ void QQmlTypeData::resolveTypes()
// Description should come from error provided by addImport() function.
error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
}
- error.setUrl(m_imports.baseUrl());
+ error.setUrl(m_importCache.baseUrl());
error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(name).arg(error.description()));
}
@@ -2413,19 +2464,19 @@ void QQmlTypeData::resolveTypes()
}
}
-bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int &majorVersion, int &minorVersion, TypeReference &ref)
+bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref)
{
QQmlImportNamespace *typeNamespace = 0;
QList<QQmlError> errors;
- bool typeFound = m_imports.resolveType(parserRef->name, &ref.type,
+ bool typeFound = m_importCache.resolveType(typeName, &ref.type,
&majorVersion, &minorVersion, &typeNamespace, &errors);
if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
// Lazy loading of implicit import
if (loadImplicitImport()) {
// Try again to find the type
errors.clear();
- typeFound = m_imports.resolveType(parserRef->name, &ref.type,
+ typeFound = m_importCache.resolveType(typeName, &ref.type,
&majorVersion, &minorVersion, &typeNamespace, &errors);
} else {
return false; //loadImplicitImport() hit an error, and called setError already
@@ -2438,7 +2489,7 @@ bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int &
// - type with unknown namespace (UnknownNamespace.SomeType {})
QQmlError error;
if (typeNamespace) {
- error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(parserRef->name));
+ error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName));
} else {
if (errors.size()) {
error = errors.takeFirst();
@@ -2447,8 +2498,8 @@ bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int &
// Description should come from error provided by addImport() function.
error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
}
- error.setUrl(m_imports.baseUrl());
- error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(parserRef->name).arg(error.description()));
+ error.setUrl(m_importCache.baseUrl());
+ error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
}
errors.prepend(error);
@@ -2459,7 +2510,7 @@ bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int &
return true;
}
-void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
+void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
{
ScriptReference ref;
ref.script = blob;
@@ -2471,7 +2522,6 @@ void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Locati
QQmlScriptData::QQmlScriptData()
: importCache(0)
- , pragmas(QQmlScript::Object::ScriptBlock::None)
, m_loaded(false)
, m_precompiledScript(0)
, m_program(0)
@@ -2517,7 +2567,7 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare
QV4::ExecutionEngine *v4 = QV8Engine::getV4(parentCtxt->engine);
QV4::Scope scope(v4);
- bool shared = pragmas & QQmlScript::Object::ScriptBlock::Shared;
+ bool shared = m_precompiledScript->data->flags & QV4::CompiledData::Unit::IsSharedLibrary;
QQmlContextData *effectiveCtxt = parentCtxt;
if (shared)
@@ -2621,11 +2671,6 @@ QQmlScriptBlob::~QQmlScriptBlob()
}
}
-QQmlScript::Object::ScriptBlock::Pragmas QQmlScriptBlob::pragmas() const
-{
- return m_metadata.pragmas;
-}
-
QQmlScriptData *QQmlScriptBlob::scriptData() const
{
return m_scriptData;
@@ -2633,36 +2678,49 @@ QQmlScriptData *QQmlScriptBlob::scriptData() const
void QQmlScriptBlob::dataReceived(const Data &data)
{
- m_source = QString::fromUtf8(data.data(), data.size());
+ QString source = QString::fromUtf8(data.data(), data.size());
- m_scriptData = new QQmlScriptData();
- m_scriptData->url = finalUrl();
- m_scriptData->urlString = finalUrlString();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
+ QmlIR::Document irUnit(v4->debugger != 0);
+ QQmlJS::DiagnosticMessage metaDataError;
+ irUnit.extractScriptMetaData(source, &metaDataError);
+ if (!metaDataError.message.isEmpty()) {
+ QQmlError e;
+ e.setUrl(finalUrl());
+ e.setLine(metaDataError.loc.startLine);
+ e.setColumn(metaDataError.loc.startColumn);
+ e.setDescription(metaDataError.message);
+ setError(e);
+ return;
+ }
- QQmlError metaDataError;
- m_metadata = QQmlScript::Parser::extractMetaData(m_source, &metaDataError);
- if (metaDataError.isValid()) {
- metaDataError.setUrl(finalUrl());
- setError(metaDataError);
+ QList<QQmlError> errors;
+ QV4::CompiledData::CompilationUnit *unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors);
+ if (unit)
+ unit->ref();
+ source.clear();
+ if (!errors.isEmpty()) {
+ if (unit)
+ unit->deref();
+ setError(errors);
return;
}
+ irUnit.javaScriptCompilationUnit = unit;
- m_imports.setBaseUrl(finalUrl(), finalUrlString());
+ QmlIR::QmlUnitGenerator qmlGenerator;
+ QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(irUnit);
+ Q_ASSERT(!unit->data);
+ Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
+ // The js unit owns the data and will free the qml unit.
+ unit->data = &qmlUnit->header;
- QList<QQmlError> errors;
+ initializeFromCompilationUnit(unit);
+ unit->deref();
+}
- foreach (const QQmlScript::Import &import, m_metadata.imports) {
- if (!addImport(import, &errors)) {
- Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_imports.baseUrl());
- error.setLine(import.location.start.line);
- error.setColumn(import.location.start.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
- return;
- }
- }
+void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
+{
+ initializeFromCompilationUnit(unit->createCompilationUnit());
}
void QQmlScriptBlob::done()
@@ -2704,23 +2762,15 @@ void QQmlScriptBlob::done()
m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_imports.populateCache(m_scriptData->importCache);
-
- m_scriptData->pragmas = m_metadata.pragmas;
+ m_importCache.populateCache(m_scriptData->importCache);
+}
- QList<QQmlError> errors;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
- m_scriptData->m_precompiledScript = QV4::Script::precompile(v4, m_scriptData->url, m_source, &errors);
- if (m_scriptData->m_precompiledScript)
- m_scriptData->m_precompiledScript->ref();
- m_source.clear();
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
+QString QQmlScriptBlob::stringAt(int index) const
+{
+ return m_scriptData->m_precompiledScript->data->stringAt(index);
}
-void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace)
+void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
{
ScriptReference ref;
ref.script = blob;
@@ -2731,6 +2781,37 @@ void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Loca
m_scripts << ref;
}
+void QQmlScriptBlob::initializeFromCompilationUnit(QV4::CompiledData::CompilationUnit *unit)
+{
+ Q_ASSERT(!m_scriptData);
+ m_scriptData = new QQmlScriptData();
+ m_scriptData->url = finalUrl();
+ m_scriptData->urlString = finalUrlString();
+ m_scriptData->m_precompiledScript = unit;
+ if (m_scriptData->m_precompiledScript)
+ m_scriptData->m_precompiledScript->ref();
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ Q_ASSERT(m_scriptData->m_precompiledScript->data->flags & QV4::CompiledData::Unit::IsQml);
+ const QV4::CompiledData::QmlUnit *qmlUnit = reinterpret_cast<const QV4::CompiledData::QmlUnit*>(m_scriptData->m_precompiledScript->data);
+
+ QList<QQmlError> errors;
+ for (quint32 i = 0; i < qmlUnit->nImports; ++i) {
+ const QV4::CompiledData::Import *import = qmlUnit->importAt(i);
+ 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;
+ }
+ }
+}
+
QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
: QQmlTypeLoader::Blob(url, QmldirFile, loader), m_import(0), m_priority(0)
{
@@ -2741,12 +2822,12 @@ const QString &QQmlQmldirData::content() const
return m_content;
}
-const QQmlScript::Import *QQmlQmldirData::import() const
+const QV4::CompiledData::Import *QQmlQmldirData::import() const
{
return m_import;
}
-void QQmlQmldirData::setImport(const QQmlScript::Import *import)
+void QQmlQmldirData::setImport(const QV4::CompiledData::Import *import)
{
m_import = import;
}
@@ -2766,6 +2847,11 @@ void QQmlQmldirData::dataReceived(const Data &data)
m_content = QString::fromUtf8(data.data(), data.size());
}
+void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *)
+{
+ Q_UNIMPLEMENTED();
+}
+
QT_END_NAMESPACE
#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 9cd28a03ce..b09ac15861 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -62,12 +62,12 @@
#include <QtQml/qqmlabstracturlinterceptor.h>
#include <private/qhashedstring_p.h>
-#include <private/qqmlscript_p.h>
#include <private/qqmlimport_p.h>
#include <private/qqmlcleanup_p.h>
#include <private/qqmldirparser_p.h>
#include <private/qqmlbundle_p.h>
#include <private/qflagpointer_p.h>
+#include <private/qqmlirbuilder_p.h>
#include <private/qv4value_inl_p.h>
#include <private/qv4script_p.h>
@@ -84,8 +84,8 @@ class QQmlTypeData;
class QQmlDataLoader;
class QQmlExtensionInterface;
-namespace QtQml {
-struct ParsedQML;
+namespace QmlIR {
+struct Document;
}
class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
@@ -155,6 +155,7 @@ protected:
// Callbacks made in load thread
virtual void dataReceived(const Data &) = 0;
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0;
virtual void done();
virtual void networkError(QNetworkReply::NetworkError);
virtual void dependencyError(QQmlDataBlob *);
@@ -228,6 +229,7 @@ public:
void load(QQmlDataBlob *, Mode = PreferSynchronous);
void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
+ void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
QQmlEngine *engine() const;
void initializeEngine(QQmlExtensionInterface *, const char *);
@@ -242,6 +244,7 @@ private:
void loadThread(QQmlDataBlob *);
void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
+ void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
void networkReplyFinished(QNetworkReply *);
void networkReplyProgress(QNetworkReply *, qint64, qint64);
@@ -250,6 +253,7 @@ private:
void setData(QQmlDataBlob *, const QByteArray &);
void setData(QQmlDataBlob *, QQmlFile *);
void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
+ void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
QQmlEngine *m_engine;
QQmlDataLoaderThread *m_thread;
@@ -275,28 +279,30 @@ public:
~Blob();
QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
- const QQmlImports &imports() const { return m_imports; }
+ const QQmlImports &imports() const { return m_importCache; }
protected:
- bool addImport(const QQmlScript::Import &import, QList<QQmlError> *errors);
- bool addPragma(const QQmlScript::Pragma &pragma, QList<QQmlError> *errors);
+ 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 QQmlScript::Import *import, int priority, QList<QQmlError> *errors);
- bool updateQmldir(QQmlQmldirData *data, const QQmlScript::Import *import, 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);
private:
virtual bool qmldirDataAvailable(QQmlQmldirData *, QList<QQmlError> *);
- virtual void scriptImported(QQmlScriptBlob *, const QQmlScript::Location &, const QString &, const QString &) {}
+ virtual void scriptImported(QQmlScriptBlob *, const QV4::CompiledData::Location &, const QString &, const QString &) {}
virtual void dependencyError(QQmlDataBlob *);
virtual void dependencyComplete(QQmlDataBlob *);
protected:
+ virtual QString stringAt(int) const { return QString(); }
+
QQmlTypeLoader *m_typeLoader;
- QQmlImports m_imports;
+ QQmlImports m_importCache;
bool m_isSingleton;
- QHash<const QQmlScript::Import *, int> m_unresolvedImports;
+ QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
QList<QQmlQmldirData *> m_qmldirs;
};
@@ -398,7 +404,7 @@ public:
{
TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0), needsCreation(true) {}
- QQmlScript::Location location;
+ QV4::CompiledData::Location location;
QQmlType *type;
int majorVersion;
int minorVersion;
@@ -411,7 +417,7 @@ public:
{
ScriptReference() : script(0) {}
- QQmlScript::Location location;
+ QV4::CompiledData::Location location;
QString qualifier;
QQmlScriptBlob *script;
};
@@ -445,19 +451,21 @@ 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);
+ virtual QString stringAt(int index) const;
+
private:
+ void continueLoadFromIR();
void resolveTypes();
void compile();
- bool resolveType(const QQmlScript::TypeReference *parserRef, int &majorVersion, int &minorVersion, TypeReference &ref);
+ bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref);
- virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
+ virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace);
- QScopedPointer<QtQml::ParsedQML> parsedQML;
- QList<QQmlScript::Import> m_newImports;
- QList<QQmlScript::Pragma> m_newPragmas;
+ QScopedPointer<QmlIR::Document> m_document;
QList<ScriptReference> m_scripts;
@@ -472,7 +480,7 @@ private:
QList<TypeDataCallback *> m_callbacks;
- QQmlScript::Import *m_implicitImport;
+ QV4::CompiledData::Import *m_implicitImport;
bool m_implicitImportLoaded;
bool loadImplicitImport();
};
@@ -498,7 +506,6 @@ public:
QString urlString;
QQmlTypeNameCache *importCache;
QList<QQmlScriptBlob *> scripts;
- QQmlScript::Object::ScriptBlock::Pragmas pragmas;
QV4::PersistentValue scriptValueForContext(QQmlContextData *parentCtxt);
@@ -506,7 +513,6 @@ protected:
virtual void clear(); // From QQmlCleanup
private:
- friend class QQmlVME;
friend class QQmlScriptBlob;
void initialize(QQmlEngine *);
@@ -531,25 +537,24 @@ public:
{
ScriptReference() : script(0) {}
- QQmlScript::Location location;
+ QV4::CompiledData::Location location;
QString qualifier;
QString nameSpace;
QQmlScriptBlob *script;
};
- QQmlScript::Object::ScriptBlock::Pragmas pragmas() const;
-
QQmlScriptData *scriptData() const;
protected:
virtual void dataReceived(const Data &);
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit);
virtual void done();
-private:
- virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
+ virtual QString stringAt(int index) const;
- QString m_source;
- QQmlScript::Parser::JavaScriptMetaData m_metadata;
+private:
+ virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace);
+ void initializeFromCompilationUnit(QV4::CompiledData::CompilationUnit *unit);
QList<ScriptReference> m_scripts;
QQmlScriptData *m_scriptData;
@@ -565,18 +570,19 @@ private:
public:
const QString &content() const;
- const QQmlScript::Import *import() const;
- void setImport(const QQmlScript::Import *);
+ const QV4::CompiledData::Import *import() const;
+ void setImport(const QV4::CompiledData::Import *);
int priority() const;
void setPriority(int);
protected:
virtual void dataReceived(const Data &);
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*);
private:
QString m_content;
- const QQmlScript::Import *m_import;
+ const QV4::CompiledData::Import *m_import;
int m_priority;
};
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index e599c37c0c..1ff95a245d 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -615,7 +615,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
QQmlVMEMetaData::MethodData *data = metaData->methodData() + index;
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[data->runtimeFunctionIndex];
- o = QV4::FunctionObject::creatScriptFunction(qmlBindingContext, runtimeFunction);
+ o = QV4::FunctionObject::createScriptFunction(qmlBindingContext, runtimeFunction);
v8methods[index] = o;
}
}
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index e2cdac16c0..d89dc92b68 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -905,8 +905,11 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty
{
QV4::ExecutionEngine *v4 = m->engine();
NamedNodeMap *r = m->as<NamedNodeMap>();
- if (!r)
+ if (!r) {
+ if (hasProperty)
+ *hasProperty = false;
return v4->currentContext()->throwTypeError();
+ }
QV8Engine *engine = v4->v8Engine;
@@ -960,8 +963,11 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty)
{
QV4::ExecutionEngine *v4 = m->engine();
NodeList *r = m->as<NodeList>();
- if (!r)
+ if (!r) {
+ if (hasProperty)
+ *hasProperty = false;
return v4->currentContext()->throwTypeError();
+ }
QV8Engine *engine = v4->v8Engine;
@@ -1388,7 +1394,8 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
error == QNetworkReply::ContentNotFoundError ||
error == QNetworkReply::AuthenticationRequiredError ||
error == QNetworkReply::ContentReSendError ||
- error == QNetworkReply::UnknownContentError) {
+ error == QNetworkReply::UnknownContentError ||
+ error == QNetworkReply::ProtocolInvalidOperationError) {
m_state = Loading;
dispatchCallback(me);
} else {
@@ -1650,6 +1657,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
QQmlXMLHttpRequestCtor *c = that->as<QQmlXMLHttpRequestCtor>();
if (c->proto)
c->proto->mark(e);
+ FunctionObject::markObjects(that, e);
}
static ReturnedValue construct(Managed *that, QV4::CallData *)
{
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 61b466a5db..8305649177 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -601,7 +601,11 @@ QV4::ReturnedValue QV8Engine::variantMapToJS(const QVariantMap &vmap)
for (it = vmap.constBegin(); it != vmap.constEnd(); ++it) {
s = m_v4Engine->newIdentifier(it.key());
v = variantToJS(it.value());
- o->insertMember(s, v);
+ uint idx = s->asArrayIndex();
+ if (idx < UINT_MAX)
+ o->arraySet(idx, v);
+ else
+ o->insertMember(s, v);
}
return o.asReturnedValue();
}
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
index 564540e147..e1900b72c3 100644
--- a/src/qml/qtqmlglobal_p.h
+++ b/src/qml/qtqmlglobal_p.h
@@ -55,6 +55,10 @@
#include "qtqmlglobal.h"
-#define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
+#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+# define Q_QML_PRIVATE_EXPORT
+#else
+# define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
+#endif
#endif // QTQMLGLOBAL_P_H
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index f6da64f913..88080b1895 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -113,12 +113,12 @@ public:
of the binding is undefined when the mouse isn't pressed. We can use the Binding
type to rewrite the above code and avoid the warning.
- \qml
+ \code
Binding on value {
when: mouse.pressed
value: mouse.mouseX
}
- \endqml
+ \endcode
The Binding type will also restore any previously set direct bindings on
the property. In that sense, it functions much like a simplified State.
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 122056e653..99ec0b55de 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -46,6 +46,7 @@
#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>
@@ -68,6 +69,7 @@ public:
bool componentcomplete;
QByteArray data;
+ QQmlRefPointer<QQmlCompiledData> cdata;
};
/*!
@@ -203,17 +205,14 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore)
d->ignoreUnknownSignals = ignore;
}
-QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &props)
+QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
{
- Q_UNUSED(objectIndex)
QByteArray rv;
QDataStream ds(&rv, QIODevice::WriteOnly);
for (int ii = 0; ii < props.count(); ++ii) {
const QV4::CompiledData::Binding *binding = props.at(ii);
QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex);
- int propLine = binding->location.line;
- int propColumn = binding->location.column;
if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
@@ -233,21 +232,19 @@ QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlU
return QByteArray();
} else {
ds << propName;
- ds << binding->valueAsString(&qmlUnit->header);
- ds << propLine;
- ds << propColumn;
+ ds << bindingIdentifier(binding);
}
}
return rv;
}
-void QQmlConnectionsParser::setCustomData(QObject *object,
- const QByteArray &data)
+void QQmlConnectionsParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *cdata)
{
QQmlConnectionsPrivate *p =
static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object));
p->data = data;
+ p->cdata = cdata;
}
@@ -261,12 +258,8 @@ void QQmlConnections::connectSignals()
while (!ds.atEnd()) {
QString propName;
ds >> propName;
- QString script;
- ds >> script;
- int line;
- ds >> line;
- int column;
- ds >> column;
+ int bindingId;
+ ds >> bindingId;
QQmlProperty prop(target(), propName);
if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
@@ -274,19 +267,15 @@ void QQmlConnections::connectSignals()
QQmlBoundSignal *signal =
new QQmlBoundSignal(target(), signalIndex, this, qmlEngine(this));
- QString location;
QQmlContextData *ctxtdata = 0;
QQmlData *ddata = QQmlData::get(this);
if (ddata) {
ctxtdata = ddata->outerContext;
- if (ctxtdata && !ctxtdata->url.isEmpty())
- location = ddata->outerContext->urlString;
}
QQmlBoundSignalExpression *expression = ctxtdata ?
new QQmlBoundSignalExpression(target(), signalIndex,
- ctxtdata, this, script,
- location, line, column) : 0;
+ ctxtdata, this, d->cdata->functionForBindingId(bindingId)) : 0;
signal->takeExpression(expression);
d->boundsignals += signal;
} else {
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index f9b664cccf..f169eeb53f 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -84,8 +84,8 @@ private:
class QQmlConnectionsParser : public QQmlCustomParser
{
public:
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &props);
- virtual void setCustomData(QObject *, const QByteArray &);
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
+ virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata);
};
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 910cec9087..be479ee17d 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1136,7 +1136,7 @@ static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const
incubationTask->index[i] += deltas[i];
}
if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < count; ++i)
+ for (int i = 1; i < qMin<int>(count, Compositor::MaximumGroupCount); ++i)
attached->m_currentIndex[i] += deltas[i];
}
}
@@ -2005,7 +2005,7 @@ QQmlDelegateModelAttached::QQmlDelegateModelAttached(
{
QQml_setParent_noEvent(this, parent);
if (QQDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
+ for (int i = 1; i < qMin<int>(m_cacheItem->metaType->groupCount, Compositor::MaximumGroupCount); ++i)
m_currentIndex[i] = m_previousIndex[i] = incubationTask->index[i];
} else {
QQmlDelegateModelPrivate * const model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model);
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 32b1154d30..7da089c9b8 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -144,7 +144,7 @@ public:
QQmlDelegateModelItemMetaType * const metaType;
QQmlContextData *contextData;
QObject *object;
- QQmlDelegateModelAttached *attached;
+ QPointer<QQmlDelegateModelAttached> attached;
QQDMIncubationTask *incubationTask;
int objectRef;
int scriptRef;
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 37742a3667..0056276d52 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -47,7 +47,6 @@
#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlscript_p.h>
#include <private/qqmlengine_p.h>
#include <private/qv4object_p.h>
@@ -486,6 +485,9 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles
void ListModel::set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng)
{
+ if (!object)
+ return;
+
ListElement *e = elements[elementIndex];
QV4::ExecutionEngine *v4 = object->engine();
@@ -1517,11 +1519,11 @@ QQmlListModelParser::ListInstruction *QQmlListModelParser::ListModelData::instru
The timer in the main example sends messages to the worker script by calling
\l WorkerScript::sendMessage(). When this message is received,
- \l{WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in \c dataloader.js,
+ \c WorkerScript.onMessage() is invoked in \c dataloader.js,
which appends the current time to the list model.
- Note the call to sync() from the \l{WorkerScript::onMessage}{WorkerScript.onMessage()}
- handler. You must call sync() or else the changes made to the list from the external
+ Note the call to sync() from the external thread.
+ You must call sync() or else the changes made to the list from that
thread will not be reflected in the list model in the main thread.
\sa {qml-data-models}{Data Models}, {declarative/threading/threadedlistmodel}{Threaded ListModel example}, {Qt QML}
@@ -2252,7 +2254,7 @@ void QQmlListModel::sync()
qmlInfo(this) << "List sync() can only be called from a WorkerScript";
}
-bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QV4::CompiledData::Binding *binding, QList<QQmlListModelParser::ListInstruction> &instr, QByteArray &data)
+bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<QQmlListModelParser::ListInstruction> &instr, QByteArray &data)
{
if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
const quint32 targetObjectIndex = binding->value.objectIndex;
@@ -2294,7 +2296,7 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU
li.dataIdx = ref;
instr << li;
- if (!compileProperty(qmlUnit, targetObjectIndex, binding, instr, data))
+ if (!compileProperty(qmlUnit, binding, instr, data))
return false;
li.type = ListInstruction::Pop;
@@ -2323,6 +2325,10 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU
} else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
d += char(Boolean);
d += char(binding->valueAsBoolean());
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Translation
+ || binding->type == QV4::CompiledData::Binding::Type_TranslationById) {
+ error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
+ return false;
} else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = binding->valueAsScriptString(&qmlUnit->header);
if (definesEmptyList(scriptStr)) {
@@ -2332,38 +2338,8 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU
bool ok;
int v = evaluateEnum(script, &ok);
if (!ok) {
- using namespace QQmlJS;
- AST::Node *node = astForBinding(objectIndex, binding->value.compiledScriptIndex);
- if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement*>(node))
- node = stmt->expression;
- AST::StringLiteral *literal = 0;
- if (AST::CallExpression *callExpr = AST::cast<AST::CallExpression *>(node)) {
- if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(callExpr->base)) {
- if (idExpr->name == QLatin1String("QT_TR_NOOP") || idExpr->name == QLatin1String("QT_TRID_NOOP")) {
- if (callExpr->arguments && !callExpr->arguments->next)
- literal = AST::cast<AST::StringLiteral *>(callExpr->arguments->expression);
- if (!literal) {
- error(binding, QQmlListModel::tr("ListElement: improperly specified %1").arg(idExpr->name.toString()));
- return false;
- }
- } else if (idExpr->name == QLatin1String("QT_TRANSLATE_NOOP")) {
- if (callExpr->arguments && callExpr->arguments->next && !callExpr->arguments->next->next)
- literal = AST::cast<AST::StringLiteral *>(callExpr->arguments->next->expression);
- if (!literal) {
- error(binding, QQmlListModel::tr("ListElement: improperly specified QT_TRANSLATE_NOOP"));
- return false;
- }
- }
- }
- }
-
- if (literal) {
- d[0] = char(String);
- d += literal->value.toUtf8();
- } else {
- error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
- return false;
- }
+ error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
+ return false;
} else {
d[0] = char(Number);
d += QByteArray::number(v);
@@ -2385,7 +2361,7 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU
return true;
}
-QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings)
+QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
QList<ListInstruction> instr;
QByteArray data;
@@ -2397,7 +2373,7 @@ QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUni
error(binding, QQmlListModel::tr("ListModel: undefined property '%1'").arg(propName));
return QByteArray();
}
- if (!compileProperty(qmlUnit, objectIndex, binding, instr, data))
+ if (!compileProperty(qmlUnit, binding, instr, data))
return QByteArray();
}
@@ -2419,7 +2395,7 @@ QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUni
return rv;
}
-void QQmlListModelParser::setCustomData(QObject *obj, const QByteArray &d)
+void QQmlListModelParser::setCustomData(QObject *obj, const QByteArray &d, QQmlCompiledData *)
{
QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index 17fbb8a819..54ed18865f 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -168,8 +168,8 @@ public:
QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
- QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings);
- void setCustomData(QObject *, const QByteArray &);
+ QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
+ void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *);
private:
struct ListInstruction
@@ -183,7 +183,7 @@ private:
int instrCount;
ListInstruction *instructions() const;
};
- bool compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QV4::CompiledData::Binding *binding, QList<ListInstruction> &instr, QByteArray &data);
+ bool compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<ListInstruction> &instr, QByteArray &data);
bool definesEmptyList(const QString &);
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index da34101c36..507e94fb7e 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -340,7 +340,11 @@ bool QQuickWorkerScriptEnginePrivate::event(QEvent *event)
return true;
} else if (event->type() == (QEvent::Type)WorkerRemoveEvent::WorkerRemove) {
WorkerRemoveEvent *workerEvent = static_cast<WorkerRemoveEvent *>(event);
- workers.remove(workerEvent->workerId());
+ QHash<int, WorkerScript *>::iterator itr = workers.find(workerEvent->workerId());
+ if (itr != workers.end()) {
+ delete itr.value();
+ workers.erase(itr);
+ }
return true;
} else {
return QObject::event(event);
@@ -382,7 +386,7 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
if (f.open(QIODevice::ReadOnly)) {
QByteArray data = f.readAll();
QString sourceCode = QString::fromUtf8(data);
- QQmlScript::Parser::extractPragmas(sourceCode);
+ QmlIR::Document::removeScriptPragmas(sourceCode);
WorkerScript *script = workers.value(id);
if (!script)
@@ -580,7 +584,7 @@ void QQuickWorkerScriptEngine::run()
that the main GUI thread is not blocked.
Messages can be passed between the new thread and the parent thread
- using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
+ using \l sendMessage() and the \c onMessage() handler.
An example:
@@ -716,10 +720,12 @@ void QQuickWorkerScript::componentComplete()
}
/*!
- \qmlsignal WorkerScript::onMessage(jsobject msg)
+ \qmlsignal WorkerScript::message(jsobject msg)
- This handler is called when a message \a msg is received from a worker
+ This signal is emitted when a message \a msg is received from a worker
script in another thread through a call to sendMessage().
+
+ The corresponding handler is \c onMessage.
*/
bool QQuickWorkerScript::event(QEvent *event)
diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro
index 963fb1be5a..25d6494558 100644
--- a/src/qmldevtools/qmldevtools.pro
+++ b/src/qmldevtools/qmldevtools.pro
@@ -1,7 +1,7 @@
option(host_build)
TARGET = QtQmlDevTools
QT = core
-CONFIG += static no_module_headers internal_module
+CONFIG += static no_module_headers internal_module qmldevtools_build
MODULE_INCLUDES = \
\$\$QT_MODULE_INCLUDE_BASE \
@@ -12,4 +12,8 @@ MODULE_PRIVATE_INCLUDES = \
load(qt_module)
+include(../3rdparty/masm/masm-defs.pri)
include(../qml/parser/parser.pri)
+include(../qml/jsruntime/jsruntime.pri)
+include(../qml/compiler/compiler.pri)
+include(../qml/qml/qml.pri)
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index b3ed81b939..3a7b13fd18 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -198,6 +198,29 @@ bool qWaitForSignal(QObject *obj, const char* signal, int timeout = 5000)
int quick_test_main(int argc, char **argv, const char *name, const char *sourceDir)
{
+ // Peek at arguments to check for '-widgets' argument
+#ifdef QT_QMLTEST_WITH_WIDGETS
+ bool withWidgets = false;
+ for (int index = 1; index < argc; ++index) {
+ if (strcmp(argv[index], "-widgets") == 0) {
+ withWidgets = true;
+ break;
+ }
+ }
+#endif
+
+ QCoreApplication *app = 0;
+ if (!QCoreApplication::instance()) {
+#ifdef QT_QMLTEST_WITH_WIDGETS
+ if (withWidgets)
+ app = new QApplication(argc, argv);
+ else
+#endif
+ {
+ app = new QGuiApplication(argc, argv);
+ }
+ }
+
// Look for QML-specific command-line options.
// -import dir Specify an import directory.
// -input dir Specify the input directory for test cases.
@@ -205,9 +228,6 @@ int quick_test_main(int argc, char **argv, const char *name, const char *sourceD
QStringList imports;
QString testPath;
QString translationFile;
-#ifdef QT_QMLTEST_WITH_WIDGETS
- bool withWidgets = false;
-#endif
int index = 1;
QScopedArrayPointer<char *> testArgV(new char *[argc + 1]);
testArgV[0] = argv[0];
@@ -235,20 +255,6 @@ int quick_test_main(int argc, char **argv, const char *name, const char *sourceD
}
testArgV[testArgC] = 0;
- QCoreApplication* app = 0;
- if (!QCoreApplication::instance()) {
-#ifdef QT_QMLTEST_WITH_WIDGETS
- if (withWidgets)
- app = new QApplication(argc, argv);
- else
-#endif
- {
- app = new QGuiApplication(argc, argv);
- }
- }
-
- // Parse the command-line arguments.
-
// Setting currentAppname and currentTestObjectName (via setProgramName) are needed
// for the code coverage analysis. Must be done before parseArgs is called.
QuickTestResult::setCurrentAppname(argv[0]);
diff --git a/src/quick/designer/designersupport.cpp b/src/quick/designer/designersupport.cpp
index e0b4bd41e5..82f796361b 100644
--- a/src/quick/designer/designersupport.cpp
+++ b/src/quick/designer/designersupport.cpp
@@ -94,7 +94,10 @@ void DesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool hide)
texture->setSize(referencedItem->boundingRect().size().toSize());
texture->setRecursive(true);
#ifndef QT_OPENGL_ES
- texture->setFormat(GL_RGBA8);
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
+ texture->setFormat(GL_RGBA8);
+ else
+ texture->setFormat(GL_RGBA);
#else
texture->setFormat(GL_RGBA);
#endif
diff --git a/src/quick/doc/images/visualize-batches.png b/src/quick/doc/images/visualize-batches.png
new file mode 100644
index 0000000000..eb6ebe3606
--- /dev/null
+++ b/src/quick/doc/images/visualize-batches.png
Binary files differ
diff --git a/src/quick/doc/images/visualize-clip.png b/src/quick/doc/images/visualize-clip.png
new file mode 100644
index 0000000000..0a67b308cc
--- /dev/null
+++ b/src/quick/doc/images/visualize-clip.png
Binary files differ
diff --git a/src/quick/doc/images/visualize-original.png b/src/quick/doc/images/visualize-original.png
new file mode 100644
index 0000000000..00a2de2e4b
--- /dev/null
+++ b/src/quick/doc/images/visualize-original.png
Binary files differ
diff --git a/src/quick/doc/images/visualize-overdraw-1.png b/src/quick/doc/images/visualize-overdraw-1.png
new file mode 100644
index 0000000000..af2cf098d7
--- /dev/null
+++ b/src/quick/doc/images/visualize-overdraw-1.png
Binary files differ
diff --git a/src/quick/doc/images/visualize-overdraw-2.png b/src/quick/doc/images/visualize-overdraw-2.png
new file mode 100644
index 0000000000..6872074808
--- /dev/null
+++ b/src/quick/doc/images/visualize-overdraw-2.png
Binary files differ
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 515263f079..edad14cfd4 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -44,7 +44,6 @@ sourcedirs += .. \
../../quickwidgets
exampledirs += ../../../examples/quick \
- ../../../examples/quickwidgets \
snippets
diff --git a/src/quick/doc/snippets/qml/xmlrole.qml b/src/quick/doc/snippets/qml/xmlrole.qml
index 0f75135da2..257594179a 100644
--- a/src/quick/doc/snippets/qml/xmlrole.qml
+++ b/src/quick/doc/snippets/qml/xmlrole.qml
@@ -52,7 +52,7 @@ XmlListModel {
//![1]
// XmlRole queries will be made on <book> elements
- query: "/catalogue/book"
+ query: "/catalog/book"
// query the book title
XmlRole { name: "title"; query: "title/string()" }
@@ -65,17 +65,22 @@ XmlListModel {
// query the book's first listed author (note in XPath the first index is 1, not 0)
XmlRole { name: "first_author"; query: "author[1]/string()" }
+
+ // query the wanted attribute as a boolean
+ XmlRole { name: "wanted"; query: "boolean(@wanted)" }
}
//![1]
+//![2]
ListView {
width: 300; height: 200
model: model
delegate: Column {
- Text { text: title + " (" + type + ")"; font.bold: true }
+ Text { text: title + " (" + type + ")"; font.bold: wanted }
Text { text: first_author }
Text { text: year }
}
+//![2]
}
}
diff --git a/src/quick/doc/snippets/qml/xmlrole.xml b/src/quick/doc/snippets/qml/xmlrole.xml
new file mode 100644
index 0000000000..70280e067d
--- /dev/null
+++ b/src/quick/doc/snippets/qml/xmlrole.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<catalog>
+ <book type="Online" wanted="true">
+ <title>Qt 5 Cadaques</title>
+ <year>2014</year>
+ <author>Juergen Bocklage-Ryannel</author>
+ <author>Johan Thelin</author>
+ </book>
+ <book type="Hardcover">
+ <title>C++ GUI Programming with Qt 4</title>
+ <year>2006</year>
+ <author>Jasmin Blanchette</author>
+ <author>Mark Summerfield</author>
+ </book>
+ <book type="Paperback">
+ <title>Programming with Qt</title>
+ <year>2002</year>
+ <author>Matthias Kalle Dalheimer</author>
+ </book>
+ </catalog>
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index 278733de8d..7a54b7a021 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -739,4 +739,121 @@ with multiple windows.
{QSG_RENDER_TIMING=1} will output a number of useful timing
parameters which can be useful in pinpointing where a problem lies.
+ \section1 Visualizing
+
+ To visualize the various aspects of the scene graph's default renderer, the
+ \c QSG_VISUALIZE environment variable can be set to one of the values
+ detailed in each section below. We provide examples of the output of
+ some of the variables using the following QML code:
+
+ \code
+ import QtQuick 2.2
+
+ Rectangle {
+ width: 200
+ height: 140
+
+ ListView {
+ id: clippedList
+ x: 20
+ y: 20
+ width: 70
+ height: 100
+ clip: true
+ model: ["Item A", "Item B", "Item C", "Item D"]
+
+ delegate: Rectangle {
+ color: "lightblue"
+ width: parent.width
+ height: 25
+
+ Text {
+ text: modelData
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ }
+
+ ListView {
+ id: clippedDelegateList
+ x: clippedList.x + clippedList.width + 20
+ y: 20
+ width: 70
+ height: 100
+ clip: true
+ model: ["Item A", "Item B", "Item C", "Item D"]
+
+ delegate: Rectangle {
+ color: "lightblue"
+ width: parent.width
+ height: 25
+ clip: true
+
+ Text {
+ text: modelData
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ }
+ }
+ \endcode
+
+ For the ListView on the left, we set its \l {Item::clip}{clip} property to
+ \c true. For the ListView on right, we also set each delegate's
+ \l {Item::clip}{clip} property to \c true to illustrate the effects of
+ clipping on batching.
+
+ \image visualize-original.png "Original"
+ Original
+
+ \note The visualized elements do not respect clipping, and rendering order is
+ arbitrary.
+
+ \section2 Visualizing Batches
+
+ Setting \c QSG_VISUALIZE to \c batches visualizes batches in the renderer.
+ Merged batches are drawn with a solid color and unmerged batches are drawn
+ with a diagonal line pattern. Few unique colors means good batching.
+ Unmerged batches are bad if they contain many individual nodes.
+
+ \image visualize-batches.png "batches"
+ \c QSG_VISUALIZE=batches
+
+ \section2 Visualizing Clipping
+
+ Setting \c QSG_VISUALIZE to \c clip draws red areas on top of the scene
+ to indicate clipping. As Qt Quick Items do not clip by default, no clipping
+ is usually visualized.
+
+ \image visualize-clip.png
+ \c QSG_VISUALIZE=clip
+
+ \section2 Visualizing Changes
+
+ Setting \c QSG_VISUALIZE to \c changes visualizes changes in the renderer.
+ Changes in the scenegraph are visualized with a flashing overlay of a random
+ color. Changes on a primitive are visualized with a solid color, while
+ changes in an ancestor, such as matrix or opacity changes, are visualized
+ with a pattern.
+
+ \section2 Visualizing Overdraw
+
+ Setting \c QSG_VISUALIZE to \c overdraw visualizes overdraw in the renderer.
+ Visualize all items in 3D to highlight overdraws. This mode can also be used
+ to detect geometry outside the viewport to some extent. Opaque items are
+ rendered with a green tint, while translucent items are rendered with a red
+ tint. The bounding box for the viewport is rendered in blue. Opaque content
+ is easier for the scenegraph to process and is usually faster to render.
+
+ Note that the root rectangle in the code above is superfluous as the window
+ is also white, so drawing the rectangle is a waste of resources in this case.
+ Changing it to an Item can give a slight performance boost.
+
+ \image visualize-overdraw-1.png "overdraw-1"
+ \image visualize-overdraw-2.png "overdraw-2"
+ \c QSG_VISUALIZE=overdraw
*/
diff --git a/src/quick/doc/src/dynamicview-tutorial.qdoc b/src/quick/doc/src/dynamicview-tutorial.qdoc
index 2f07b7b234..cf1115cf4a 100644
--- a/src/quick/doc/src/dynamicview-tutorial.qdoc
+++ b/src/quick/doc/src/dynamicview-tutorial.qdoc
@@ -109,8 +109,8 @@ the view and cannot be moved by other means.
Dragging the content item is enabled by binding it to the MouseArea's
\l {QtQuick::MouseArea::drag.target}{drag.target} property. Because we still want the view to be
-flickable we wait until the MouseArea's \l {QtQuick::MouseArea::onPressAndHold}{onPressAndHold}
-handler is triggered before binding the drag target. This way when mouse moves before the hold
+flickable we wait until the MouseArea's \l {QtQuick::MouseArea::}{pressAndHold}
+signal is emitted before binding the drag target. This way when mouse moves before the hold
timeout has expired it is interpreted as moving the list and if it moves after it is interpreted as
dragging an item. To make it more obvious to the user when an item can be dragged we'll change the
background color of the content item when the timeout has expired.
diff --git a/src/quick/doc/src/examples.qdoc b/src/quick/doc/src/examples.qdoc
index def50ecd60..22c9786fda 100644
--- a/src/quick/doc/src/examples.qdoc
+++ b/src/quick/doc/src/examples.qdoc
@@ -74,7 +74,7 @@ steps such as use cases and introductory material. For more information about Qt
\div {class="landingicons"}
\div {class="icons1of3"}
- \bold{Development Environment}
+ \b{Development Environment}
\list
\li \l{Qt Creator: Creating Qt Quick Projects}{Creating Qt Quick Projects}
\li \l{Qt Creator: Using Qt Quick Designer}{Using Qt Quick Designer}
@@ -85,7 +85,7 @@ steps such as use cases and introductory material. For more information about Qt
\endlist
\enddiv
\div {class="icons1of3"}
- \bold{Beginning with QML and Qt Quick}
+ \b{Beginning with QML and Qt Quick}
\list
\li \l{First Steps with QML}
\li \l{Getting Started Programming with Qt Quick}{Qt Quick Text Editor}
@@ -93,7 +93,7 @@ steps such as use cases and introductory material. For more information about Qt
\endlist
\enddiv
\div {class="icons1of3"}
- \bold{Use Cases}
+ \b{Use Cases}
\list
\li \l{qtquick-usecase-visual.html}{Visual types in QML}
\li \l{qtquick-usecase-userinput.html}{Responding to User Input in QML}
@@ -124,7 +124,7 @@ the examples from within Qt Creator.
\div {class="landingicons"}
\div {class="icons1of3"}
- \bold{QML Types and Controls}
+ \b{QML Types and Controls}
\list
\li \l{Qt Quick Controls - Gallery}{Controls Gallery}
\li \l{Qt Quick System Dialog Examples}{Dialog Examples}
@@ -135,7 +135,7 @@ the examples from within Qt Creator.
\endlist
\enddiv
\div {class="icons1of3"}
- \bold{Layouts and Views}
+ \b{Layouts and Views}
\list
\li \l{Qt Quick Controls - Basic Layouts Example}{Basic Layouts}
\li \l{Qt Quick Examples - Positioners}{Positioners}
@@ -145,7 +145,7 @@ the examples from within Qt Creator.
\endlist
\enddiv
\div {class="icons1of3"}
- \bold{Image and Graphics}
+ \b{Image and Graphics}
\list
\li \l{Qt Quick Examples - Image Elements}{Image Elements}
\li \l{Qt Quick Examples - Animation}{Animation}
@@ -157,7 +157,7 @@ the examples from within Qt Creator.
\div {class="landingicons"}
\div {class="icons1of3"}
- \bold{Keyboard, Focus, and Touch}
+ \b{Keyboard, Focus, and Touch}
\list
\li \l{Qt Quick Examples - Key Interaction}{Key Interaction}
\li \l{Qt Quick Examples - MouseArea}{MouseArea}
@@ -165,7 +165,7 @@ the examples from within Qt Creator.
\endlist
\enddiv
\div {class="icons1of3"}
- \bold{System and Events}
+ \b{System and Events}
\list
\li \l{Qt Quick Examples - Threading}{Threading}
\li \l{Qt Quick Examples - Accessibility}{Accessibility}
@@ -174,7 +174,7 @@ the examples from within Qt Creator.
\endlist
\enddiv
\div {class="icons1of3"}
- \bold{Scene Graph}
+ \b{Scene Graph}
\list
\li \l{Scene Graph - OpenGL Under QML}{OpenGL Under QML}
\li \l{Scene Graph - Painted Item}{Painted Item}
diff --git a/src/quick/doc/src/tutorial.qdoc b/src/quick/doc/src/tutorial.qdoc
index e0c05b16a8..75ca1b8d55 100644
--- a/src/quick/doc/src/tutorial.qdoc
+++ b/src/quick/doc/src/tutorial.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -31,7 +31,7 @@
\brief An introduction to the basic concepts and features of QML.
\nextpage QML Tutorial 1 - Basic Types
-This tutorial gives an introduction to QML, the declarative language for Qt Quick. It doesn't cover everything;
+This tutorial gives an introduction to QML, the language for Qt Quick UIs. It doesn't cover everything;
the emphasis is on teaching the key principles, and features are introduced as needed.
Through the different steps of this tutorial we will learn about QML basic types, we will create our own QML component
diff --git a/src/quick/doc/src/whatsnew.qdoc b/src/quick/doc/src/whatsnew.qdoc
index f50e80edf6..ca2a2156d8 100644
--- a/src/quick/doc/src/whatsnew.qdoc
+++ b/src/quick/doc/src/whatsnew.qdoc
@@ -53,7 +53,6 @@ features introduced by the new import and new classes in Qt 5.1:
\endlist
These types are kept due to compatibility reasons and are replaced by the
\l{Qt QML Models QML Types}{Qt QML Models} types.
- \endlist
\endlist
\section2 New Submodules
@@ -216,7 +215,7 @@ relative to its start.
\list
\li \c Text.RightElide is now supported where text spans multiple lines.
\li New \l{Text::}{linkColor} property controls the color of linked text.
- \li New \l{Text::}{onLineLaidOut} handler is called for every line during the layout process to
+ \li New \l{Text::}{lineLaidOut} signal is emitted for every line during the layout process to
give the option of positioning and/or resizing lines as they are laid out.
\li New \l{Text::}{doLayout()} method will trigger the text layout from Javascript.
\li New \l{Text::}{fontSizeMode} property allows text to be fitted to the item size.
@@ -250,9 +249,9 @@ the window loses focus.
\list
\li Wheel events are now supported; events are provided through the new WheelEvent type.
\li New \l{MouseArea::}{propagateComposedEvents} property sets whether composed events are
- propagated to other mouse areas. If this property is true and the l{MouseArea::onClicked}{clicked},
- \l{MouseArea::onDoubleClicked}{doubleClicked} or \l{MouseArea::onPressAndHold}{pressAndHold}
- handlers reject a mouse event, the event will be propagated to overlapping MouseArea items
+ propagated to other mouse areas. If this property is true and the handlers of the
+ \l{MouseArea::}{clicked}, \l{MouseArea::}{doubleClicked} or \l{MouseArea::}{pressAndHold}
+ signals reject a mouse event, the event will be propagated to overlapping MouseArea items
in the same area that are lower in the stacking order.
\li New \l{MouseArea::}{cursorShape} property controls the cursor shape.
\endlist
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 17adf1b66b..7d3be0865b 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -271,10 +271,10 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
\li Replace all HTML event handlers with the MouseArea item.
\li Change setInterval/setTimeout function calls with the \l Timer item or
the use of requestAnimationFrame().
- \li Place painting code into the onPaint handler and trigger
+ \li Place painting code into the \c onPaint handler and trigger
painting by calling the markDirty() or requestPaint() methods.
\li To draw images, load them by calling the Canvas's loadImage() method and then request to paint
- them in the onImageLoaded handler.
+ them in the \c onImageLoaded handler.
\endlist
\sa Context2D
@@ -590,8 +590,10 @@ void QQuickCanvasItem::geometryChanged(const QRectF &newGeometry, const QRectF &
emit canvasWindowChanged();
}
- if (d->available && newSize != oldGeometry.size())
- requestPaint();
+ if (d->available && newSize != oldGeometry.size()) {
+ if (isVisible() || (d->extra.isAllocated() && d->extra->effectRefCount > 0))
+ requestPaint();
+ }
}
void QQuickCanvasItem::releaseResources()
@@ -640,9 +642,6 @@ void QQuickCanvasItem::updatePolish()
QQuickItem::updatePolish();
Q_D(QQuickCanvasItem);
- if (!isVisible() && !(d->extra.isAllocated() && d->extra->effectRefCount>0))
- return;
-
if (d->context && d->renderStrategy != QQuickCanvasItem::Cooperative)
d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth, antialiasing());
@@ -844,10 +843,9 @@ void QQuickCanvasItem::requestPaint()
\qmlmethod QtQuick::Canvas::markDirty(rect area)
Mark the given \a area as dirty, so that when this area is visible the
- canvas renderer will redraw it. This will trigger the onPaint signal
- handler function.
+ canvas renderer will redraw it. This will trigger the \c paint signal.
- \sa onPaint, requestPaint()
+ \sa paint, requestPaint()
*/
void QQuickCanvasItem::markDirty(const QRectF& rect)
@@ -897,9 +895,11 @@ QQmlRefPointer<QQuickCanvasPixmap> QQuickCanvasItem::loadedPixmap(const QUrl& ur
}
/*!
- \qmlsignal QtQuick::Canvas::onImageLoaded()
+ \qmlsignal QtQuick::Canvas::imageLoaded()
- This handler is called when an image has been loaded.
+ This signal is emitted when an image has been loaded.
+
+ The corresponding handler is \c onImageLoaded.
\sa loadImage()
*/
@@ -908,11 +908,11 @@ QQmlRefPointer<QQuickCanvasPixmap> QQuickCanvasItem::loadedPixmap(const QUrl& ur
\qmlmethod QtQuick::Canvas::loadImage(url image)
Loads the given \c image asynchronously.
- When the image is ready, onImageLoaded will be emitted.
+ When the image is ready, \l imageLoaded will be emitted.
The loaded image can be unloaded by the unloadImage() method.
Note: Only loaded images can be painted on the Canvas item.
- \sa unloadImage, onImageLoaded, isImageLoaded(),
+ \sa unloadImage, imageLoaded, isImageLoaded(),
Context2D::createImageData(), Context2D::drawImage()
*/
void QQuickCanvasItem::loadImage(const QUrl& url)
@@ -939,7 +939,7 @@ void QQuickCanvasItem::loadImage(const QUrl& url)
Once an image is unloaded it cannot be painted by the canvas context
unless it is loaded again.
- \sa loadImage(), onImageLoaded, isImageLoaded(),
+ \sa loadImage(), imageLoaded, isImageLoaded(),
Context2D::createImageData(), Context2D::drawImage
*/
void QQuickCanvasItem::unloadImage(const QUrl& url)
@@ -1099,20 +1099,24 @@ QRect QQuickCanvasItem::tiledRect(const QRectF &window, const QSize &tileSize)
}
/*!
- \qmlsignal QtQuick::Canvas::onPaint(rect region)
+ \qmlsignal QtQuick::Canvas::paint(rect region)
- This handler is called to render the \a region. If a context is active it
- can be referenced from the context property.
+ This signal is emitted when the \a region needs to be rendered. If a context
+ is active it can be referenced from the context property.
- This signal can be triggered markdirty(), requestPaint() or by changing
+ This signal can be triggered by markdirty(), requestPaint() or by changing
the current canvas window.
+
+ The corresponding handler is \c onPaint.
*/
/*!
- \qmlsignal QtQuick::Canvas::onPainted()
+ \qmlsignal QtQuick::Canvas::painted()
- This handler is called after all context painting commands are executed and
+ This signal is emitted after all context painting commands are executed and
the Canvas has been rendered.
+
+ The corresponding handler is \c onPainted.
*/
QT_END_NAMESPACE
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 9851983201..2a6eae71f7 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -2916,7 +2916,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallConte
\sa Image
\sa Canvas::loadImage
\sa Canvas::isImageLoaded
- \sa Canvas::onImageLoaded
+ \sa Canvas::imageLoaded
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
*/
@@ -2936,7 +2936,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallConte
\sa Image
\sa Canvas::loadImage()
\sa Canvas::isImageLoaded
- \sa Canvas::onImageLoaded
+ \sa Canvas::imageLoaded
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
*/
@@ -2957,7 +2957,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallConte
\sa Image
\sa Canvas::loadImage()
\sa Canvas::isImageLoaded
- \sa Canvas::onImageLoaded
+ \sa Canvas::imageLoaded
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
*/
@@ -3175,8 +3175,11 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint
QV4::ExecutionEngine *v4 = m->engine();
QV4::Scope scope(v4);
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
- if (!m)
+ if (!m) {
+ if (hasProperty)
+ *hasProperty = false;
return m->engine()->currentContext()->throwTypeError();
+ }
if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
if (hasProperty)
@@ -4136,7 +4139,9 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->openglContext();
- m_surface = window;
+ m_surface.reset(new QOffscreenSurface);
+ m_surface->setFormat(window->format());
+ m_surface->create();
m_glContext = new QOpenGLContext;
m_glContext->setFormat(cc->format());
m_glContext->setShareContext(cc);
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 4390ae62cc..ab851d302f 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -49,6 +49,7 @@
#include <private/qquickcanvasitem_p.h>
#include <QtGui/qpainter.h>
#include <QtGui/qpainterpath.h>
+#include <QtGui/qoffscreensurface.h>
#include <QtCore/qstring.h>
#include <QtCore/qstack.h>
#include <QtCore/qqueue.h>
@@ -229,7 +230,7 @@ public:
QQmlRefPointer<QQuickCanvasPixmap> createPixmap(const QUrl& url);
QOpenGLContext *glContext() { return m_glContext; }
- QSurface *surface() { return m_surface; }
+ QSurface *surface() { return m_surface.data(); }
void setGrabbedImage(const QImage& grab);
State state;
@@ -241,7 +242,7 @@ public:
QV4::PersistentValue m_strokeStyle;
QV4::PersistentValue m_v4path;
QV8Engine *m_v8engine;
- QSurface *m_surface;
+ QScopedPointer<QOffscreenSurface> m_surface;
QOpenGLContext *m_glContext;
QV4::PersistentValue m_v4value;
QQuickContext2DTexture *m_texture;
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index 06a0713365..5697c25ff0 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -214,6 +214,8 @@ void QQuickContext2DCommandBuffer::setPainterState(QPainter* p, const QQuickCont
if (state.globalCompositeOperation != p->compositionMode())
p->setCompositionMode(state.globalCompositeOperation);
+
+ p->setClipPath(state.clipPath);
}
static void qt_drawImage(QPainter *p, QQuickContext2D::State& state, QImage image, const QRectF& sr, const QRectF& dr, bool shadow = false)
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 64b8f257dc..bfe957e943 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -596,7 +596,10 @@ void QQuickAnimatedSprite::prepareNextFrame()
qreal frameDuration = m_spriteEngine->spriteDuration()/frameCount;
if (frameDuration > 0) {
qreal frame = (time - animT)/(frameDuration / 1000.0);
- frame = qBound(qreal(0.0), frame, frameCount - qreal(1.0));//Stop at count-1 frames until we have between anim interpolation
+ bool lastLoop = m_loops > 0 && m_curLoop == m_loops-1;
+ //don't visually interpolate for the last frame of the last loop
+ qreal max = lastLoop ? frameCount - qreal(1.0) : frameCount;
+ frame = qBound(qreal(0.0), frame, max);
progress = modf(frame,&frameAt);
if (m_curFrame > frameAt) //went around
m_curLoop++;
@@ -623,21 +626,54 @@ void QQuickAnimatedSprite::prepareNextFrame()
}
if (m_curFrame != lastFrame && isCurrentFrameChangedConnected())
emit currentFrameChanged(m_curFrame);
- if (m_spriteEngine->sprite()->reverse())
- frameAt = (m_spriteEngine->spriteFrames() - 1) - frameAt;
- qreal y = m_spriteEngine->spriteY() / m_sheetSize.height();
+
+ qreal frameCount = m_spriteEngine->spriteFrames();
+ bool reverse = 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 = m_spriteEngine->spriteX() / m_sheetSize.width();
- x1 += frameAt * w;
- qreal x2 = x1;
- if (frameAt < (m_spriteEngine->spriteFrames()-1))
- x2 += w;
+ qreal x1 = m_spriteEngine->spriteX() / m_sheetSize.width() + frameAt * w;
+ qreal y1 = m_spriteEngine->spriteY() / m_sheetSize.height();
+
+ //### 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;
+ if (reverse) {
+ if (frameAt > 0) {
+ x2 = x1 - w;
+ y2 = y1;
+ } else {
+ x2 = 1.0 - w;
+ 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;
+
+ y2 = 1.0 - h;
+ }
+ }
+ } else {
+ if (frameAt < (frameCount-1)) {
+ x2 = x1 + w;
+ y2 = y1;
+ } else {
+ x2 = 0.0;
+ y2 = y1 + h;
+ if (y2 >= 1.0)
+ y2 = 0.0;
+ }
+ }
m_material->animX1 = x1;
- m_material->animY1 = y;
+ m_material->animY1 = y1;
m_material->animX2 = x2;
- m_material->animY2 = y;
+ m_material->animY2 = y2;
m_material->animW = w;
m_material->animH = h;
m_material->animT = m_interpolate ? progress : 0.0;
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index 605c485f6b..6c36032d3c 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -523,7 +523,7 @@ void QQuickDragAttached::setProposedAction(Qt::DropAction action)
\endlist
When using \c Drag.Automatic you should also define \l mimeData and bind the
- \active property to the active property of \l MouseArea.drag.
+ \l active property to the active property of \l MouseArea.drag.
*/
QQuickDrag::DragType QQuickDragAttached::dragType() const
@@ -694,17 +694,21 @@ void QQuickDragAttached::cancel()
}
/*!
- \qmlattachedsignal QtQuick::Drag::onDragStarted()
+ \qmlattachedsignal QtQuick::Drag::dragStarted()
- This handler is called when a drag is started with the \l startDrag method
+ This signal is emitted when a drag is started with the \l startDrag() method
or when it is started automatically using the \l dragType property.
+
+ The corresponding handler is \c onDragStarted.
*/
/*!
- \qmlattachedsignal QtQuick::Drag::onDragFinished(DropAction action)
+ \qmlattachedsignal QtQuick::Drag::dragFinished(DropAction action)
+
+ This signal is emitted when a drag finishes and the drag was started with the
+ \l startDrag() method or started automatically using the \l dragType property.
- This handler is called when a drag finishes and the drag was started with the
- \l startDrag method or started automatically using the \l dragType property.
+ The corresponding handler is \c onDragFinished.
*/
Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedActions)
diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index 57e500a150..23ee016941 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -208,9 +208,11 @@ qreal QQuickDropAreaDrag::y() const
}
/*!
- \qmlsignal QtQuick::DropArea::onPositionChanged(DragEvent drag)
+ \qmlsignal QtQuick::DropArea::positionChanged(DragEvent drag)
- This handler is called when the position of a drag has changed.
+ This signal is emitted when the position of a drag has changed.
+
+ The corresponding handler is \c onPositionChanged.
*/
void QQuickDropArea::dragMoveEvent(QDragMoveEvent *event)
@@ -249,9 +251,11 @@ QStringList QQuickDropAreaPrivate::getKeys(const QMimeData *mimeData) const
}
/*!
- \qmlsignal QtQuick::DropArea::onEntered(DragEvent drag)
+ \qmlsignal QtQuick::DropArea::entered(DragEvent drag)
+
+ This signal is emitted when a \a drag enters the bounds of a DropArea.
- This handler is called when a \a drag enters the bounds of a DropArea.
+ The corresponding handler is \c onEntered.
*/
void QQuickDropArea::dragEnterEvent(QDragEnterEvent *event)
@@ -282,9 +286,11 @@ void QQuickDropArea::dragEnterEvent(QDragEnterEvent *event)
}
/*!
- \qmlsignal QtQuick::DropArea::onExited()
+ \qmlsignal QtQuick::DropArea::exited()
- This handler is called when a drag exits the bounds of a DropArea.
+ This signal is emitted when a drag exits the bounds of a DropArea.
+
+ The corresponding handler is \c onExited.
*/
void QQuickDropArea::dragLeaveEvent(QDragLeaveEvent *)
@@ -303,10 +309,12 @@ void QQuickDropArea::dragLeaveEvent(QDragLeaveEvent *)
}
/*!
- \qmlsignal QtQuick::DropArea::onDropped(DragEvent drop)
+ \qmlsignal QtQuick::DropArea::dropped(DragEvent drop)
- This handler is called when a drop event occurs within the bounds of
+ This signal is emitted when a drop event occurs within the bounds of
a DropArea.
+
+ The corresponding handler is \c onDropped.
*/
void QQuickDropArea::dropEvent(QDropEvent *event)
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 77687cf72a..d1bad78d41 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -548,19 +548,23 @@ is finished.
*/
/*!
- \qmlsignal QtQuick::Flickable::onDragStarted()
+ \qmlsignal QtQuick::Flickable::dragStarted()
- This handler is called when the view starts to be dragged due to user
+ This signal is emitted when the view starts to be dragged due to user
interaction.
+
+ The corresponding handler is \c onDragStarted.
*/
/*!
- \qmlsignal QtQuick::Flickable::onDragEnded()
+ \qmlsignal QtQuick::Flickable::dragEnded()
- This handler is called when the user stops dragging the view.
+ This signal is emitted when the user stops dragging the view.
If the velocity of the drag is sufficient at the time the
touch/mouse button is released then a flick will start.
+
+ The corresponding handler is \c onDragEnded.
*/
/*!
@@ -615,34 +619,42 @@ is finished.
*/
/*!
- \qmlsignal QtQuick::Flickable::onMovementStarted()
+ \qmlsignal QtQuick::Flickable::movementStarted()
- This handler is called when the view begins moving due to user
+ This signal is emitted when the view begins moving due to user
interaction.
+
+ The corresponding handler is \c onMovementStarted.
*/
/*!
- \qmlsignal QtQuick::Flickable::onMovementEnded()
+ \qmlsignal QtQuick::Flickable::movementEnded()
- This handler is called when the view stops moving due to user
- interaction. If a flick was generated, this handler will
- be triggered once the flick stops. If a flick was not
- generated, the handler will be triggered when the
+ This signal is emitted when the view stops moving due to user
+ interaction. If a flick was generated, this signal will
+ be emitted once the flick stops. If a flick was not
+ generated, this signal will be emitted when the
user stops dragging - i.e. a mouse or touch release.
+
+ The corresponding handler is \c onMovementEnded.
*/
/*!
- \qmlsignal QtQuick::Flickable::onFlickStarted()
+ \qmlsignal QtQuick::Flickable::flickStarted()
- This handler is called when the view is flicked. A flick
+ This signal is emitted when the view is flicked. A flick
starts from the point that the mouse or touch is released,
while still in motion.
+
+ The corresponding handler is \c onFlickStarted.
*/
/*!
- \qmlsignal QtQuick::Flickable::onFlickEnded()
+ \qmlsignal QtQuick::Flickable::flickEnded()
- This handler is called when the view stops moving due to a flick.
+ This signal is emitted when the view stops moving due to a flick.
+
+ The corresponding handler is \c onFlickEnded.
*/
/*!
@@ -1725,9 +1737,9 @@ void QQuickFlickable::setRebound(QQuickTransition *transition)
and \l {Item::childrenRect.height}{childrenRect.height} properties
of the \l contentItem. For example, the previous snippet could be rewritten with:
- \qml
+ \code
contentWidth: contentItem.childrenRect.width; contentHeight: contentItem.childrenRect.height
- \endqml
+ \endcode
Though this assumes that the origin of the childrenRect is 0,0.
*/
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 268c2d5342..10d281b7a1 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -70,7 +70,7 @@ public:
* for integrating OpenGL rendering using a framebuffer object (FBO)
* with Qt Quick.
*
- * On most platforms, the rendering will occur on a dedicated thread.
+ * On most platforms, the rendering will occur on a \l {Scene Graph and Rendering}{dedicated thread}.
* For this reason, the QQuickFramebufferObject class enforces a strict
* separation between the item implementation and the FBO rendering. All
* item logic, such as properties and UI-related helper functions needed by
@@ -99,7 +99,7 @@ public:
* to \c false and return a texture of your choosing from
* QQuickFramebufferObject::Renderer::createFramebufferObject().
*
- * \sa {Scene Graph - Rendering FBOs}
+ * \sa {Scene Graph - Rendering FBOs}, {Scene Graph and Rendering}
*/
/*!
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index e7b1437cf3..82658c73fc 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -1305,16 +1305,20 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
*/
/*!
- \qmlattachedsignal QtQuick::GridView::onAdd()
- This attached handler is called immediately after an item is added to the view.
+ \qmlattachedsignal QtQuick::GridView::add()
+ This attached signal is emitted immediately after an item is added to the view.
+
+ The corresponding handler is \c onAdd.
*/
/*!
- \qmlattachedsignal QtQuick::GridView::onRemove()
- This attached handler is called immediately before an item is removed from the view.
+ \qmlattachedsignal QtQuick::GridView::remove()
+ This attached signal is emitted immediately before an item is removed from the view.
If a \l remove transition has been specified, it is applied after
- this signal handler is called, providing that delayRemove is false.
+ this signal is handled, providing that \l delayRemove is false.
+
+ The corresponding handler is \c onRemove.
*/
@@ -1345,6 +1349,8 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
The item size of the GridView is determined by cellHeight and cellWidth. It will not resize the items
based on the size of the root item in the delegate.
+ The default \l {QQuickItem::z}{stacking order} of delegate instances is \c 1.
+
\note Delegates are instantiated as needed and may be destroyed at any time.
State should \e never be stored in a delegate.
*/
@@ -1373,6 +1379,8 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
The highlightItem is managed by the view unless
\l highlightFollowsCurrentItem is set to false.
+ The default \l {QQuickItem::z}{stacking order}
+ of the highlight item is \c 0.
\sa highlight, highlightFollowsCurrentItem
*/
@@ -1391,6 +1399,7 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
An instance of the highlight component is created for each view.
The geometry of the resulting component instance will be managed by the view
so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
+ The default \l {QQuickItem::z}{stacking order} of the highlight item is \c 0.
\sa highlightItem, highlightFollowsCurrentItem
*/
@@ -1691,7 +1700,8 @@ void QQuickGridView::setSnapMode(SnapMode mode)
This property holds the component to use as the footer.
An instance of the footer component is created for each view. The
- footer is positioned at the end of the view, after any items.
+ footer is positioned at the end of the view, after any items. The
+ default \l {QQuickItem::z}{stacking order} of the footer is \c 1.
\sa header, footerItem
*/
@@ -1701,6 +1711,7 @@ void QQuickGridView::setSnapMode(SnapMode mode)
An instance of the header component is created for each view. The
header is positioned at the beginning of the view, before any items.
+ The default \l {QQuickItem::z}{stacking order} of the header is \c 1.
\sa footer, headerItem
*/
@@ -1711,6 +1722,7 @@ void QQuickGridView::setSnapMode(SnapMode mode)
An instance of the header component is created for each view. The
header is positioned at the beginning of the view, before any items.
+ The default \l {QQuickItem::z}{stacking order} of the header is \c 1.
\sa header, footerItem
*/
@@ -1720,7 +1732,8 @@ void QQuickGridView::setSnapMode(SnapMode mode)
This holds the footer item created from the \l footer component.
An instance of the footer component is created for each view. The
- footer is positioned at the end of the view, after any items.
+ footer is positioned at the end of the view, after any items. The
+ default \l {QQuickItem::z}{stacking order} of the footer is \c 1.
\sa footer, headerItem
*/
@@ -1788,7 +1801,7 @@ void QQuickGridView::setSnapMode(SnapMode mode)
populated, or when the view's \l model changes. (In those cases, the \l populate transition is
applied instead.) Additionally, this transition should \e not animate the height of the new item;
doing so will cause any items beneath the new item to be laid out at the wrong position. Instead,
- the height can be animated within a \l {ListView::onAdd}{ListView.onAdd} in the delegate.
+ the height can be animated within the \l {add}{onAdd} handler in the delegate.
\sa addDisplaced, populate, ViewTransition
*/
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 69a39d2396..08dbfa3c23 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -589,8 +589,8 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
- qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width();
- qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->pix.height();
+ qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width() / d->devicePixelRatio;
+ qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->pix.height() / d->devicePixelRatio;
int xOffset = 0;
if (d->hAlign == QQuickImage::AlignHCenter)
@@ -671,10 +671,12 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
break;
};
- QRectF nsrect(sourceRect.x() / d->pix.width(),
- sourceRect.y() / d->pix.height(),
- sourceRect.width() / d->pix.width(),
- sourceRect.height() / d->pix.height());
+ qreal nsWidth = (hWrap == QSGTexture::Repeat) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
+ qreal nsHeight = (vWrap == QSGTexture::Repeat) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
+ QRectF nsrect(sourceRect.x() / nsWidth,
+ sourceRect.y() / nsHeight,
+ sourceRect.width() / nsWidth,
+ sourceRect.height() / nsHeight);
if (targetRect.isEmpty()
|| !qIsFinite(targetRect.width()) || !qIsFinite(targetRect.height())
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index c842922dc6..66a56cc8bf 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -42,7 +42,10 @@
#include "qquickimagebase_p.h"
#include "qquickimagebase_p_p.h"
+#include <QtGui/qguiapplication.h>
+
#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlfile.h>
QT_BEGIN_NAMESPACE
@@ -50,12 +53,14 @@ QQuickImageBase::QQuickImageBase(QQuickItem *parent)
: QQuickImplicitSizeItem(*(new QQuickImageBasePrivate), parent)
{
setFlag(ItemHasContents);
+ connect(this, SIGNAL(windowChanged(QQuickWindow*)), SLOT(handleWindowChanged(QQuickWindow*)));
}
QQuickImageBase::QQuickImageBase(QQuickImageBasePrivate &dd, QQuickItem *parent)
: QQuickImplicitSizeItem(dd, parent)
{
setFlag(ItemHasContents);
+ connect(this, SIGNAL(windowChanged(QQuickWindow*)), SLOT(handleWindowChanged(QQuickWindow*)));
}
QQuickImageBase::~QQuickImageBase()
@@ -208,7 +213,13 @@ void QQuickImageBase::load()
if (d->cache)
options |= QQuickPixmap::Cache;
d->pix.clear(this);
- d->pix.load(qmlEngine(this), d->url, d->sourcesize, options);
+
+ const qreal targetDevicePixelRatio = (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio());
+ d->devicePixelRatio = 1.0;
+
+ QUrl loadUrl = d->url;
+ resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
+ d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
@@ -275,6 +286,19 @@ void QQuickImageBase::requestProgress(qint64 received, qint64 total)
}
}
+void QQuickImageBase::handleWindowChanged(QQuickWindow* window)
+{
+ if (window)
+ connect(window, SIGNAL(screenChanged(QScreen*)), this, SLOT(handleScreenChanged(QScreen*)));
+}
+
+void QQuickImageBase::handleScreenChanged(QScreen*)
+{
+ // Screen DPI might have changed, reload images on screen change.
+ if (isComponentComplete())
+ load();
+}
+
void QQuickImageBase::componentComplete()
{
Q_D(QQuickImageBase);
@@ -286,7 +310,52 @@ void QQuickImageBase::componentComplete()
void QQuickImageBase::pixmapChange()
{
Q_D(QQuickImageBase);
- setImplicitSize(d->pix.width(), d->pix.height());
+ setImplicitSize(d->pix.width() / d->devicePixelRatio, d->pix.height() / d->devicePixelRatio);
+}
+
+// /path/to/foo.png -> path/too/foo@2x.png
+static QString image2xPath(const QString &path)
+{
+ const int dotIndex = path.lastIndexOf(QLatin1Char('.'));
+ if (dotIndex == -1)
+ return path;
+ if (path.contains(QLatin1String("@2x.")))
+ return path;
+
+ QString retinaPath = path;
+ retinaPath.insert(dotIndex, QStringLiteral("@2x"));
+ return retinaPath;
+}
+
+void QQuickImageBase::resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio)
+{
+ Q_ASSERT(sourceUrl);
+ Q_ASSERT(sourceDevicePixelRatio);
+
+ QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
+
+ // Non-local file path: @2x loading is not supported.
+ if (localFile.isEmpty())
+ return;
+
+ // Special case: the url in the QML source refers directly to an "@2x" file.
+ if (localFile.contains(QLatin1String("@2x"))) {
+ *sourceDevicePixelRatio = qreal(2.0);
+ return;
+ }
+
+ // Don't load @2x files non normal-dpi displays.
+ if (!(targetDevicePixelRatio > qreal(1.0)))
+ return;
+
+ // Look for an @2x version
+ QString localFile2x = image2xPath(localFile);
+ if (!QFile(localFile2x).exists())
+ return;
+
+ // @2x file found found: Change url and devicePixelRatio
+ *sourceUrl = QUrl::fromLocalFile(localFile2x);
+ *sourceDevicePixelRatio = qreal(2.0);
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index 72258b4971..67f1e81cae 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -86,6 +86,8 @@ public:
virtual void setMirror(bool mirror);
bool mirror() const;
+ void resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio);
+
Q_SIGNALS:
void sourceChanged(const QUrl &);
void sourceSizeChanged();
@@ -104,6 +106,8 @@ protected:
private Q_SLOTS:
virtual void requestFinished();
void requestProgress(qint64,qint64);
+ void handleWindowChanged(QQuickWindow *window);
+ void handleScreenChanged(QScreen *);
private:
Q_DISABLE_COPY(QQuickImageBase)
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index 395abf01fa..bb8778d789 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -69,6 +69,7 @@ public:
QQuickImageBasePrivate()
: status(QQuickImageBase::Null),
progress(0.0),
+ devicePixelRatio(1.0),
async(false),
cache(true),
mirror(false)
@@ -81,6 +82,7 @@ public:
qreal progress;
QSize sourcesize;
QSize oldSourceSize;
+ qreal devicePixelRatio;
bool async : 1;
bool cache : 1;
bool mirror: 1;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 2c89c32b45..03a78895cf 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -924,276 +924,354 @@ bool QQuickKeysAttached::isConnected(const char *signalName)
*/
/*!
- \qmlsignal QtQuick::Keys::onPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::pressed(KeyEvent event)
- This handler is called when a key has been pressed. The \a event
+ This signal is emitted when a key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onReleased(KeyEvent event)
+ \qmlsignal QtQuick::Keys::released(KeyEvent event)
- This handler is called when a key has been released. The \a event
+ This signal is emitted when a key has been released. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onReleased.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit0Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit0Pressed(KeyEvent event)
- This handler is called when the digit '0' has been pressed. The \a event
+ This signal is emitted when the digit '0' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit0Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit1Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit1Pressed(KeyEvent event)
- This handler is called when the digit '1' has been pressed. The \a event
+ This signal is emitted when the digit '1' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit1Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit2Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit2Pressed(KeyEvent event)
- This handler is called when the digit '2' has been pressed. The \a event
+ This signal is emitted when the digit '2' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit2Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit3Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit3Pressed(KeyEvent event)
- This handler is called when the digit '3' has been pressed. The \a event
+ This signal is emitted when the digit '3' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit3Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit4Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit4Pressed(KeyEvent event)
- This handler is called when the digit '4' has been pressed. The \a event
+ This signal is emitted when the digit '4' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit4Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit5Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit5Pressed(KeyEvent event)
- This handler is called when the digit '5' has been pressed. The \a event
+ This signal is emitted when the digit '5' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit5Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit6Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit6Pressed(KeyEvent event)
- This handler is called when the digit '6' has been pressed. The \a event
+ This signal is emitted when the digit '6' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit6Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit7Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit7Pressed(KeyEvent event)
- This handler is called when the digit '7' has been pressed. The \a event
+ This signal is emitted when the digit '7' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit7Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit8Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit8Pressed(KeyEvent event)
- This handler is called when the digit '8' has been pressed. The \a event
+ This signal is emitted when the digit '8' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit8Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDigit9Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::digit9Pressed(KeyEvent event)
- This handler is called when the digit '9' has been pressed. The \a event
+ This signal is emitted when the digit '9' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDigit9Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onLeftPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::leftPressed(KeyEvent event)
- This handler is called when the Left arrow has been pressed. The \a event
+ This signal is emitted when the Left arrow has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onLeftPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onRightPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::rightPressed(KeyEvent event)
- This handler is called when the Right arrow has been pressed. The \a event
+ This signal is emitted when the Right arrow has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onRightPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onUpPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::upPressed(KeyEvent event)
- This handler is called when the Up arrow has been pressed. The \a event
+ This signal is emitted when the Up arrow has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onUpPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDownPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::downPressed(KeyEvent event)
- This handler is called when the Down arrow has been pressed. The \a event
+ This signal is emitted when the Down arrow has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDownPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onTabPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::tabPressed(KeyEvent event)
- This handler is called when the Tab key has been pressed. The \a event
+ This signal is emitted when the Tab key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onTabPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onBacktabPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::backtabPressed(KeyEvent event)
- This handler is called when the Shift+Tab key combination (Backtab) has
+ This signal is emitted when the Shift+Tab key combination (Backtab) has
been pressed. The \a event parameter provides information about the event.
+
+ The corresponding handler is \c onBacktabPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onAsteriskPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::asteriskPressed(KeyEvent event)
- This handler is called when the Asterisk '*' has been pressed. The \a event
+ This signal is emitted when the Asterisk '*' has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onAsteriskPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onEscapePressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::escapePressed(KeyEvent event)
- This handler is called when the Escape key has been pressed. The \a event
+ This signal is emitted when the Escape key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onEscapePressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onReturnPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::returnPressed(KeyEvent event)
- This handler is called when the Return key has been pressed. The \a event
+ This signal is emitted when the Return key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onReturnPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onEnterPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::enterPressed(KeyEvent event)
- This handler is called when the Enter key has been pressed. The \a event
+ This signal is emitted when the Enter key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onEnterPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onDeletePressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::deletePressed(KeyEvent event)
- This handler is called when the Delete key has been pressed. The \a event
+ This signal is emitted when the Delete key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onDeletePressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onSpacePressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::spacePressed(KeyEvent event)
- This handler is called when the Space key has been pressed. The \a event
+ This signal is emitted when the Space key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onSpacePressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onBackPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::backPressed(KeyEvent event)
- This handler is called when the Back key has been pressed. The \a event
+ This signal is emitted when the Back key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onBackPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onCancelPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::cancelPressed(KeyEvent event)
- This handler is called when the Cancel key has been pressed. The \a event
+ This signal is emitted when the Cancel key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onCancelPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onSelectPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::selectPressed(KeyEvent event)
- This handler is called when the Select key has been pressed. The \a event
+ This signal is emitted when the Select key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onSelectPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onYesPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::yesPressed(KeyEvent event)
- This handler is called when the Yes key has been pressed. The \a event
+ This signal is emitted when the Yes key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onYesPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onNoPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::noPressed(KeyEvent event)
- This handler is called when the No key has been pressed. The \a event
+ This signal is emitted when the No key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onNoPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onContext1Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::context1Pressed(KeyEvent event)
- This handler is called when the Context1 key has been pressed. The \a event
+ This signal is emitted when the Context1 key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onContext1Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onContext2Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::context2Pressed(KeyEvent event)
- This handler is called when the Context2 key has been pressed. The \a event
+ This signal is emitted when the Context2 key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onContext2Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onContext3Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::context3Pressed(KeyEvent event)
- This handler is called when the Context3 key has been pressed. The \a event
+ This signal is emitted when the Context3 key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onContext3Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onContext4Pressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::context4Pressed(KeyEvent event)
- This handler is called when the Context4 key has been pressed. The \a event
+ This signal is emitted when the Context4 key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onContext4Pressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onCallPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::callPressed(KeyEvent event)
- This handler is called when the Call key has been pressed. The \a event
+ This signal is emitted when the Call key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onCallPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onHangupPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::hangupPressed(KeyEvent event)
- This handler is called when the Hangup key has been pressed. The \a event
+ This signal is emitted when the Hangup key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onHangupPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onFlipPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::flipPressed(KeyEvent event)
- This handler is called when the Flip key has been pressed. The \a event
+ This signal is emitted when the Flip key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onFlipPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onMenuPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::menuPressed(KeyEvent event)
- This handler is called when the Menu key has been pressed. The \a event
+ This signal is emitted when the Menu key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onMenuPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onVolumeUpPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::volumeUpPressed(KeyEvent event)
- This handler is called when the VolumeUp key has been pressed. The \a event
+ This signal is emitted when the VolumeUp key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onVolumeUpPressed.
*/
/*!
- \qmlsignal QtQuick::Keys::onVolumeDownPressed(KeyEvent event)
+ \qmlsignal QtQuick::Keys::volumeDownPressed(KeyEvent event)
- This handler is called when the VolumeDown key has been pressed. The \a event
+ This signal is emitted when the VolumeDown key has been pressed. The \a event
parameter provides information about the event.
+
+ The corresponding handler is \c onVolumeDownPressed.
*/
QQuickKeysAttached::QQuickKeysAttached(QObject *parent)
@@ -1256,7 +1334,7 @@ void QQuickKeysAttached::keyPressed(QKeyEvent *event, bool post)
for (int ii = 0; ii < d->targets.count(); ++ii) {
QQuickItem *i = d->targets.at(ii);
if (i && i->isVisible()) {
- d->item->window()->sendEvent(i, event);
+ QCoreApplication::sendEvent(i, event);
if (event->isAccepted()) {
d->inPress = false;
return;
@@ -1298,7 +1376,7 @@ void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post)
for (int ii = 0; ii < d->targets.count(); ++ii) {
QQuickItem *i = d->targets.at(ii);
if (i && i->isVisible()) {
- d->item->window()->sendEvent(i, event);
+ QCoreApplication::sendEvent(i, event);
if (event->isAccepted()) {
d->inRelease = false;
return;
@@ -1604,8 +1682,8 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
thumb is to only use classes with the "QSG" prefix inside the
QQuickItem::updatePaintNode() function.
- To read more about how the scene graph rendering works, see
- \l{Scene Graph and Rendering}
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
\section1 Custom QPainter Items
@@ -1667,12 +1745,12 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
\section2 Key Handling
Key handling is available to all Item-based visual types via the \l Keys
- attached property. The \e Keys attached property provides basic handlers
- such as \l {Keys::}{onPressed} and \l {Keys}{::onReleased}, as well as
- handlers for specific keys, such as \l {Keys::}{onSpacePressed}. The
+ attached property. The \e Keys attached property provides basic signals
+ such as \l {Keys::}{pressed} and \l {Keys::}{released}, as well as
+ signals for specific keys, such as \l {Keys::}{spacePressed}. The
example below assigns \l {Keyboard Focus in Qt Quick}{keyboard focus} to
- the item and handles the left key via the general \e onPressed handler
- and the return key via the onReturnPressed handler:
+ the item and handles the left key via the general \c onPressed handler
+ and the return key via the \c onReturnPressed handler:
\qml
import QtQuick 2.0
@@ -2055,8 +2133,6 @@ bool QQuickItemPrivate::qt_tab_all_widgets()
*/
bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
{
- bool result = true;
-
if (!item->window())
return false;
@@ -2064,14 +2140,13 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
return true;
#ifndef QT_NO_ACCESSIBILITY
- result = false;
if (QObject *acc = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(item, false)) {
int role = acc->property("role").toInt();
if (role == QAccessible::EditableText
|| role == QAccessible::Table
|| role == QAccessible::List
|| role == QAccessible::SpinBox) {
- result = true;
+ return true;
} else if (role == QAccessible::ComboBox) {
QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(item);
return iface->state().editable;
@@ -2079,7 +2154,11 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
}
#endif
- return result;
+ QVariant readonly = item->property("readOnly");
+ if (readonly.isValid() && !readonly.toBool() && item->property("text").isValid())
+ return true;
+
+ return false;
}
/*!
@@ -3348,6 +3427,9 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
in this function. Similarly for signals, these will be emitted on the render
thread and will thus often be delivered via queued connections.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
+
\sa QSGMaterial, QSGSimpleMaterial, QSGGeometryNode, QSGGeometry,
QSGFlatColorMaterial, QSGTextureMaterial, QSGNode::markDirty()
*/
@@ -6319,10 +6401,12 @@ void QQuickItem::setFocus(bool focus, Qt::FocusReason reason)
while (scope && !scope->isFocusScope() && scope->parentItem())
scope = scope->parentItem();
if (d->window) {
- if (focus)
- QQuickWindowPrivate::get(d->window)->setFocusInScope(scope, this, reason);
- else
- QQuickWindowPrivate::get(d->window)->clearFocusInScope(scope, this, reason);
+ if (reason != Qt::PopupFocusReason) {
+ if (focus)
+ QQuickWindowPrivate::get(d->window)->setFocusInScope(scope, this, reason);
+ else
+ QQuickWindowPrivate::get(d->window)->clearFocusInScope(scope, this, reason);
+ }
} else {
// do the focus changes from setFocusInScope/clearFocusInScope that are
// unrelated to a window
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index dc8230f6be..1436ab332f 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -127,13 +127,6 @@ static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject
return QQmlPrivate::IncompatibleParent;
}
-static bool compareQQuickAnchorLines(const void *p1, const void *p2)
-{
- const QQuickAnchorLine &l1 = *static_cast<const QQuickAnchorLine*>(p1);
- const QQuickAnchorLine &l2 = *static_cast<const QQuickAnchorLine*>(p2);
- return l1 == l2;
-}
-
static void qt_quickitems_defineModule(const char *uri, int major, int minor)
{
QQmlPrivate::RegisterAutoParent autoparent = { 0, &qquickitem_autoParent };
@@ -211,7 +204,6 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPen>();
qmlRegisterType<QQuickFlickableVisibleArea>();
qRegisterMetaType<QQuickAnchorLine>("QQuickAnchorLine");
- QQmlMetaType::setQQuickAnchorLineCompareFunction(compareQQuickAnchorLines);
qmlRegisterType<QQuickTextDocument>();
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index e51a562490..b4f6c34c6a 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -364,6 +364,8 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate)
if (!d->ownModel) {
d->model = new QQmlDelegateModel(qmlContext(this));
d->ownModel = true;
+ if (isComponentComplete())
+ static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
}
if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
int oldCount = dataModel->count();
@@ -906,12 +908,12 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
else
maxExtent = isContentFlowReversed() ? q->minXExtent()-size(): -q->maxXExtent();
if (!item) {
- int itemPos = positionAt(idx);
+ qreal itemPos = positionAt(idx);
changedVisibleIndex(idx);
// save the currently visible items in case any of them end up visible again
QList<FxViewItem *> oldVisible = visibleItems;
visibleItems.clear();
- setPosition(qMin(qreal(itemPos), maxExtent));
+ setPosition(qMin(itemPos, maxExtent));
// now release the reference to all the old visible items.
for (int i = 0; i < oldVisible.count(); ++i)
releaseItem(oldVisible.at(i));
@@ -2318,7 +2320,8 @@ void QQuickItemView::initItem(int, QObject *object)
{
QQuickItem* item = qmlobject_cast<QQuickItem*>(object);
if (item) {
- item->setZ(1);
+ if (qFuzzyIsNull(item->z()))
+ item->setZ(1);
item->setParentItem(contentItem());
QQuickItemPrivate::get(item)->setCulled(true);
}
@@ -2382,7 +2385,8 @@ QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component,
item = new QQuickItem;
}
if (item) {
- item->setZ(zValue);
+ if (qFuzzyIsNull(item->z()))
+ item->setZ(zValue);
QQml_setParent_noEvent(item, q->contentItem());
item->setParentItem(q->contentItem());
}
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 3ac28f438b..8f9dbb567f 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -966,7 +966,8 @@ QQuickItem * QQuickListViewPrivate::getSectionItem(const QString &section)
if (!sectionItem) {
delete nobj;
} else {
- sectionItem->setZ(2);
+ if (qFuzzyIsNull(sectionItem->z()))
+ sectionItem->setZ(2);
QQml_setParent_noEvent(sectionItem, contentItem);
sectionItem->setParentItem(contentItem);
}
@@ -1836,19 +1837,23 @@ QQuickListView::~QQuickListView()
*/
/*!
- \qmlattachedsignal QtQuick::ListView::onAdd()
- This attached signal handler is called immediately after an item is added to the view.
+ \qmlattachedsignal QtQuick::ListView::add()
+ This attached signal is emitted immediately after an item is added to the view.
If an \l add transition is specified, it is applied immediately after
- this signal handler is called.
+ this signal is handled.
+
+ The corresponding handler is \c onAdd.
*/
/*!
- \qmlattachedsignal QtQuick::ListView::onRemove()
- This attached handler is called immediately before an item is removed from the view.
+ \qmlattachedsignal QtQuick::ListView::remove()
+ This attached signal is emitted immediately before an item is removed from the view.
If a \l remove transition has been specified, it is applied after
- this signal handler is called, providing that delayRemove is false.
+ this signal is handled, providing that \l delayRemove is false.
+
+ The corresponding handler is \c onRemove.
*/
/*!
@@ -1881,6 +1886,8 @@ QQuickListView::~QQuickListView()
It is recommended that the delegate's size be a whole number to avoid sub-pixel
alignment of items.
+ The default \l {QQuickItem::z}{stacking order} of delegate instances is \c 1.
+
\note Delegates are instantiated as needed and may be destroyed at any time.
They are parented to ListView's \l {Flickable::contentItem}{contentItem}, not to the view itself.
State should \e never be stored in a delegate.
@@ -1908,6 +1915,8 @@ QQuickListView::~QQuickListView()
The \c highlightItem is managed by the view unless
\l highlightFollowsCurrentItem is set to false.
+ The default \l {QQuickItem::z}{stacking order}
+ of the highlight item is \c 0.
\sa highlight, highlightFollowsCurrentItem
*/
@@ -1924,7 +1933,8 @@ QQuickListView::~QQuickListView()
An instance of the highlight component is created for each list.
The geometry of the resulting component instance is managed by the list
so as to stay with the current item, unless the highlightFollowsCurrentItem
- property is false.
+ property is false. The default \l {QQuickItem::z}{stacking order} of the
+ highlight item is \c 0.
\sa highlightItem, highlightFollowsCurrentItem,
{Qt Quick Examples - Views#Highlight demonstrates adding a custom highlight to a ListView.}{ListView highlight example}
@@ -2202,7 +2212,9 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
A case insensitive comparison is used when determining section
boundaries.
- \c section.delegate holds the delegate component for each section.
+ \c section.delegate holds the delegate component for each section. The
+ default \l {QQuickItem::z}{stacking order} of section delegate instances
+ is \c 2.
\c section.labelPositioning determines whether the current and/or
next section labels stick to the start/end of the view, and whether
@@ -2388,7 +2400,8 @@ void QQuickListView::setSnapMode(SnapMode mode)
This property holds the component to use as the footer.
An instance of the footer component is created for each view. The
- footer is positioned at the end of the view, after any items.
+ footer is positioned at the end of the view, after any items. The
+ default \l {QQuickItem::z}{stacking order} of the footer is \c 1.
\sa header, footerItem
*/
@@ -2400,6 +2413,7 @@ void QQuickListView::setSnapMode(SnapMode mode)
An instance of the header component is created for each view. The
header is positioned at the beginning of the view, before any items.
+ The default \l {QQuickItem::z}{stacking order} of the header is \c 1.
\sa footer, headerItem
*/
@@ -2410,6 +2424,7 @@ void QQuickListView::setSnapMode(SnapMode mode)
An instance of the header component is created for each view. The
header is positioned at the beginning of the view, before any items.
+ The default \l {QQuickItem::z}{stacking order} of the header is \c 1.
\sa header, footerItem
*/
@@ -2419,7 +2434,8 @@ void QQuickListView::setSnapMode(SnapMode mode)
This holds the footer item created from the \l footer component.
An instance of the footer component is created for each view. The
- footer is positioned at the end of the view, after any items.
+ footer is positioned at the end of the view, after any items. The
+ default \l {QQuickItem::z}{stacking order} of the footer is \c 1.
\sa footer, headerItem
*/
@@ -2487,7 +2503,7 @@ void QQuickListView::setSnapMode(SnapMode mode)
populated, or when the view's \l model changes. (In those cases, the \l populate transition is
applied instead.) Additionally, this transition should \e not animate the height of the new item;
doing so will cause any items beneath the new item to be laid out at the wrong position. Instead,
- the height can be animated within \l onAdd in the delegate.
+ the height can be animated within the \l {add}{onAdd} handler in the delegate.
\sa addDisplaced, populate, ViewTransition
*/
@@ -2844,11 +2860,11 @@ void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &ol
Q_D(QQuickListView);
if (d->isRightToLeft()) {
// maintain position relative to the right edge
- int dx = newGeometry.width() - oldGeometry.width();
+ qreal dx = newGeometry.width() - oldGeometry.width();
setContentX(contentX() - dx);
} else if (d->isBottomToTop()) {
// maintain position relative to the bottom edge
- int dy = newGeometry.height() - oldGeometry.height();
+ qreal dy = newGeometry.height() - oldGeometry.height();
setContentY(contentY() - dy);
}
QQuickItemView::geometryChanged(newGeometry, oldGeometry);
@@ -2958,7 +2974,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Insert &ch
}
// index can be the next item past the end of the visible items list (i.e. appended)
- int pos = 0;
+ qreal pos = 0;
if (visibleItems.count()) {
pos = index < visibleItems.count() ? visibleItems.at(index)->position()
: visibleItems.last()->endPosition()+spacing;
@@ -2969,7 +2985,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Insert &ch
// Insert items before the visible item.
int insertionIdx = index;
int i = 0;
- int from = tempPos - displayMarginBeginning - buffer;
+ qreal from = tempPos - displayMarginBeginning - buffer;
for (i = count-1; i >= 0; --i) {
if (pos > from && insertionIdx < visibleIndex) {
@@ -3000,7 +3016,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Insert &ch
}
} else {
int i = 0;
- int to = buffer+displayMarginEnd+tempPos+size();
+ qreal to = buffer + displayMarginEnd + tempPos + size();
for (i = 0; i < count && pos <= to; ++i) {
FxViewItem *item = 0;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index debe4b7497..f8a4f26ec3 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -449,8 +449,7 @@ void QQuickLoader::loadFromSource()
}
\endqml
- To unload the currently loaded object, set this property to an empty string
- or \c undefined.
+ To unload the currently loaded object, set this property to \c undefined.
Since \c {QtQuick 2.0}, Loader is able to load any type of object; it
is not restricted to Item types.
@@ -816,10 +815,12 @@ void QQuickLoader::componentComplete()
}
/*!
- \qmlsignal QtQuick::Loader::onLoaded()
+ \qmlsignal QtQuick::Loader::loaded()
- This handler is called when the \l status becomes \c Loader.Ready, or on successful
+ This signal is emitted when the \l status becomes \c Loader.Ready, or on successful
initial load.
+
+ The corresponding handler is \c onLoaded.
*/
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 5aa72836b3..2d84660b6d 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -258,30 +258,32 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
*/
/*!
- \qmlsignal QtQuick::MouseArea::onEntered()
+ \qmlsignal QtQuick::MouseArea::entered()
- This handler is called when the mouse enters the mouse area.
+ This signal is emitted when the mouse enters the mouse area.
- By default the onEntered handler is only called while a button is
- pressed. Setting hoverEnabled to true enables handling of
- onEntered when no mouse button is pressed.
+ By default this signal is only emitted if a button is currently
+ pressed. Set \l hoverEnabled to true to emit this signal
+ even when no mouse button is pressed.
\sa hoverEnabled
+
+ The corresponding handler is \c onEntered.
*/
/*!
- \qmlsignal QtQuick::MouseArea::onExited()
+ \qmlsignal QtQuick::MouseArea::exited()
- This handler is called when the mouse exits the mouse area.
+ This signal is emitted when the mouse exits the mouse area.
- By default the onExited handler is only called while a button is
- pressed. Setting hoverEnabled to true enables handling of
- onExited when no mouse button is pressed.
+ By default this signal is only emitted if a button is currently
+ pressed. Set \l hoverEnabled to true to emit this signal
+ even when no mouse button is pressed.
The example below shows a fairly typical relationship between
two MouseAreas, with \c mouseArea2 on top of \c mouseArea1. Moving the
- mouse into \c mouseArea2 from \c mouseArea1 will cause \c onExited
- to be called for \c mouseArea1.
+ mouse into \c mouseArea2 from \c mouseArea1 will cause \c mouseArea1
+ to emit the \c exited signal.
\qml
Rectangle {
width: 400; height: 400
@@ -299,112 +301,134 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
}
\endqml
- If instead you give the two mouseAreas a parent-child relationship,
+ If instead you give the two MouseAreas a parent-child relationship,
moving the mouse into \c mouseArea2 from \c mouseArea1 will \b not
- cause \c onExited to be called for \c mouseArea1. Instead, they will
+ cause \c mouseArea1 to emit \c exited. Instead, they will
both be considered to be simultaneously hovered.
\sa hoverEnabled
+
+ The corresponding handler is \c onExited.
*/
/*!
- \qmlsignal QtQuick::MouseArea::onPositionChanged(MouseEvent mouse)
+ \qmlsignal QtQuick::MouseArea::positionChanged(MouseEvent mouse)
- This handler is called when the mouse position changes.
+ This signal is emitted when the mouse position changes.
The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
position, and any buttons currently pressed.
- The \e accepted property of the MouseEvent parameter is ignored in this handler.
+ By default this signal is only emitted if a button is currently
+ pressed. Set \l hoverEnabled to true to emit this signal
+ even when no mouse button is pressed.
+
+ When handling this signal, changing the \l {MouseEvent::}{accepted} property of the \a mouse
+ parameter has no effect.
- By default the onPositionChanged handler is only called while a button is
- pressed. Setting hoverEnabled to true enables handling of
- onPositionChanged when no mouse button is pressed.
+ The corresponding handler is \c onPositionChanged.
*/
/*!
- \qmlsignal QtQuick::MouseArea::onClicked(MouseEvent mouse)
+ \qmlsignal QtQuick::MouseArea::clicked(MouseEvent mouse)
- This handler is called when there is a click. A click is defined as a press followed by a release,
+ This signal is emitted when there is a click. A click is defined as a press followed by a release,
both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
releasing is also considered a click).
The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
position of the release of the click, and whether the click was held.
- The \e accepted property of the MouseEvent parameter is ignored in this handler.
+ When handling this signal, changing the \l {MouseEvent::}{accepted} property of the \a mouse
+ parameter has no effect.
+
+ The corresponding handler is \c onClicked.
*/
/*!
- \qmlsignal QtQuick::MouseArea::onPressed(MouseEvent mouse)
+ \qmlsignal QtQuick::MouseArea::pressed(MouseEvent mouse)
- This handler is called when there is a press.
+ This signal is emitted when there is a press.
The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
position and which button was pressed.
- The \e accepted property of the MouseEvent parameter determines whether this MouseArea
- will handle the press and all future mouse events until release. The default is to accept
- the event and not allow other MouseArea beneath this one to handle the event. If \e accepted
- is set to false, no further events will be sent to this MouseArea until the button is next
- pressed.
+ When handling this signal, use the \l {MouseEvent::}{accepted} property of the \a mouse
+ parameter to control whether this MouseArea handles the press and all future mouse events until
+ release. The default is to accept the event and not allow other MouseAreas beneath this one to
+ handle the event. If \e accepted is set to false, no further events will be sent to this MouseArea
+ until the button is next pressed.
+
+ The corresponding handler is \c onPressed.
*/
/*!
- \qmlsignal QtQuick::MouseArea::onReleased(MouseEvent mouse)
+ \qmlsignal QtQuick::MouseArea::released(MouseEvent mouse)
- This handler is called when there is a release.
+ This signal is emitted when there is a release.
The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
position of the release of the click, and whether the click was held.
- The \e accepted property of the MouseEvent parameter is ignored in this handler.
+ When handling this signal, changing the \l {MouseEvent::}{accepted} property of the \a mouse
+ parameter has no effect.
- \sa onCanceled
+ The corresponding handler is \c onReleased.
+
+ \sa canceled
*/
/*!
- \qmlsignal QtQuick::MouseArea::onPressAndHold(MouseEvent mouse)
+ \qmlsignal QtQuick::MouseArea::pressAndHold(MouseEvent mouse)
- This handler is called when there is a long press (currently 800ms).
+ This signal is emitted when there is a long press (currently 800ms).
The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
position of the press, and which button is pressed.
- The \e accepted property of the MouseEvent parameter is ignored in this handler.
+ When handling this signal, changing the \l {MouseEvent::}{accepted} property of the \a mouse
+ parameter has no effect.
+
+ The corresponding handler is \c onPressAndHold.
*/
/*!
- \qmlsignal QtQuick::MouseArea::onDoubleClicked(MouseEvent mouse)
+ \qmlsignal QtQuick::MouseArea::doubleClicked(MouseEvent mouse)
- This handler is called when there is a double-click (a press followed by a release followed by a press).
+ This signal is emitted when there is a double-click (a press followed by a release followed by a press).
The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
position of the release of the click, and whether the click was held.
- If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
- in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
- click; otherwise they are suppressed. The accepted property defaults to true.
+ When handling this signal, if the \l {MouseEvent::}{accepted} property of the \a mouse
+ parameter is set to false, the pressed/released/clicked signals will be emitted for the second
+ click; otherwise they are suppressed. The \c accepted property defaults to true.
+
+ The corresponding handler is \c onDoubleClicked.
*/
/*!
- \qmlsignal QtQuick::MouseArea::onCanceled()
+ \qmlsignal QtQuick::MouseArea::canceled()
- This handler is called when mouse events have been canceled, either because an event was not accepted, or
+ 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 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
- case, if you execute some logic on the pressed signal and then start dragging, the
+ case, if you execute some logic in the \c onPressed signal handler and then start dragging, the
\l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
the logic when the MouseArea has lost the mouse handling to the \l Flickable,
- \c onCanceled should be used in addition to onReleased.
+ \c canceled should be handled in addition to \l released.
+
+ The corresponding handler is \c onCanceled.
*/
/*!
- \qmlsignal QtQuick::MouseArea::onWheel(WheelEvent wheel)
+ \qmlsignal QtQuick::MouseArea::wheel(WheelEvent wheel)
- This handler is called in response to both mouse wheel and trackpad scroll gestures.
+ This signal is emitted in response to both mouse wheel and trackpad scroll gestures.
The \l {WheelEvent}{wheel} parameter provides information about the event, including the x and y
position, any buttons currently pressed, and information about the wheel movement, including
angleDelta and pixelDelta.
+
+ The corresponding handler is \c onWheel.
*/
QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
@@ -1217,7 +1241,7 @@ void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
\c drag.axis. For example, if \c anchors.left or \c anchors.right was set
for \c rect in the above example, it cannot be dragged along the X-axis.
This can be avoided by settng the anchor value to \c undefined in
- an \l onPressed handler.
+ an \l {pressed}{onPressed} handler.
If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 6a5ba931c7..c20559454e 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -259,60 +259,72 @@ void QQuickTouchPoint::setSceneY(qreal sceneY)
*/
/*!
- \qmlsignal QtQuick::MultiPointTouchArea::onPressed(list<TouchPoint> touchPoints)
+ \qmlsignal QtQuick::MultiPointTouchArea::pressed(list<TouchPoint> touchPoints)
- This handler is called when new touch points are added. \a touchPoints is a list of these new points.
+ This signal is emitted when new touch points are added. \a touchPoints is a list of these new points.
- If minimumTouchPoints is set to a value greater than one, this handler will not be called until the minimum number
- of required touch points has been reached. At that point, onPressed will be called with all the current touch points.
+ If minimumTouchPoints is set to a value greater than one, this signal will not be emitted until the minimum number
+ of required touch points has been reached.
+
+ The corresponding handler is \c onPressed.
*/
/*!
- \qmlsignal QtQuick::MultiPointTouchArea::onUpdated(list<TouchPoint> touchPoints)
+ \qmlsignal QtQuick::MultiPointTouchArea::updated(list<TouchPoint> touchPoints)
+
+ This signal is emitted when existing touch points are updated. \a touchPoints is a list of these updated points.
- This handler is called when existing touch points are updated. \a touchPoints is a list of these updated points.
+ The corresponding handler is \c onUpdated.
*/
/*!
- \qmlsignal QtQuick::MultiPointTouchArea::onReleased(list<TouchPoint> touchPoints)
+ \qmlsignal QtQuick::MultiPointTouchArea::released(list<TouchPoint> touchPoints)
+
+ This signal is emitted when existing touch points are removed. \a touchPoints is a list of these removed points.
- This handler is called when existing touch points are removed. \a touchPoints is a list of these removed points.
+ The corresponding handler is \c onReleased.
*/
/*!
- \qmlsignal QtQuick::MultiPointTouchArea::onCanceled(list<TouchPoint> touchPoints)
+ \qmlsignal QtQuick::MultiPointTouchArea::canceled(list<TouchPoint> touchPoints)
- This handler is called when new touch events have been canceled because another item stole the touch event handling.
+ This signal is emitted when new touch events have been canceled because another item stole the touch event handling.
This signal is for advanced use: it is useful when there is more than one MultiPointTouchArea
that is handling input, or when there is a MultiPointTouchArea inside a \l Flickable. In the latter
- case, if you execute some logic on the onPressed signal and then start dragging, the
+ case, if you execute some logic in the \c onPressed signal handler and then start dragging, the
\l Flickable may steal the touch handling from the MultiPointTouchArea. In these cases, to reset
the logic when the MultiPointTouchArea has lost the touch handling to the \l Flickable,
- \c onCanceled should be used in addition to onReleased.
+ \c canceled should be handled in addition to \l released.
\a touchPoints is the list of canceled points.
+
+ The corresponding handler is \c onCanceled.
*/
/*!
- \qmlsignal QtQuick::MultiPointTouchArea::onGestureStarted(GestureEvent gesture)
+ \qmlsignal QtQuick::MultiPointTouchArea::gestureStarted(GestureEvent gesture)
- This handler is called when the global drag threshold has been reached.
+ This signal is emitted when the global drag threshold has been reached.
- This function is typically used when a MultiPointTouchAreas has been nested in a Flickable or another MultiPointTouchArea.
- When the threshold has been reached, and the handler called, you can determine whether or not the touch
+ This signal is typically used when a MultiPointTouchArea has been nested in a Flickable or another MultiPointTouchArea.
+ When the threshold has been reached and the signal is handled, you can determine whether or not the touch
area should grab the current touch points. By default they will not be grabbed; to grab them call \c gesture.grab(). If the
gesture is not grabbed, the nesting Flickable, for example, would also have an opportunity to grab.
The gesture object also includes information on the current set of \c touchPoints and the \c dragThreshold.
+
+ The corresponding handler is \c onGestureStarted.
*/
/*!
- \qmlsignal QtQuick::MultiPointTouchArea::onTouchUpdated(list<TouchPoint> touchPoints)
+ \qmlsignal QtQuick::MultiPointTouchArea::touchUpdated(list<TouchPoint> touchPoints)
- This handler is called when the touch points handled by the MultiPointTouchArea change. This includes adding new touch points,
+ This signal is emitted when the touch points handled by the MultiPointTouchArea change. This includes adding new touch points,
removing or canceling previous touch points, as well as updating current touch point data. \a touchPoints is the list of all current touch
points.
+
+ The corresponding handler is \c onTouchUpdated.
*/
/*!
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 0080f54d20..45cd8e184c 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -1147,50 +1147,62 @@ bool QQuickPathView::isDragging() const
}
/*!
- \qmlsignal QtQuick::PathView::onMovementStarted()
+ \qmlsignal QtQuick::PathView::movementStarted()
- This handler is called when the view begins moving due to user
+ This signal is emitted when the view begins moving due to user
interaction.
+
+ The corresponding handler is \c onMovementStarted.
*/
/*!
- \qmlsignal QtQuick::PathView::onMovementEnded()
+ \qmlsignal QtQuick::PathView::movementEnded()
- This handler is called when the view stops moving due to user
- interaction. If a flick was generated, this handler will
- be triggered once the flick stops. If a flick was not
- generated, the handler will be triggered when the
+ This signal is emitted when the view stops moving due to user
+ interaction. If a flick was generated, this signal will
+ be emitted once the flick stops. If a flick was not
+ generated, this signal will be emitted when the
user stops dragging - i.e. a mouse or touch release.
+
+ The corresponding handler is \c onMovementEnded.
*/
/*!
- \qmlsignal QtQuick::PathView::onFlickStarted()
+ \qmlsignal QtQuick::PathView::flickStarted()
- This handler is called when the view is flicked. A flick
+ This signal is emitted when the view is flicked. A flick
starts from the point that the mouse or touch is released,
while still in motion.
+
+ The corresponding handler is \c onFlickStarted.
*/
/*!
- \qmlsignal QtQuick::PathView::onFlickEnded()
+ \qmlsignal QtQuick::PathView::flickEnded()
- This handler is called when the view stops moving due to a flick.
+ This signal is emitted when the view stops moving due to a flick.
+
+ The corresponding handler is \c onFlickEnded.
*/
/*!
- \qmlsignal QtQuick::PathView::onDragStarted()
+ \qmlsignal QtQuick::PathView::dragStarted()
- This handler is called when the view starts to be dragged due to user
+ This signal is emitted when the view starts to be dragged due to user
interaction.
+
+ The corresponding handler is \c onDragStarted.
*/
/*!
- \qmlsignal QtQuick::PathView::onDragEnded()
+ \qmlsignal QtQuick::PathView::dragEnded()
- This handler is called when the user stops dragging the view.
+ This signal is emitted when the user stops dragging the view.
If the velocity of the drag is suffient at the time the
touch/mouse button is released then a flick will start.
+
+ The corresponding handler is \c onDragEnded.
*/
/*!
@@ -1230,6 +1242,8 @@ void QQuickPathView::setDelegate(QQmlComponent *delegate)
if (!d->ownModel) {
d->model = new QQmlDelegateModel(qmlContext(this));
d->ownModel = true;
+ if (isComponentComplete())
+ static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
}
if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
int oldCount = dataModel->count();
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index c2ca66f840..234f78c380 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -100,7 +100,7 @@ QT_BEGIN_NAMESPACE
\li \c previousScale is the scale factor of the previous event.
\endlist
- When a pinch gesture is started, the scale is 1.0.
+ When a pinch gesture is started, the scale is \c 1.0.
*/
/*!
@@ -116,7 +116,7 @@ QT_BEGIN_NAMESPACE
\li \c rotation is the total rotation since the pinch gesture started.
\endlist
- When a pinch gesture is started, the rotation is 0.0.
+ When a pinch gesture is started, the rotation is \c 0.0.
*/
/*!
@@ -190,33 +190,50 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate()
*/
/*!
- \qmlsignal QtQuick::PinchArea::onPinchStarted()
+ \qmlsignal QtQuick::PinchArea::pinchStarted()
- This handler is called when the pinch area detects that a pinch gesture has started.
+ This signal is emitted when the pinch area detects that a pinch gesture has
+ started: two touch points (fingers) have been detected, and they have moved
+ beyond the \l {QStyleHints}{startDragDistance} threshold for the gesture to begin.
- The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
- including the scale, center and angle of the pinch.
+ The \l {PinchEvent}{pinch} parameter (not the same as the \l {PinchArea}{pinch}
+ property) provides information about the pinch gesture, including the scale,
+ center and angle of the pinch. At the time of the \c pinchStarted signal,
+ these values are reset to the default values, regardless of the results
+ from previous gestures: pinch.scale will be \c 1.0 and pinch.rotation will be \c 0.0.
+ As the gesture progresses, \l pinchUpdated will report the deviation from those
+ defaults.
To ignore this gesture set the \c pinch.accepted property to false. The gesture
will be canceled and no further events will be sent.
+
+ The corresponding handler is \c onPinchStarted.
*/
/*!
- \qmlsignal QtQuick::PinchArea::onPinchUpdated()
+ \qmlsignal QtQuick::PinchArea::pinchUpdated()
+
+ This signal is emitted when the pinch area detects that a pinch gesture has changed.
- This handler is called when the pinch area detects that a pinch gesture has changed.
+ The \l {PinchEvent}{pinch} parameter provides information about the pinch
+ gesture, including the scale, center and angle of the pinch. These values
+ reflect changes only since the beginning of the current gesture, and
+ therefore are not limited by the minimum and maximum limits in the
+ \l {PinchArea}{pinch} property.
- The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
- including the scale, center and angle of the pinch.
+ The corresponding handler is \c onPinchUpdated.
*/
/*!
- \qmlsignal QtQuick::PinchArea::onPinchFinished()
+ \qmlsignal QtQuick::PinchArea::pinchFinished()
- This handler is called when the pinch area detects that a pinch gesture has finished.
+ This signal is emitted when the pinch area detects that a pinch gesture has finished.
- The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
- including the scale, center and angle of the pinch.
+ The \l {PinchEvent}{pinch} parameter (not the same as the \l {PinchArea}{pinch}
+ property) provides information about the pinch gesture, including the
+ scale, center and angle of the pinch.
+
+ The corresponding handler is \c onPinchFinished.
*/
@@ -239,8 +256,8 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate()
\list
\li \c pinch.target specifies the id of the item to drag.
\li \c pinch.active specifies if the target item is currently being dragged.
- \li \c pinch.minimumScale and \c pinch.maximumScale limit the range of the Item::scale property.
- \li \c pinch.minimumRotation and \c pinch.maximumRotation limit the range of the Item::rotation property.
+ \li \c pinch.minimumScale and \c pinch.maximumScale limit the range of the Item.scale property, but not the \c PinchEvent \l {PinchEvent}{scale} property.
+ \li \c pinch.minimumRotation and \c pinch.maximumRotation limit the range of the Item.rotation property, but not the \c PinchEvent \l {PinchEvent}{rotation} property.
\li \c pinch.dragAxis specifies whether dragging in not allowed (\c Pinch.NoDrag), can be done horizontally (\c Pinch.XAxis), vertically (\c Pinch.YAxis), or both (\c Pinch.XAndYAxis)
\li \c pinch.minimum and \c pinch.maximum limit how far the target can be dragged along the corresponding axes.
\endlist
@@ -360,6 +377,39 @@ void QQuickPinchArea::updatePinch()
Q_D(QQuickPinchArea);
QQuickWindow *win = window();
+
+ if (d->touchPoints.count() < 2) {
+ setKeepMouseGrab(false);
+ QQuickWindow *c = window();
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ }
+
+ if (d->touchPoints.count() == 0) {
+ if (d->inPinch) {
+ d->inPinch = false;
+ QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
+ QQuickPinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(pinchCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ emit pinchFinished(&pe);
+ d->pinchStartDist = 0;
+ d->pinchActivated = false;
+ if (d->pinch && d->pinch->target())
+ d->pinch->setActive(false);
+ }
+ d->initPinch = false;
+ d->pinchRejected = false;
+ d->stealMouse = false;
+ return;
+ }
+
QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0);
@@ -404,48 +454,57 @@ void QQuickPinchArea::updatePinch()
if (angle > 180)
angle -= 360;
if (!d->inPinch || d->initPinch) {
- if (d->touchPoints.count() >= 2
- && (qAbs(p1.x()-d->sceneStartPoint1.x()) >= dragThreshold
- || qAbs(p1.y()-d->sceneStartPoint1.y()) >= dragThreshold
- || qAbs(p2.x()-d->sceneStartPoint2.x()) >= dragThreshold
- || qAbs(p2.y()-d->sceneStartPoint2.y()) >= dragThreshold)) {
- d->initPinch = false;
+ if (d->touchPoints.count() >= 2) {
+ if (d->initPinch) {
+ if (!d->inPinch)
+ d->pinchStartDist = dist;
+ d->initPinch = false;
+ }
d->sceneStartCenter = sceneCenter;
d->sceneLastCenter = sceneCenter;
d->pinchStartCenter = mapFromScene(sceneCenter);
- d->pinchStartDist = dist;
d->pinchStartAngle = angle;
d->pinchLastScale = 1.0;
d->pinchLastAngle = angle;
d->pinchRotation = 0.0;
d->lastPoint1 = p1;
d->lastPoint2 = p2;
- QQuickPinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
- pe.setStartCenter(d->pinchStartCenter);
- pe.setPreviousCenter(d->pinchStartCenter);
- pe.setPreviousAngle(d->pinchLastAngle);
- pe.setPreviousScale(d->pinchLastScale);
- pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
- pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
- pe.setPoint1(mapFromScene(d->lastPoint1));
- pe.setPoint2(mapFromScene(d->lastPoint2));
- pe.setPointCount(d->touchPoints.count());
- emit pinchStarted(&pe);
- if (pe.accepted()) {
- if (win && win->mouseGrabberItem() != this)
- grabMouse();
- setKeepMouseGrab(true);
- grabTouchPoints(QVector<int>() << touchPoint1.id() << touchPoint2.id());
- d->inPinch = true;
- d->stealMouse = true;
- if (d->pinch && d->pinch->target()) {
- d->pinchStartPos = pinch()->target()->position();
- d->pinchStartScale = d->pinch->target()->scale();
- d->pinchStartRotation = d->pinch->target()->rotation();
- d->pinch->setActive(true);
+ if (qAbs(dist - d->pinchStartDist) >= dragThreshold ||
+ (pinch()->axis() != QQuickPinch::NoDrag &&
+ (qAbs(p1.x()-d->sceneStartPoint1.x()) >= dragThreshold
+ || qAbs(p1.y()-d->sceneStartPoint1.y()) >= dragThreshold
+ || qAbs(p2.x()-d->sceneStartPoint2.x()) >= dragThreshold
+ || qAbs(p2.y()-d->sceneStartPoint2.y()) >= dragThreshold))) {
+ QQuickPinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
+ d->pinchStartDist = dist;
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(d->pinchStartCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ pe.setPointCount(d->touchPoints.count());
+ emit pinchStarted(&pe);
+ if (pe.accepted()) {
+ d->inPinch = true;
+ d->stealMouse = true;
+ if (win && win->mouseGrabberItem() != this)
+ grabMouse();
+ setKeepMouseGrab(true);
+ grabTouchPoints(QVector<int>() << touchPoint1.id() << touchPoint2.id());
+ d->inPinch = true;
+ d->stealMouse = true;
+ if (d->pinch && d->pinch->target()) {
+ d->pinchStartPos = pinch()->target()->position();
+ d->pinchStartScale = d->pinch->target()->scale();
+ d->pinchStartRotation = d->pinch->target()->rotation();
+ d->pinch->setActive(true);
+ }
+ } else {
+ d->pinchRejected = true;
}
- } else {
- d->pinchRejected = true;
}
}
} else if (d->pinchStartDist > 0) {
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 4a199d9352..55736c33c3 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -220,7 +220,7 @@ QImage QQuickRenderControl::grab()
return QImage();
render();
- QImage grabContent = qt_gl_read_framebuffer(d->window->size(), false, false);
+ QImage grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->devicePixelRatio(), false, false);
return grabContent;
}
@@ -248,4 +248,34 @@ QQuickWindow *QQuickRenderControl::window() const
return d->window;
}
+/*!
+ \fn QWindow *QQuickRenderControl::renderWindow(QPoint *offset)
+
+ Reimplemented in subclasses to return the real window this render control
+ is rendering into.
+
+ If \a offset in non-null, it is set to the offset of the control
+ inside the window.
+*/
+
+/*!
+ Returns the real window that \a win is being rendered to, if any.
+
+ If \a offset in non-null, it is set to the offset of the rendering
+ inside its window.
+
+ */
+
+QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
+{
+ if (!win)
+ return 0;
+ QQuickRenderControl *rc = QQuickWindowPrivate::get(win)->renderControl;
+ if (rc)
+ return rc->renderWindow(offset);
+ return 0;
+}
+
+
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickrendercontrol_p.h b/src/quick/items/qquickrendercontrol_p.h
index 98dc946303..e7b7759afa 100644
--- a/src/quick/items/qquickrendercontrol_p.h
+++ b/src/quick/items/qquickrendercontrol_p.h
@@ -63,6 +63,8 @@ public:
~QQuickRenderControl();
QQuickWindow *window() const;
+ virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return 0; }
+ static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = 0);
void windowDestroyed();
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 072bfab73c..e226d7ba49 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -131,22 +131,26 @@ QQuickRepeaterPrivate::~QQuickRepeaterPrivate()
*/
/*!
- \qmlsignal QtQuick::Repeater::onItemAdded(int index, Item item)
+ \qmlsignal QtQuick::Repeater::itemAdded(int index, Item item)
- This handler is called when an item is added to the repeater. The \a index
+ This signal is emitted when an item is added to the repeater. The \a index
parameter holds the index at which the item has been inserted within the
repeater, and the \a item parameter holds the \l Item that has been added.
+
+ The corresponding handler is \c onItemAdded.
*/
/*!
- \qmlsignal QtQuick::Repeater::onItemRemoved(int index, Item item)
+ \qmlsignal QtQuick::Repeater::itemRemoved(int index, Item item)
- This handler is called when an item is removed from the repeater. The \a index
+ This signal is emitted when an item is removed from the repeater. The \a index
parameter holds the index at which the item was removed from the repeater,
and the \a item parameter holds the \l Item that was removed.
Do not keep a reference to \a item if it was created by this repeater, as
- in these cases it will be deleted shortly after the handler is called.
+ in these cases it will be deleted shortly after the signal is handled.
+
+ The corresponding handler is \c onItemRemoved.
*/
QQuickRepeater::QQuickRepeater(QQuickItem *parent)
: QQuickItem(*(new QQuickRepeaterPrivate), parent)
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 54c7527eec..82f4f0af3e 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -108,9 +108,9 @@ QT_BEGIN_NAMESPACE
such as task bars and system menus. If you want to position a Window at
the right of the desktop, you can bind to it like this:
- \qml
+ \code
x: Screen.desktopAvailableWidth - width
- \endqml
+ \endcode
*/
/*!
\qmlattachedproperty int Screen::desktopAvailableHeight
@@ -122,9 +122,9 @@ QT_BEGIN_NAMESPACE
such as task bars and system menus. If you want to position a Window at
the bottom of the desktop, you can bind to it like this:
- \qml
+ \code
y: Screen.desktopAvailableHeight - height
- \endqml
+ \endcode
*/
/*!
\qmlattachedproperty real Screen::logicalPixelDensity
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 287173957f..312cd483e2 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -1250,9 +1250,9 @@ QQuickText::~QQuickText()
*/
/*!
- \qmlsignal QtQuick::Text::onLineLaidOut(object line)
+ \qmlsignal QtQuick::Text::lineLaidOut(object line)
- This handler is called for each line of text that is laid out during the layout
+ This signal is emitted for each line of text that is laid out during the layout
process. The specified \a line object provides more details about the line that
is currently being laid out.
@@ -1277,12 +1277,14 @@ QQuickText::~QQuickText()
}
}
\endcode
+
+ The corresponding handler is \c onLineLaidOut.
*/
/*!
- \qmlsignal QtQuick::Text::onLinkActivated(string link)
+ \qmlsignal QtQuick::Text::linkActivated(string link)
- This handler is called when the user clicks on a link embedded in the text.
+ This signal is emitted when the user clicks on a link embedded in the text.
The link must be in rich text or HTML format and the
\a link string provides access to the particular link.
@@ -1293,6 +1295,8 @@ QQuickText::~QQuickText()
Clicking on the highlighted link will output
\tt{http://qt-project.org link activated} to the console.
+
+ The corresponding handler is \c onLinkActivated.
*/
/*!
@@ -2566,13 +2570,15 @@ bool QQuickTextPrivate::isLinkHoveredConnected()
}
/*!
- \qmlsignal QtQuick::Text::onLinkHovered(string link)
+ \qmlsignal QtQuick::Text::linkHovered(string link)
\since 5.2
- This handler is called when the user hovers a link embedded in the
+ This signal is emitted when the user hovers a link embedded in the
text. The link must be in rich text or HTML format and the \a link
string provides access to the particular link.
+ The corresponding handler is \c onLinkHovered.
+
\sa hoveredLink, linkAt()
*/
@@ -2584,7 +2590,7 @@ bool QQuickTextPrivate::isLinkHoveredConnected()
embedded in the text. The link must be in rich text or HTML format
and the \a hoveredLink string provides access to the particular link.
- \sa onLinkHovered, linkAt()
+ \sa linkHovered, linkAt()
*/
QString QQuickText::hoveredLink() const
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 0a9677bd4e..53d736fb36 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -1365,6 +1365,11 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
{
+ return inputMethodQuery(property, QVariant());
+}
+
+QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
+{
Q_D(const QQuickTextControl);
QTextBlock block = d->cursor.block();
switch (property) {
@@ -1382,6 +1387,47 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property) cons
return QVariant(); // No limit.
case Qt::ImAnchorPosition:
return QVariant(d->cursor.anchor() - block.position());
+ case Qt::ImAbsolutePosition:
+ return QVariant(d->cursor.anchor());
+ case Qt::ImTextAfterCursor:
+ {
+ int maxLength = argument.isValid() ? argument.toInt() : 1024;
+ QTextCursor tmpCursor = d->cursor;
+ int localPos = d->cursor.position() - block.position();
+ QString result = block.text().mid(localPos);
+ while (result.length() < maxLength) {
+ int currentBlock = tmpCursor.blockNumber();
+ tmpCursor.movePosition(QTextCursor::NextBlock);
+ if (tmpCursor.blockNumber() == currentBlock)
+ break;
+ result += QLatin1Char('\n') + tmpCursor.block().text();
+ }
+ return QVariant(result);
+ }
+ case Qt::ImTextBeforeCursor:
+ {
+ int maxLength = argument.isValid() ? argument.toInt() : 1024;
+ QTextCursor tmpCursor = d->cursor;
+ int localPos = d->cursor.position() - block.position();
+ int numBlocks = 0;
+ int resultLen = localPos;
+ while (resultLen < maxLength) {
+ int currentBlock = tmpCursor.blockNumber();
+ tmpCursor.movePosition(QTextCursor::PreviousBlock);
+ if (tmpCursor.blockNumber() == currentBlock)
+ break;
+ numBlocks++;
+ resultLen += tmpCursor.block().length();
+ }
+ QString result;
+ while (numBlocks) {
+ result += tmpCursor.block().text() + QLatin1Char('\n');
+ tmpCursor.movePosition(QTextCursor::NextBlock);
+ --numBlocks;
+ }
+ result += block.text().mid(0,localPos);
+ return QVariant(result);
+ }
default:
return QVariant();
}
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index bc5371b0c3..39221ced11 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -160,6 +160,7 @@ public:
#ifndef QT_NO_IM
virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+ Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
#endif
virtual QMimeData *createMimeDataFromSelection() const;
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 6fc1a3f4a5..3c4d0d4b42 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -116,11 +116,13 @@ TextEdit {
*/
/*!
- \qmlsignal QtQuick::TextEdit::onLinkActivated(string link)
+ \qmlsignal QtQuick::TextEdit::linkActivated(string link)
- This handler is called when the user clicks on a link embedded in the text.
+ This signal is emitted when the user clicks on a link embedded in the text.
The link must be in rich text or HTML format and the
\a link string provides access to the particular link.
+
+ The corresponding handler is \c onLinkActivated.
*/
// This is a pretty arbitrary figure. The idea is that we don't want to break down the document
@@ -2009,6 +2011,7 @@ void QQuickTextEditPrivate::init()
qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(redoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged()));
qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize()));
QObject::connect(document, &QQuickTextDocumentWithImageResources::contentsChange, q, &QQuickTextEdit::q_contentsChange);
+ QObject::connect(document->documentLayout(), &QAbstractTextDocumentLayout::updateBlock, q, &QQuickTextEdit::invalidateBlock);
document->setDefaultFont(font);
document->setDocumentMargin(textMargin);
@@ -2243,6 +2246,11 @@ void QQuickTextEdit::updateWholeDocument()
}
}
+void QQuickTextEdit::invalidateBlock(const QTextBlock &block)
+{
+ markDirtyNodesForRange(block.position(), block.position() + block.length(), 0);
+}
+
void QQuickTextEdit::updateCursor()
{
Q_D(QQuickTextEdit);
@@ -2509,13 +2517,15 @@ bool QQuickTextEditPrivate::isLinkHoveredConnected()
}
/*!
- \qmlsignal QtQuick::TextEdit::onLinkHovered(string link)
+ \qmlsignal QtQuick::TextEdit::linkHovered(string link)
\since 5.2
- This handler is called when the user hovers a link embedded in the text.
+ This signal is emitted when the user hovers a link embedded in the text.
The link must be in rich text or HTML format and the
\a link string provides access to the particular link.
+ The corresponding handler is \c onLinkHovered.
+
\sa hoveredLink, linkAt()
*/
@@ -2527,7 +2537,7 @@ bool QQuickTextEditPrivate::isLinkHoveredConnected()
embedded in the text. The link must be in rich text or HTML format
and the link string provides access to the particular link.
- \sa onLinkHovered, linkAt()
+ \sa linkHovered, linkAt()
*/
QString QQuickTextEdit::hoveredLink() const
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index b84552d255..c6b7ce3699 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -50,6 +50,8 @@ QT_BEGIN_NAMESPACE
class QQuickTextDocument;
class QQuickTextEditPrivate;
+class QTextBlock;
+
class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
{
Q_OBJECT
@@ -326,6 +328,7 @@ private Q_SLOTS:
void createCursor();
void q_canPasteChanged();
void updateWholeDocument();
+ void invalidateBlock(const QTextBlock &block);
void updateCursor();
void q_updateAlignment();
void updateSize();
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 26dda5db6b..41eb5c0bde 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1201,23 +1201,27 @@ bool QQuickTextInput::hasAcceptableInput() const
}
/*!
- \qmlsignal QtQuick::TextInput::onAccepted()
+ \qmlsignal QtQuick::TextInput::accepted()
- This handler is called when the Return or Enter key is pressed.
+ This signal is emitted when the Return or Enter key is pressed.
Note that if there is a \l validator or \l inputMask set on the text
- input, the handler will only be emitted if the input is in an acceptable
+ input, the signal will only be emitted if the input is in an acceptable
state.
+
+ The corresponding handler is \c onAccepted.
*/
/*!
- \qmlsignal QtQuick::TextInput::onEditingFinished()
+ \qmlsignal QtQuick::TextInput::editingFinished()
\since 5.2
- This handler is called when the Return or Enter key is pressed or
+ This signal is emitted when the Return or Enter key is pressed or
the text input loses focus. Note that if there is a validator or
inputMask set on the text input and enter/return is pressed, this
- handler will only be called if the input follows
+ signal will only be emitted if the input follows
the inputMask and the validator returns an acceptable state.
+
+ The corresponding handler is \c onEditingFinished.
*/
#ifndef QT_NO_IM
@@ -2360,7 +2364,6 @@ void QQuickTextInput::setPersistentSelection(bool on)
emit persistentSelectionChanged();
}
-#ifndef QT_NO_CLIPBOARD
/*!
\qmlproperty bool QtQuick::TextInput::canPaste
@@ -2369,6 +2372,7 @@ void QQuickTextInput::setPersistentSelection(bool on)
*/
bool QQuickTextInput::canPaste() const
{
+#if !defined(QT_NO_CLIPBOARD)
Q_D(const QQuickTextInput);
if (!d->canPasteValid) {
if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
@@ -2376,8 +2380,10 @@ bool QQuickTextInput::canPaste() const
const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
}
return d->canPaste;
-}
+#else
+ return false;
#endif
+}
/*!
\qmlproperty bool QtQuick::TextInput::canUndo
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index 5a88273543..211aba8703 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -100,9 +100,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged)
Q_PROPERTY(bool persistentSelection READ persistentSelection WRITE setPersistentSelection NOTIFY persistentSelectionChanged)
-#ifndef QT_NO_CLIPBOARD
Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged)
-#endif
Q_PROPERTY(bool canUndo READ canUndo NOTIFY canUndoChanged)
Q_PROPERTY(bool canRedo READ canRedo NOTIFY canRedoChanged)
#ifndef QT_NO_IM
@@ -261,9 +259,7 @@ public:
QRectF boundingRect() const;
QRectF clipRect() const;
-#ifndef QT_NO_CLIPBOARD
bool canPaste() const;
-#endif
bool canUndo() const;
bool canRedo() const;
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index 82c1b3a6ae..72c66448b4 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -58,16 +58,16 @@ QT_BEGIN_NAMESPACE
DEFINE_OBJECT_VTABLE(QQuickRootItemMarker);
-QQuickRootItemMarker::QQuickRootItemMarker(QQuickViewPrivate *view)
- : QV4::Object(QQmlEnginePrivate::getV4Engine(view->engine.data()))
- , view(view)
+QQuickRootItemMarker::QQuickRootItemMarker(QQmlEngine *engine, QQuickWindow *window)
+ : QV4::Object(QQmlEnginePrivate::getV4Engine(engine))
+ , window(window)
{
setVTable(staticVTable());
}
void QQuickRootItemMarker::markObjects(QV4::Managed *that, QV4::ExecutionEngine *e)
{
- QQuickItem *root = static_cast<QQuickRootItemMarker*>(that)->view->root;
+ QQuickItem *root = static_cast<QQuickRootItemMarker*>(that)->window->contentItem();
if (root) {
QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(root);
rootPrivate->markObjects(e);
@@ -91,7 +91,7 @@ void QQuickViewPrivate::init(QQmlEngine* e)
{
QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine.data());
QV4::Scope scope(v4);
- QV4::Scoped<QQuickRootItemMarker> v(scope, new (v4->memoryManager) QQuickRootItemMarker(this));
+ QV4::Scoped<QQuickRootItemMarker> v(scope, new (v4->memoryManager) QQuickRootItemMarker(engine.data(), q));
rootItemMarker = v;
}
diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h
index 74e40081e9..dfc8c21d0b 100644
--- a/src/quick/items/qquickview_p.h
+++ b/src/quick/items/qquickview_p.h
@@ -106,7 +106,7 @@ struct QQuickRootItemMarker : public QV4::Object
{
V4_OBJECT
- QQuickRootItemMarker(QQuickViewPrivate *view);
+ QQuickRootItemMarker(QQmlEngine *engine, QQuickWindow *window);
static void destroy(Managed *that)
{
@@ -115,7 +115,7 @@ struct QQuickRootItemMarker : public QV4::Object
static void markObjects(Managed *that, QV4::ExecutionEngine *e);
- QQuickViewPrivate *view;
+ QQuickWindow *window;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index b9713c7b6a..16b48efd86 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -286,7 +286,7 @@ void QQuickWindow::update()
Q_D(QQuickWindow);
if (d->windowManager)
d->windowManager->update(this);
- else
+ else if (d->renderControl)
d->renderControl->update();
}
@@ -450,6 +450,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
sg = renderControl->sceneGraphContext();
context = renderControl->renderContext(sg);
} else {
+ windowManager->addWindow(q);
sg = windowManager->sceneGraphContext();
context = windowManager->createRenderContext(sg);
}
@@ -975,8 +976,6 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
For easily displaying a scene from a QML file, see \l{QQuickView}.
-
-
\section1 Rendering
QQuickWindow uses a scene graph on top of OpenGL to
@@ -1031,6 +1030,9 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
scene graph and its OpenGL context being deleted. The
sceneGraphInvalidated() signal will be emitted when this happens.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
+
\sa {Scene Graph - OpenGL Under QML}
*/
@@ -1077,10 +1079,12 @@ QQuickWindow::~QQuickWindow()
Q_D(QQuickWindow);
d->animationController->deleteLater();
- if (d->renderControl)
+ if (d->renderControl) {
d->renderControl->windowDestroyed();
- else
+ } else if (d->windowManager) {
+ d->windowManager->removeWindow(this);
d->windowManager->windowDestroyed(this);
+ }
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete d->incubationController; d->incubationController = 0;
@@ -1090,8 +1094,6 @@ QQuickWindow::~QQuickWindow()
delete d->contentItem; d->contentItem = 0;
}
-
-
/*!
This function tries to release redundant resources currently held by the QML scene.
@@ -1289,9 +1291,11 @@ bool QQuickWindow::event(QEvent *e)
QTouchEvent *touch = static_cast<QTouchEvent*>(e);
d->translateTouchEvent(touch);
d->deliverTouchEvent(touch);
- // we consume all touch events ourselves to avoid duplicate
- // mouse delivery by QtGui mouse synthesis
- e->accept();
+ if (Q_LIKELY(qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
+ // we consume all touch events ourselves to avoid duplicate
+ // mouse delivery by QtGui mouse synthesis
+ e->accept();
+ }
return true;
}
break;
@@ -2389,9 +2393,9 @@ void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &fo
const bool isDebug = QLibraryInfo::isDebugBuild();
const QString eglLibName = QLatin1String(isDebug ? "libEGLd.dll" : "libEGL.dll");
const QString glesLibName = QLatin1String(isDebug ? "libGLESv2d.dll" : "libGLESv2.dll");
- //: %1 Context type (Open GL, EGL), ANGLE %2, %3 library names
+ //: %1 Context type (Open GL, EGL), %2 format, ANGLE %3, %4 library names
const char msg[] = QT_TRANSLATE_NOOP("QQuickWindow",
- "Failed to create %1 context for format %2."
+ "Failed to create %1 context for format %2.\n"
"This is most likely caused by not having the necessary graphics drivers installed.\n\n"
"Install a driver providing OpenGL 2.0 or higher, or, if this is not possible, "
"make sure the ANGLE Open GL ES 2.0 emulation libraries (%3, %4 and d3dcompiler_*.dll) "
@@ -2784,7 +2788,7 @@ void QQuickWindow::maybeUpdate()
Q_D(QQuickWindow);
if (d->renderControl)
d->renderControl->maybeUpdate();
- else
+ else if (d->windowManager)
d->windowManager->maybeUpdate(this);
}
@@ -2856,12 +2860,12 @@ QOpenGLContext *QQuickWindow::openglContext() const
/*!
\fn void QQuickWindow::sceneGraphError(SceneGraphError error, const QString &message)
- This signal is emitted when an error occurred during scene graph initialization.
+ This signal is emitted when an \a error occurred during scene graph initialization.
Applications should connect to this signal if they wish to handle errors,
like OpenGL context creation failures, in a custom way. When no slot is
connected to the signal, the behavior will be different: Quick will print
- the message, or show a message box, and terminate the application.
+ the \a message, or show a message box, and terminate the application.
This signal will be emitted from the gui thread.
@@ -2908,7 +2912,7 @@ QOpenGLContext *QQuickWindow::openglContext() const
*/
/*!
- \qmlsignal closing(CloseEvent close)
+ \qmlsignal QtQuick.Window::Window::closing(CloseEvent close)
\since 5.1
This signal is emitted when the user tries to close the window.
@@ -2917,6 +2921,8 @@ QOpenGLContext *QQuickWindow::openglContext() const
property is true by default so that the window is allowed to close; but you
can implement an onClosing() handler and set close.accepted = false if
you need to do something else before the window can be closed.
+
+ The corresponding handler is \c onClosing.
*/
@@ -3042,7 +3048,7 @@ QImage QQuickWindow::grabWindow()
QOpenGLContext context;
context.setFormat(requestedFormat());
- context.setShareContext(QSGContext::sharedOpenGLContext());
+ context.setShareContext(QOpenGLContextPrivate::globalShareContext());
context.create();
context.makeCurrent(this);
d->context->initialize(&context);
@@ -3051,7 +3057,7 @@ QImage QQuickWindow::grabWindow()
d->syncSceneGraph();
d->renderSceneGraph(size());
- QImage image = qt_gl_read_framebuffer(size(), false, false);
+ QImage image = qt_gl_read_framebuffer(size() * devicePixelRatio(), false, false);
d->cleanupNodesOnShutdown();
d->context->invalidate();
context.doneCurrent();
@@ -3059,7 +3065,11 @@ QImage QQuickWindow::grabWindow()
return image;
}
- return d->renderControl ? d->renderControl->grab() : d->windowManager->grab(this);
+ if (d->renderControl)
+ return d->renderControl->grab();
+ else if (d->windowManager)
+ return d->windowManager->grab(this);
+ return QImage();
}
/*!
@@ -3244,8 +3254,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
context in the same state as it was when the signal handler was entered. Failing to
do so can result in the scene not rendering properly.
- \sa scenegraphInvalidated()
-
+ \sa sceneGraphInvalidated()
\since 5.3
*/
@@ -3303,6 +3312,10 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
support QSGTexture::Repeat. Other values from CreateTextureOption are
ignored.
+ The returned texture will be using \c GL_TEXTURE_2D as texture target and
+ \c GL_RGBA as internal format. Reimplement QSGTexture to create textures
+ with different parameters.
+
\warning This function will return 0 if the scene graph has not yet been
initialized.
@@ -3314,7 +3327,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
This function can be called from any thread.
- \sa sceneGraphInitialized()
+ \sa sceneGraphInitialized(), QSGTexture
*/
QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const
@@ -3337,13 +3350,17 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
The caller of the function is responsible for deleting the returned texture.
+ The returned texture will be using \c GL_TEXTURE_2D as texture target and
+ assumes that internal format is \c {GL_RGBA}. Reimplement QSGTexture to
+ create textures with different parameters.
+
Use \a options to customize the texture attributes. The TextureUsesAtlas
option is ignored.
\warning This function will return 0 if the scenegraph has not yet been
initialized.
- \sa sceneGraphInitialized()
+ \sa sceneGraphInitialized(), QSGTexture
*/
QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
{
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index f6c32dcac3..d06fff8c3e 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -41,6 +41,7 @@
#include "qquickwindowmodule_p.h"
#include "qquickscreen_p.h"
+#include "qquickview_p.h"
#include <QtQuick/QQuickWindow>
#include <QtCore/QCoreApplication>
#include <QtQml/QQmlEngine>
@@ -73,7 +74,7 @@ public:
void setVisible(bool visible) {
if (!m_complete)
m_visible = visible;
- else
+ else if (!transientParent() || transientParent()->isVisible())
QQuickWindow::setVisible(visible);
}
@@ -91,16 +92,41 @@ Q_SIGNALS:
protected:
void classBegin() {
+ QQmlEngine* e = qmlEngine(this);
//Give QQuickView behavior when created from QML with QQmlApplicationEngine
if (QCoreApplication::instance()->property("__qml_using_qqmlapplicationengine") == QVariant(true)) {
- QQmlEngine* e = qmlEngine(this);
if (e && !e->incubationController())
e->setIncubationController(incubationController());
}
+ Q_ASSERT(e);
+ {
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(e);
+ QV4::Scope scope(v4);
+ QV4::ScopedObject v(scope, new (v4->memoryManager) QQuickRootItemMarker(e, this));
+ rootItemMarker = v;
+ }
}
void componentComplete() {
m_complete = true;
+ if (transientParent() && !transientParent()->isVisible()) {
+ connect(transientParent(), &QQuickWindow::visibleChanged, this,
+ &QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection);
+ } else {
+ setWindowVisibility();
+ }
+ }
+
+private Q_SLOTS:
+ void setWindowVisibility()
+ {
+ if (transientParent() && !transientParent()->isVisible())
+ return;
+
+ if (sender()) {
+ disconnect(transientParent(), &QWindow::visibleChanged, this,
+ &QQuickWindowQmlImpl::setWindowVisibility);
+ }
// We have deferred window creation until we have the full picture of what
// the user wanted in terms of window state, geometry, visibility, etc.
@@ -140,6 +166,7 @@ private:
bool m_complete;
bool m_visible;
Visibility m_visibility;
+ QV4::PersistentValue rootItemMarker;
};
void QQuickWindowModule::defineModule()
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index f525c83009..c9115f35fc 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -758,6 +758,8 @@ Renderer::Renderer(QSGRenderContext *ctx)
, m_tmpOpaqueElements(16)
, m_rebuild(FullRebuild)
, m_zRange(0)
+ , m_renderOrderRebuildLower(-1)
+ , m_renderOrderRebuildUpper(-1)
, m_currentMaterial(0)
, m_currentShader(0)
, m_currentClip(0)
@@ -1422,8 +1424,11 @@ void Renderer::invalidateBatchAndOverlappingRenderOrders(Batch *batch)
Q_ASSERT(batch);
Q_ASSERT(batch->first);
- int first = batch->first->order;
- int last = batch->lastOrderInBatch;
+ if (m_renderOrderRebuildLower < 0 || batch->first->order < m_renderOrderRebuildLower)
+ m_renderOrderRebuildLower = batch->first->order;
+ if (m_renderOrderRebuildUpper < 0 || batch->lastOrderInBatch > m_renderOrderRebuildUpper)
+ m_renderOrderRebuildUpper = batch->lastOrderInBatch;
+
batch->invalidate();
for (int i=0; i<m_alphaBatches.size(); ++i) {
@@ -1431,7 +1436,7 @@ void Renderer::invalidateBatchAndOverlappingRenderOrders(Batch *batch)
if (b->first) {
int bf = b->first->order;
int bl = b->lastOrderInBatch;
- if (bl > first && bf < last)
+ if (bl > m_renderOrderRebuildLower && bf < m_renderOrderRebuildUpper)
b->invalidate();
}
}
@@ -1444,7 +1449,7 @@ void Renderer::invalidateBatchAndOverlappingRenderOrders(Batch *batch)
*/
void Renderer::cleanupBatches(QDataBuffer<Batch *> *batches) {
if (batches->size()) {
- std::sort(&batches->first(), &batches->last() + 1, qsg_sort_batch_is_valid);
+ std::stable_sort(&batches->first(), &batches->last() + 1, qsg_sort_batch_is_valid);
int count = 0;
while (count < batches->size() && batches->at(count)->first)
++count;
@@ -2190,7 +2195,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES)
glLineWidth(g->lineWidth());
#if !defined(QT_OPENGL_ES_2)
- else if (g->drawingMode() == GL_POINTS)
+ else if (!QOpenGLContext::currentContext()->isOpenGLES() && g->drawingMode() == GL_POINTS)
glPointSize(g->lineWidth());
#endif
@@ -2430,6 +2435,8 @@ void Renderer::render()
renderBatches();
m_rebuild = 0;
+ m_renderOrderRebuildLower = -1;
+ m_renderOrderRebuildUpper = -1;
if (m_visualizeMode != VisualizeNothing)
visualize();
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 96b99a2918..89a33cb8c4 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -506,6 +506,8 @@ private:
uint m_rebuild;
qreal m_zRange;
+ int m_renderOrderRebuildLower;
+ int m_renderOrderRebuildUpper;
GLuint m_bufferStrategy;
int m_batchNodeThreshold;
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
index 40e0a014ab..43ff1b6240 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.cpp
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -286,6 +286,9 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
\sa QSGGeometryNode, {Scene Graph - Custom Geometry}
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
+
*/
/*!
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 4954fe20bb..22fe29959e 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -166,8 +166,8 @@ static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty();
};
\endcode
- \warning Instances of QSGMaterialShader belongs to the Scene Graph rendering
- thread, and cannot be used from the GUI thread.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
*/
@@ -550,6 +550,9 @@ static void qt_print_material_count()
\ingroup qtquick-scenegraph-materials
It serves no purpose outside the QSGMaterial::type() function.
+
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
*/
/*!
@@ -585,8 +588,8 @@ static void qt_print_material_count()
};
\endcode
- \warning Instances of QSGMaterial belongs to the Scene Graph rendering thread,
- and cannot be used from the GUI thread.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
*/
/*!
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index 5c196b252c..b0a4f20149 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -99,8 +99,8 @@ static void qt_print_node_count()
together. Nodes in a blocked subtree will not be preprocessed() and not
rendered.
- \warning Anything related to QSGNode should happen on the scene graph
- rendering thread.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
*/
/*!
@@ -683,6 +683,9 @@ void qsgnode_set_description(QSGNode *node, const QString &description)
The QSGBasicGeometryNode class should not be used by itself. It is only encapsulates
shared functionality between the QSGGeometryNode and QSGClipNode classes.
+
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
*/
@@ -824,6 +827,9 @@ void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
to avoid an extra operation in the fragment shader can have significant performance
impact on embedded graphics chips. The opaque material is optional.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
+
\sa QSGGeometry, QSGMaterial, QSGSimpleMaterial
*/
@@ -1036,6 +1042,9 @@ void QSGGeometryNode::setInheritedOpacity(qreal opacity)
Clip nodes must have a geometry before they can be added to the scene graph.
Clipping is usually implemented by using the stencil buffer.
+
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
*/
@@ -1127,6 +1136,10 @@ void QSGClipNode::setClipRect(const QRectF &rect)
transformations. However, because the renderer optimizes for 2D use-cases rather
than 3D use-cases, rendering a scene with full 3D transformations needs to
be done with some care.
+
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
+
*/
@@ -1264,6 +1277,8 @@ void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyState state)
be marked as blocked, causing isSubtreeBlocked() to return true. This
is done for performance reasons.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
*/
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index 55c9444365..eddd38a68f 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -134,6 +134,8 @@ public:
virtual void setCustomRenderMode(const QByteArray &) { };
+ void clearChangedFlag() { m_changed_emitted = false; }
+
Q_SIGNALS:
void sceneGraphChanged(); // Add, remove, ChangeFlags changes...
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 9f7818a442..64506d1c26 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -99,13 +99,8 @@ public:
QSGContextPrivate()
: antialiasingMethod(QSGContext::UndecidedAntialiasing)
, distanceFieldDisabled(qmlDisableDistanceField())
- , distanceFieldAntialiasing(
-#if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2_ANGLE)
- QSGGlyphNode::HighQualitySubPixelAntialiasing
-#else
- QSGGlyphNode::GrayAntialiasing
-#endif
- )
+ , distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing)
+ , distanceFieldAntialiasingDecided(false)
{
}
@@ -117,12 +112,9 @@ public:
QSGContext::AntialiasingMethod antialiasingMethod;
bool distanceFieldDisabled;
QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing;
-
- static QOpenGLContext *sharedOpenGLContext;
+ bool distanceFieldAntialiasingDecided;
};
-QOpenGLContext *QSGContextPrivate::sharedOpenGLContext = 0;
-
class QSGTextureCleanupEvent : public QEvent
{
public:
@@ -161,6 +153,8 @@ QSGContext::QSGContext(QObject *parent) :
{
Q_D(QSGContext);
QByteArray mode = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING");
+ if (!mode.isEmpty())
+ d->distanceFieldAntialiasingDecided = true;
if (mode == "subpixel")
d->distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing;
else if (mode == "subpixel-lowq")
@@ -179,20 +173,6 @@ QSGRenderContext *QSGContext::createRenderContext()
return new QSGRenderContext(this);
}
-/*!
- * This function is used by the Qt WebEngine to set up context sharing
- * across multiple windows. Do not use it for any other purpose.
- */
-void QSGContext::setSharedOpenGLContext(QOpenGLContext *context)
-{
- QSGContextPrivate::sharedOpenGLContext = context;
-}
-
-QOpenGLContext *QSGContext::sharedOpenGLContext()
-{
- return QSGContextPrivate::sharedOpenGLContext;
-}
-
void QSGContext::renderContextInitialized(QSGRenderContext *renderContext)
{
Q_D(QSGContext);
@@ -212,6 +192,17 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext)
}
}
+ // With OpenGL ES, except for Angle on Windows, use GrayAntialiasing, unless
+ // some value had been requested explicitly. This could not be decided
+ // before without a context. Now the context is ready.
+ if (!d->distanceFieldAntialiasingDecided) {
+ d->distanceFieldAntialiasingDecided = true;
+#ifndef Q_OS_WIN
+ if (renderContext->openglContext()->isOpenGLES())
+ d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
+#endif
+ }
+
static bool dumped = false;
if (!dumped && qEnvironmentVariableIsSet("QSG_INFO")) {
dumped = true;
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 2ab78ce289..ac372b9718 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -168,9 +168,6 @@ public:
virtual QSize minimumFBOSize() const;
virtual QSurfaceFormat defaultSurfaceFormat() const;
- static void setSharedOpenGLContext(QOpenGLContext *context);
- static QOpenGLContext *sharedOpenGLContext();
-
void setDistanceFieldEnabled(bool enabled);
bool isDistanceFieldEnabled() const;
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index a625eebd5d..48b405467b 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -231,7 +231,8 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if !defined(QT_OPENGL_ES_2)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ if (!QOpenGLContext::currentContext()->isOpenGLES())
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
const GLint internalFormat = isCoreProfile() ? GL_R8 : GL_ALPHA;
const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
#else
@@ -373,7 +374,8 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if !defined(QT_OPENGL_ES_2)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ if (!ctx->isOpenGLES())
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultimagenode.cpp
index 926c0c1f4a..d925b1c7c4 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultimagenode.cpp
@@ -307,13 +307,11 @@ void QSGDefaultImageNode::preprocess()
markDirty(DirtyMaterial);
}
-#ifdef QT_OPENGL_ES_2
inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
return x == (x & -x);
}
-#endif
namespace {
struct X { float x, tx; };
@@ -360,15 +358,18 @@ void QSGDefaultImageNode::updateGeometry()
bool hasTiles = hTiles != 1 || vTiles != 1;
bool fullTexture = innerSourceRect == QRectF(0, 0, 1, 1);
-#ifdef QT_OPENGL_ES_2
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- bool npotSupported = ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
- QSize size = t->textureSize();
- bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
- bool wrapSupported = npotSupported || !isNpot;
-#else
bool wrapSupported = true;
+
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+#ifndef QT_OPENGL_ES_2
+ if (ctx->isOpenGLES())
#endif
+ {
+ bool npotSupported = ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
+ QSize size = t->textureSize();
+ const bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
+ wrapSupported = npotSupported || !isNpot;
+ }
// An image can be rendered as a single quad if:
// - There are no margins, and either:
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
index 810a503cee..467f454d0f 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
@@ -289,10 +289,22 @@ void QSGDefaultRectangleNode::update()
if (m_dirty_geometry) {
updateGeometry();
m_dirty_geometry = false;
+
+ QSGNode::DirtyState state = QSGNode::DirtyGeometry;
+ // smoothed material is always blended, so no change in material state
+ if (material() == &m_material) {
+ bool wasBlending = (m_material.flags() & QSGMaterial::Blending);
+ bool isBlending = (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
+ || (m_color.alpha() < 255 && m_color.alpha() != 0)
+ || (m_pen_width > 0 && m_border_color.alpha() < 255);
+ if (wasBlending != isBlending) {
+ m_material.setFlag(QSGMaterial::Blending, isBlending);
+ state |= QSGNode::DirtyMaterial;
+ }
+ }
+
+ markDirty(state);
}
- m_material.setFlag(QSGMaterial::Blending, (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
- || (m_color.alpha() < 255 && m_color.alpha() != 0)
- || (m_pen_width > 0 && m_border_color.alpha() < 255));
}
void QSGDefaultRectangleNode::updateGeometry()
@@ -770,8 +782,6 @@ void QSGDefaultRectangleNode::updateGeometry()
Q_ASSERT(outerAATail == indexCount);
}
}
-
- markDirty(DirtyGeometry);
}
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 00e67aa944..38de4a5c39 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -45,7 +45,6 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QTime>
-#include <QtCore/QScopedPointer>
#include <QtCore/QLibraryInfo>
#include <QtCore/private/qabstractanimation_p.h>
@@ -82,12 +81,27 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_
DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP);
DEFINE_BOOL_CONFIG_OPTION(qmlForceThreadedRenderer, QML_FORCE_THREADED_RENDERER); // Might trigger graphics driver threading bugs, use at own risk
-Q_GLOBAL_STATIC(QScopedPointer<QSGRenderLoop>, s_renderLoopInstance);
+QSGRenderLoop *QSGRenderLoop::s_instance = 0;
QSGRenderLoop::~QSGRenderLoop()
{
}
+void QSGRenderLoop::cleanup()
+{
+ if (!s_instance)
+ return;
+ foreach (QQuickWindow *w, s_instance->windows()) {
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(w);
+ if (wd->windowManager == s_instance) {
+ s_instance->windowDestroyed(w);
+ wd->windowManager = 0;
+ }
+ }
+ delete s_instance;
+ s_instance = 0;
+}
+
class QSGGuiThreadRenderLoop : public QSGRenderLoop
{
Q_OBJECT
@@ -148,8 +162,8 @@ bool QSGRenderLoop::useConsistentTiming()
QSGRenderLoop *QSGRenderLoop::instance()
{
- if (s_renderLoopInstance->isNull()) {
- s_renderLoopInstance->reset(QSGContext::createWindowManager());
+ if (!s_instance) {
+ s_instance = QSGContext::createWindowManager();
bool info = qEnvironmentVariableIsSet("QSG_INFO");
@@ -159,7 +173,7 @@ QSGRenderLoop *QSGRenderLoop::instance()
qDebug() << "QSG: using fixed animation steps";
}
- if (s_renderLoopInstance->isNull()) {
+ if (!s_instance) {
enum RenderLoopType {
BasicRenderLoop,
@@ -191,26 +205,28 @@ QSGRenderLoop *QSGRenderLoop::instance()
switch (loopType) {
case ThreadedRenderLoop:
if (info) qDebug() << "QSG: threaded render loop";
- s_renderLoopInstance->reset(new QSGThreadedRenderLoop());
+ s_instance = new QSGThreadedRenderLoop();
break;
case WindowsRenderLoop:
if (info) qDebug() << "QSG: windows render loop";
- s_renderLoopInstance->reset(new QSGWindowsRenderLoop());
+ s_instance = new QSGWindowsRenderLoop();
break;
default:
if (info) qDebug() << "QSG: basic render loop";
- s_renderLoopInstance->reset(new QSGGuiThreadRenderLoop());
+ s_instance = new QSGGuiThreadRenderLoop();
break;
}
}
+
+ qAddPostRoutine(QSGRenderLoop::cleanup);
}
- return s_renderLoopInstance->data();
+ return s_instance;
}
void QSGRenderLoop::setInstance(QSGRenderLoop *instance)
{
- Q_ASSERT(s_renderLoopInstance->isNull());
- s_renderLoopInstance->reset(instance);
+ Q_ASSERT(!s_instance);
+ s_instance = instance;
}
void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window,
@@ -295,6 +311,8 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete gl;
gl = 0;
+ } else if (window == gl->surface()) {
+ gl->doneCurrent();
}
}
@@ -311,10 +329,10 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (!gl) {
gl = new QOpenGLContext();
gl->setFormat(window->requestedFormat());
- if (QSGContext::sharedOpenGLContext())
- gl->setShareContext(QSGContext::sharedOpenGLContext());
+ if (QOpenGLContextPrivate::globalShareContext())
+ gl->setShareContext(QOpenGLContextPrivate::globalShareContext());
if (!gl->create()) {
- const bool isEs = gl->isES();
+ const bool isEs = gl->isOpenGLES();
delete gl;
gl = 0;
handleContextCreationFailure(window, isEs);
@@ -361,7 +379,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
renderTime = renderTimer.nsecsElapsed() - syncTime;
if (data.grabOnly) {
- grabContent = qt_gl_read_framebuffer(window->size(), false, false);
+ grabContent = qt_gl_read_framebuffer(window->size() * window->devicePixelRatio(), false, false);
data.grabOnly = false;
}
diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h
index 2418af4157..8d5312b188 100644
--- a/src/quick/scenegraph/qsgrenderloop_p.h
+++ b/src/quick/scenegraph/qsgrenderloop_p.h
@@ -44,6 +44,7 @@
#include <QtGui/QImage>
#include <private/qtquickglobal_p.h>
+#include <QtCore/QSet>
QT_BEGIN_NAMESPACE
@@ -78,6 +79,10 @@ public:
virtual void releaseResources(QQuickWindow *window) = 0;
+ void addWindow(QQuickWindow *win) { m_windows.insert(win); }
+ void removeWindow(QQuickWindow *win) { m_windows.remove(win); }
+ QSet<QQuickWindow *> windows() const { return m_windows; }
+
// ### make this less of a singleton
static QSGRenderLoop *instance();
static void setInstance(QSGRenderLoop *instance);
@@ -86,11 +91,18 @@ public:
virtual bool interleaveIncubation() const { return false; }
+ static void cleanup();
+
Q_SIGNALS:
void timeToIncubate();
protected:
void handleContextCreationFailure(QQuickWindow *window, bool isEs);
+
+private:
+ static QSGRenderLoop *s_instance;
+
+ QSet<QQuickWindow *> m_windows;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index a5b46b7c75..1ba54ea19e 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -62,6 +62,7 @@
#include <private/qquickanimatorcontroller_p.h>
#include <private/qquickprofiler_p.h>
+#include <private/qqmldebugservice_p.h>
/*
Overall design:
@@ -428,7 +429,7 @@ bool QSGRenderThread::event(QEvent *e)
QQuickWindowPrivate::get(window)->renderSceneGraph(windowSize);
QSG_RT_DEBUG(" - grabbing result...");
- *ce->image = qt_gl_read_framebuffer(windowSize, false, false);
+ *ce->image = qt_gl_read_framebuffer(windowSize * window->devicePixelRatio(), false, false);
}
QSG_RT_DEBUG(" - waking gui to handle grab result");
waitCondition.wakeOne();
@@ -513,6 +514,10 @@ void QSGRenderThread::sync(bool inExpose)
if (current) {
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool hadRenderer = d->renderer != 0;
+ // If the scene graph was touched since the last sync() make sure it sends the
+ // changed signal.
+ if (d->renderer)
+ d->renderer->clearChangedFlag();
d->syncSceneGraph();
if (!hadRenderer && d->renderer) {
QSG_RT_DEBUG(" - renderer was created, hooking up changed signal");
@@ -663,6 +668,8 @@ void QSGRenderThread::run()
animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0);
animatorDriver->install();
QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming());
+ if (QQmlDebugService::isDebuggingEnabled())
+ QQuickProfiler::registerAnimationCallback();
while (active) {
@@ -791,8 +798,6 @@ void QSGThreadedRenderLoop::startOrStopAnimationTimer()
}
}
-
-
/*
Removes this window from the list of tracked windowes in this
window manager. hide() will trigger obscure, which in turn will
@@ -873,6 +878,7 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
QSG_GUI_DEBUG(window, " - adding window to list");
Window win;
win.window = window;
+ win.actualWindowFormat = window->format();
win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
win.timerId = 0;
win.updateDuringSync = false;
@@ -899,11 +905,11 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
if (!w->thread->gl) {
w->thread->gl = new QOpenGLContext();
- if (QSGContext::sharedOpenGLContext())
- w->thread->gl->setShareContext(QSGContext::sharedOpenGLContext());
+ if (QOpenGLContextPrivate::globalShareContext())
+ w->thread->gl->setShareContext(QOpenGLContextPrivate::globalShareContext());
w->thread->gl->setFormat(w->window->requestedFormat());
if (!w->thread->gl->create()) {
- const bool isEs = w->thread->gl->isES();
+ const bool isEs = w->thread->gl->isOpenGLES();
delete w->thread->gl;
w->thread->gl = 0;
handleContextCreationFailure(w->window, isEs);
@@ -1045,7 +1051,7 @@ void QSGThreadedRenderLoop::releaseResources(Window *w, bool inDestructor)
if (!window->handle()) {
QSG_GUI_DEBUG(window, " - using fallback surface");
fallback = new QOffscreenSurface();
- fallback->setFormat(window->requestedFormat());
+ fallback->setFormat(w->actualWindowFormat);
fallback->create();
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index 970bd63040..b86b3c73a4 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -87,6 +87,7 @@ private:
struct Window {
QQuickWindow *window;
QSGRenderThread *thread;
+ QSurfaceFormat actualWindowFormat;
int timerId;
uint updateDuringSync : 1;
};
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 32f52417bb..dc12d00490 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -179,11 +179,11 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
RLDEBUG(" - creating GL context");
m_gl = new QOpenGLContext();
m_gl->setFormat(window->requestedFormat());
- if (QSGContext::sharedOpenGLContext())
- m_gl->setShareContext(QSGContext::sharedOpenGLContext());
+ if (QOpenGLContextPrivate::globalShareContext())
+ m_gl->setShareContext(QOpenGLContextPrivate::globalShareContext());
bool created = m_gl->create();
if (!created) {
- const bool isEs = m_gl->isES();
+ const bool isEs = m_gl->isOpenGLES();
delete m_gl;
m_gl = 0;
handleContextCreationFailure(window, isEs);
@@ -341,7 +341,7 @@ QImage QSGWindowsRenderLoop::grab(QQuickWindow *window)
d->syncSceneGraph();
d->renderSceneGraph(window->size());
- QImage image = qt_gl_read_framebuffer(window->size(), false, false);
+ QImage image = qt_gl_read_framebuffer(window->size() * window->devicePixelRatio(), false, false);
return image;
}
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index 99d1d60258..1ff7d11162 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -143,7 +143,13 @@ Atlas::Atlas(const QSize &size)
, m_allocated(false)
{
-#ifdef QT_OPENGL_ES
+ m_internalFormat = GL_RGBA;
+ m_externalFormat = GL_BGRA;
+
+#ifndef QT_OPENGL_ES
+ if (QOpenGLContext::currentContext()->isOpenGLES()) {
+#endif
+
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK)
QString *deviceName =
static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName"));
@@ -153,7 +159,7 @@ Atlas::Atlas(const QSize &size)
|| deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0);
#else
static bool wrongfullyReportsBgra8888Support = false;
-#endif
+#endif // ANDROID
const char *ext = (const char *) glGetString(GL_EXTENSIONS);
if (!wrongfullyReportsBgra8888Support
@@ -165,13 +171,13 @@ Atlas::Atlas(const QSize &size)
} else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) {
m_internalFormat = GL_RGBA;
m_externalFormat = GL_BGRA;
-#endif
+#endif // IOS
} else {
m_internalFormat = m_externalFormat = GL_RGBA;
}
-#else
- m_internalFormat = GL_RGBA;
- m_externalFormat = GL_BGRA;
+
+#ifndef QT_OPENGL_ES
+ }
#endif
m_use_bgra_fallback = qEnvironmentVariableIsSet("QSG_ATLAS_USE_BGRA_FALLBACK");
@@ -326,7 +332,8 @@ void Atlas::bind(QSGTexture::Filtering filtering)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if !defined(QT_OPENGL_ES_2)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ if (!QOpenGLContext::currentContext()->isOpenGLES())
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, 0);
diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
index 59bde0d602..f5a75fd627 100644
--- a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
+++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
@@ -75,8 +75,6 @@ void QSGDepthStencilBuffer::detach()
GL_RENDERBUFFER, 0);
}
-// ###TODO Remove once using Khronos OpenGL headers
-#if defined(QT_OPENGL_ES_2)
#ifndef GL_DEPTH24_STENCIL8_OES
#define GL_DEPTH24_STENCIL8_OES 0x88F0
#endif
@@ -84,7 +82,6 @@ void QSGDepthStencilBuffer::detach()
#ifndef GL_DEPTH_COMPONENT24_OES
#define GL_DEPTH_COMPONENT24_OES 0x81A6
#endif
-#endif
QSGDefaultDepthStencilBuffer::QSGDefaultDepthStencilBuffer(QOpenGLContext *context, const Format &format)
: QSGDepthStencilBuffer(context, format)
@@ -117,12 +114,10 @@ QSGDefaultDepthStencilBuffer::QSGDefaultDepthStencilBuffer(QOpenGLContext *conte
if (!m_depthBuffer && (format.attachments & DepthAttachment)) {
m_functions.glGenRenderbuffers(1, &m_depthBuffer);
m_functions.glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
-#ifdef QT_OPENGL_ES
- const GLenum internalFormat = m_functions.hasOpenGLExtension(QOpenGLExtensions::Depth24)
+ GLenum internalFormat = GL_DEPTH_COMPONENT;
+ if (context->isOpenGLES())
+ internalFormat = m_functions.hasOpenGLExtension(QOpenGLExtensions::Depth24)
? GL_DEPTH_COMPONENT24_OES : GL_DEPTH_COMPONENT16;
-#else
- const GLenum internalFormat = GL_DEPTH_COMPONENT;
-#endif
if (format.samples && m_functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples,
internalFormat, width, height);
@@ -136,7 +131,7 @@ QSGDefaultDepthStencilBuffer::QSGDefaultDepthStencilBuffer(QOpenGLContext *conte
#ifdef QT_OPENGL_ES
const GLenum internalFormat = GL_STENCIL_INDEX8;
#else
- const GLenum internalFormat = GL_STENCIL_INDEX;
+ const GLenum internalFormat = context->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX;
#endif
if (format.samples && m_functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples,
diff --git a/src/quick/scenegraph/util/qsgsimplematerial.cpp b/src/quick/scenegraph/util/qsgsimplematerial.cpp
index a247b37d77..ada4dd6c4f 100644
--- a/src/quick/scenegraph/util/qsgsimplematerial.cpp
+++ b/src/quick/scenegraph/util/qsgsimplematerial.cpp
@@ -142,6 +142,9 @@
the unique QSGSimpleMaterialShader implementation must be
instantiated with a unique C++ type.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
+
\sa {Scene Graph - Simple Material}
*/
@@ -244,6 +247,9 @@
\inmodule QtQuick
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
+
\sa QSGSimpleMaterialShader
*/
diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
index 47cb82d01b..bbf115fa2a 100644
--- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
+++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
@@ -107,6 +107,8 @@ QSGSimpleTextureNode::QSGSimpleTextureNode()
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("simpletexture"));
#endif
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index 3bbcb0c112..cd0b64fe49 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -39,8 +39,6 @@
**
****************************************************************************/
-#define GL_GLEXT_PROTOTYPES
-
#include "qsgtexture_p.h"
#include <qopenglfunctions.h>
#include <QtQuick/private/qsgcontext_p.h>
@@ -83,7 +81,7 @@ static QElapsedTimer qsg_renderer_timer;
QT_BEGIN_NAMESPACE
-#if !defined(QT_NO_DEBUG) && defined(QT_OPENGL_ES_2)
+#ifndef QT_NO_DEBUG
inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
@@ -237,6 +235,9 @@ static void qt_debug_remove_texture(QSGTexture* texture)
the function removedFromAtlas() can be used to extract a
non-atlassed copy.
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
+
\sa {Scene Graph - Rendering FBOs}, {Scene Graph - Rendering FBOs in a thread}
*/
@@ -514,7 +515,7 @@ void QSGTexture::updateBindOptions(bool force)
}
if (force || d->wrapChanged) {
-#if !defined(QT_NO_DEBUG) && defined(QT_OPENGL_ES_2)
+#ifndef QT_NO_DEBUG
if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat) {
bool npotSupported = QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::NPOTTextures);
QSize size = textureSize();
@@ -566,6 +567,7 @@ void QSGPlainTexture::setImage(const QImage &image)
m_has_alpha = image.hasAlphaChannel();
m_dirty_texture = true;
m_dirty_bind_options = true;
+ m_mipmaps_generated = false;
}
int QSGPlainTexture::textureId() const
@@ -686,7 +688,10 @@ void QSGPlainTexture::bind()
externalFormat = GL_BGRA;
#ifdef QT_OPENGL_ES
internalFormat = GL_BGRA;
-#endif
+#else
+ if (context->isOpenGLES())
+ internalFormat = GL_BGRA;
+#endif // QT_OPENGL_ES
} else if (!wrongfullyReportsBgra8888Support
&& (context->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888"))
|| context->hasExtension(QByteArrayLiteral("GL_IMG_texture_format_BGRA8888")))) {
@@ -765,6 +770,9 @@ void QSGPlainTexture::bind()
To update the content of the texture, call updateTexture() explicitly. Simply calling bind()
will not update the texture.
+
+ \note All classes with QSG prefix should be used solely on the scene graph's
+ rendering thread. See \l {Scene Graph and Rendering} for more information.
*/
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index df55404504..afa535d322 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -46,13 +46,11 @@
QT_BEGIN_NAMESPACE
-#ifdef QT_OPENGL_ES_2
inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
return x == (x & -x);
}
-#endif
QSGMaterialType QSGOpaqueTextureMaterialShader::type;
@@ -83,19 +81,20 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
QSGTexture *t = tx->texture();
t->setFiltering(tx->filtering());
-#ifdef QT_OPENGL_ES_2
- bool npotSupported = QOpenGLFunctions(const_cast<QOpenGLContext *>(state.context())).hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
- QSize size = t->textureSize();
- bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
- if (!npotSupported && isNpot) {
- t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
- t->setVerticalWrapMode(QSGTexture::ClampToEdge);
- } else
-#endif
- {
- t->setHorizontalWrapMode(tx->horizontalWrapMode());
- t->setVerticalWrapMode(tx->verticalWrapMode());
+
+ t->setHorizontalWrapMode(tx->horizontalWrapMode());
+ t->setVerticalWrapMode(tx->verticalWrapMode());
+ bool npotSupported = const_cast<QOpenGLContext *>(state.context())
+ ->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
+ if (!npotSupported) {
+ QSize size = t->textureSize();
+ const bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
+ if (isNpot) {
+ t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ }
}
+
t->setMipmapFiltering(tx->mipmapFiltering());
if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId())
@@ -153,7 +152,7 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial()
: m_texture(0)
, m_filtering(QSGTexture::Nearest)
- , m_mipmap_filtering(QSGTexture::Nearest)
+ , m_mipmap_filtering(QSGTexture::None)
, m_horizontal_wrap(QSGTexture::ClampToEdge)
, m_vertical_wrap(QSGTexture::ClampToEdge)
{
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 36316e27c0..10d2176d0a 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -200,19 +200,21 @@ QQmlProperty QQuickAbstractAnimationPrivate::createProperty(QObject *obj, const
}
/*!
- \qmlsignal QtQuick::Animation::onStarted()
+ \qmlsignal QtQuick::Animation::started()
- This signal handler is called when the animation begins.
+ This signal is emitted when the animation begins.
It is only triggered for top-level, standalone animations. It will not be
triggered for animations in a Behavior or Transition, or animations
that are part of an animation group.
+
+ The corresponding handler is \c onStarted.
*/
/*!
- \qmlsignal QtQuick::Animation::onStopped()
+ \qmlsignal QtQuick::Animation::stopped()
- This signal handler is called when the animation ends.
+ This signal is emitted when the animation ends.
The animation may have been stopped manually, or may have run to completion.
@@ -220,8 +222,10 @@ QQmlProperty QQuickAbstractAnimationPrivate::createProperty(QObject *obj, const
triggered for animations in a Behavior or Transition, or animations
that are part of an animation group.
- If \l alwaysRunToEnd is true, onStopped will not be called until the animation
+ If \l alwaysRunToEnd is true, this signal will not be emitted until the animation
has completed its current iteration.
+
+ The corresponding handler is \c onStopped.
*/
void QQuickAbstractAnimation::setRunning(bool r)
@@ -869,6 +873,19 @@ void QActionAnimation::updateState(State newState, State oldState)
}
}
+void QActionAnimation::debugAnimation(QDebug d) const
+{
+ d << "ActionAnimation(" << hex << (void *) this << dec << ")";
+
+ if (animAction) {
+ int indentLevel = 1;
+ const QAbstractAnimationJob *job = this;
+ while ((job = job->group()))
+ ++indentLevel;
+ animAction->debugAction(d, indentLevel);
+ }
+}
+
/*!
\qmltype ScriptAction
\instantiates QQuickScriptAction
@@ -953,6 +970,22 @@ QAbstractAnimationAction* QQuickScriptActionPrivate::createAction()
return new Proxy(this);
}
+void QQuickScriptActionPrivate::debugAction(QDebug d, int indentLevel) const
+{
+ QQmlScriptString scriptStr = hasRunScriptScript ? runScriptScript : script;
+
+ if (!scriptStr.isEmpty()) {
+ QQmlExpression expr(scriptStr);
+
+ QByteArray ind(indentLevel, ' ');
+ QString exprStr = expr.expression();
+ int endOfFirstLine = exprStr.indexOf('\n');
+ d << "\n" << ind.constData() << exprStr.left(endOfFirstLine);
+ if (endOfFirstLine != -1 && endOfFirstLine < exprStr.length())
+ d << "...";
+ }
+}
+
void QQuickScriptActionPrivate::execute()
{
Q_Q(QQuickScriptAction);
@@ -1166,6 +1199,14 @@ QAbstractAnimationJob* QQuickPropertyAction::transition(QQuickStateActions &acti
QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
}
}
+ virtual void debugAction(QDebug d, int indentLevel) const {
+ QByteArray ind(indentLevel, ' ');
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ const QQuickStateAction &action = actions.at(ii);
+ d << "\n" << ind.constData() << "target:" << action.property.object() << "property:" << action.property.name()
+ << "value:" << action.toValue;
+ }
+ }
};
QStringList props = d->properties.isEmpty() ? QStringList() : d->properties.split(QLatin1Char(','));
@@ -1925,6 +1966,19 @@ void QQuickBulkValueAnimator::topLevelAnimationLoopChanged()
QAbstractAnimationJob::topLevelAnimationLoopChanged();
}
+void QQuickBulkValueAnimator::debugAnimation(QDebug d) const
+{
+ d << "BulkValueAnimation(" << hex << (void *) this << dec << ")" << "duration:" << duration();
+
+ if (animValue) {
+ int indentLevel = 1;
+ const QAbstractAnimationJob *job = this;
+ while ((job = job->group()))
+ ++indentLevel;
+ animValue->debugUpdater(d, indentLevel);
+ }
+}
+
/*!
\qmltype PropertyAnimation
\instantiates QQuickPropertyAnimation
@@ -2498,6 +2552,16 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v)
fromSourced = true;
}
+void QQuickAnimationPropertyUpdater::debugUpdater(QDebug d, int indentLevel) const
+{
+ QByteArray ind(indentLevel, ' ');
+ for (int i = 0; i < actions.count(); ++i) {
+ const QQuickStateAction &action = actions.at(i);
+ d << "\n" << ind.constData() << "target:" << action.property.object() << "property:" << action.property.name()
+ << "from:" << action.fromValue << "to:" << action.toValue;
+ }
+}
+
QQuickStateActions QQuickPropertyAnimation::createTransitionActions(QQuickStateActions &actions,
QQmlProperties &modified,
QObject *defaultTarget)
diff --git a/src/quick/util/qquickanimation_p_p.h b/src/quick/util/qquickanimation_p_p.h
index 127f447e5d..f2b5f6388f 100644
--- a/src/quick/util/qquickanimation_p_p.h
+++ b/src/quick/util/qquickanimation_p_p.h
@@ -79,18 +79,19 @@ class QAbstractAnimationAction
public:
virtual ~QAbstractAnimationAction() {}
virtual void doAction() = 0;
+ virtual void debugAction(QDebug, int) const {}
};
//templated animation action
//allows us to specify an action that calls a function of a class.
//(so that class doesn't have to inherit QQuickAbstractAnimationAction)
-template<class T, void (T::*method)()>
+template<class T, void (T::*method)(), void (T::*debugMethod)(QDebug, int) const>
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); }
private:
T *m_instance;
};
@@ -111,6 +112,7 @@ public:
protected:
virtual void updateCurrentTime(int);
virtual void updateState(State newState, State oldState);
+ void debugAnimation(QDebug d) const;
private:
QAbstractAnimationAction *animAction;
@@ -121,6 +123,7 @@ class QQuickBulkValueUpdater
public:
virtual ~QQuickBulkValueUpdater() {}
virtual void setValue(qreal value) = 0;
+ virtual void debugUpdater(QDebug, int) const {}
};
//animates QQuickBulkValueUpdater (assumes start and end values will be reals or compatible)
@@ -145,6 +148,7 @@ public:
protected:
void updateCurrentTime(int currentTime);
void topLevelAnimationLoopChanged();
+ void debugAnimation(QDebug d) const;
private:
QQuickBulkValueUpdater *animValue;
@@ -224,8 +228,10 @@ public:
void execute();
QAbstractAnimationAction* createAction();
+ void debugAction(QDebug d, int indentLevel) const;
typedef QAnimationActionProxy<QQuickScriptActionPrivate,
- &QQuickScriptActionPrivate::execute> Proxy;
+ &QQuickScriptActionPrivate::execute,
+ &QQuickScriptActionPrivate::debugAction> Proxy;
};
class QQuickPropertyActionPrivate : public QQuickAbstractAnimationPrivate
@@ -307,6 +313,8 @@ public:
void setValue(qreal v);
+ void debugUpdater(QDebug d, int indentLevel) const;
+
QQuickStateActions actions;
int interpolatorType; //for Number/ColorAnimation
QVariantAnimation::Interpolator interpolator;
diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp
index 5ae74c2fec..4428452aa0 100644
--- a/src/quick/util/qquickglobal.cpp
+++ b/src/quick/util/qquickglobal.cpp
@@ -61,23 +61,9 @@ QT_BEGIN_NAMESPACE
class QQuickColorProvider : public QQmlColorProvider
{
public:
- static inline QColor QColorFromString(const QString &s)
- {
- // Should we also handle #rrggbb here?
- if (s.length() == 9 && s.startsWith(QLatin1Char('#'))) {
- uchar a = fromHex(s, 1);
- uchar r = fromHex(s, 3);
- uchar g = fromHex(s, 5);
- uchar b = fromHex(s, 7);
- return QColor(r, g, b, a);
- }
-
- return QColor(s);
- }
-
QVariant colorFromString(const QString &s, bool *ok)
{
- QColor c(QColorFromString(s));
+ QColor c(s);
if (c.isValid()) {
if (ok) *ok = true;
return QVariant(c);
@@ -89,7 +75,7 @@ public:
unsigned rgbaFromString(const QString &s, bool *ok)
{
- QColor c(QColorFromString(s));
+ QColor c(s);
if (c.isValid()) {
if (ok) *ok = true;
return c.rgba();
@@ -155,34 +141,6 @@ public:
return QVariant::fromValue(QColor::fromRgbF(r, g, b, a + inv_a * baseColor.alphaF()));
}
-
-private:
- static uchar fromHex(const uchar c, const uchar c2)
- {
- uchar rv = 0;
- if (c >= '0' && c <= '9')
- rv += (c - '0') * 16;
- else if (c >= 'A' && c <= 'F')
- rv += (c - 'A' + 10) * 16;
- else if (c >= 'a' && c <= 'f')
- rv += (c - 'a' + 10) * 16;
-
- if (c2 >= '0' && c2 <= '9')
- rv += (c2 - '0');
- else if (c2 >= 'A' && c2 <= 'F')
- rv += (c2 - 'A' + 10);
- else if (c2 >= 'a' && c2 <= 'f')
- rv += (c2 - 'a' + 10);
-
- return rv;
- }
-
- static inline uchar fromHex(const QString &s, int idx)
- {
- uchar c = s.at(idx).toLatin1();
- uchar c2 = s.at(idx + 1).toLatin1();
- return fromHex(c, c2);
- }
};
@@ -639,7 +597,7 @@ public:
switch (type) {
case QMetaType::QColor:
- return createFromStringTyped<QColor>(data, dataSize, QQuickColorProvider::QColorFromString(s));
+ return createFromStringTyped<QColor>(data, dataSize, QColor(s));
case QMetaType::QVector2D:
return createFromStringTyped<QVector2D>(data, dataSize, vector2DFromString(s, &ok));
case QMetaType::QVector3D:
@@ -677,7 +635,7 @@ public:
bool variantFromString(const QString &s, QVariant *v)
{
- QColor c(QQuickColorProvider::QColorFromString(s));
+ QColor c(s);
if (c.isValid()) {
*v = QVariant::fromValue(c);
return true;
@@ -725,7 +683,7 @@ public:
switch (type) {
case QMetaType::QColor:
{
- QColor c(QQuickColorProvider::QColorFromString(s));
+ QColor c(s);
*v = QVariant::fromValue(c);
return true;
}
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index 25e40d8eb6..7e8b71da63 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -320,8 +320,6 @@ void QQuickPath::endpoint(QList<AttributePoint> &attributePoints, const QString
}
}
-static QString percentString(QLatin1String("_qfx_percent"));
-
void QQuickPath::processPath()
{
Q_D(QQuickPath);
@@ -358,6 +356,8 @@ QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &en
qreal startY = d->startY.isValid() ? d->startY.value : startPoint.y();
path.moveTo(startX, startY);
+ const QString percentString = QStringLiteral("_qfx_percent");
+
bool usesPercent = false;
int index = 0;
foreach (QQuickPathElement *pathElement, d->_pathElements) {
diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp
index 0bd22d1d25..4418f6dd9c 100644
--- a/src/quick/util/qquickprofiler.cpp
+++ b/src/quick/util/qquickprofiler.cpp
@@ -72,7 +72,7 @@ void QQuickProfilerData::toByteArrays(QList<QByteArray> &messages) const
switch (decodedMessageType) {
case QQuickProfiler::Event:
if (decodedDetailType == (int)QQuickProfiler::AnimationFrame)
- ds << framerate << count;
+ ds << framerate << count << threadId;
break;
case QQuickProfiler::PixmapCacheEvent:
ds << detailUrl.toString();
@@ -137,7 +137,14 @@ void QQuickProfiler::initialize()
void animationTimerCallback(qint64 delta)
{
- Q_QUICK_PROFILE(animationFrame(delta));
+ Q_QUICK_PROFILE(animationFrame(delta,
+ QThread::currentThread() == QCoreApplication::instance()->thread() ?
+ QQuickProfiler::GuiThread : QQuickProfiler::RenderThread));
+}
+
+void QQuickProfiler::registerAnimationCallback()
+{
+ QUnifiedTimer::instance()->registerProfilerCallback(&animationTimerCallback);
}
class CallbackRegistrationHelper : public QObject {
@@ -145,7 +152,7 @@ class CallbackRegistrationHelper : public QObject {
public slots:
void registerAnimationTimerCallback()
{
- QUnifiedTimer::instance()->registerProfilerCallback(&animationTimerCallback);
+ QQuickProfiler::registerAnimationCallback();
delete this;
}
};
diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h
index 721560b9e5..03cef951b5 100644
--- a/src/quick/util/qquickprofiler_p.h
+++ b/src/quick/util/qquickprofiler_p.h
@@ -95,9 +95,9 @@ struct Q_AUTOTEST_EXPORT QQuickProfilerData
framerate(framerate), count(count) {}
QQuickProfilerData(qint64 time, int messageType, int detailType, int framerate = 0,
- int count = 0) :
+ int count = 0, int threadId = 0) :
time(time), messageType(messageType), detailType(detailType), framerate(framerate),
- count(count) {}
+ count(count), threadId(threadId) {}
// Special ctor for scenegraph frames. Note that it's missing the QString/QUrl params.
// This is slightly ugly, but makes it easier to disambiguate between int and qint64 params.
@@ -133,7 +133,10 @@ struct Q_AUTOTEST_EXPORT QQuickProfilerData
int count; //used by animation events and for pixmaps
};
- qint64 subtime_5;
+ union {
+ qint64 subtime_5;
+ int threadId;
+ };
void toByteArrays(QList<QByteArray> &messages) const;
};
@@ -144,6 +147,11 @@ class Q_QUICK_PRIVATE_EXPORT QQuickProfiler : public QQmlAbstractProfilerAdapter
Q_OBJECT
public:
+ enum AnimationThread {
+ GuiThread,
+ RenderThread
+ };
+
template<EventType DetailType>
static void addEvent()
{
@@ -151,13 +159,14 @@ public:
1 << DetailType));
}
- static void animationFrame(qint64 delta)
+ static void animationFrame(qint64 delta, AnimationThread threadId)
{
int animCount = QUnifiedTimer::instance()->runningAnimationCount();
if (animCount > 0 && delta > 0) {
s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), 1 << Event,
- 1 << AnimationFrame, 1000 / (int)delta /* trim fps to integer */, animCount));
+ 1 << AnimationFrame, 1000 / (int)delta /* trim fps to integer */, animCount,
+ threadId));
}
}
@@ -191,6 +200,8 @@ public:
1 << PixmapCacheEvent, 1 << CountType, url, 0, 0, 0, count));
}
+ static void registerAnimationCallback();
+
qint64 timestamp() { return m_timer.nsecsElapsed(); }
qint64 sendMessages(qint64 until, QList<QByteArray> &messages);
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index b2f490e3c8..1786317356 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -46,9 +46,9 @@
#include <qqmlinfo.h>
#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlscript_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>
@@ -205,6 +205,7 @@ public:
QPointer<QObject> object;
QByteArray data;
+ QQmlRefPointer<QQmlCompiledData> cdata;
bool decoded : 1;
bool restore : 1;
@@ -259,9 +260,8 @@ void QQuickPropertyChangesParser::compileList(QList<QPair<QString, const QV4::Co
list << qMakePair(propName, binding);
}
-QByteArray QQuickPropertyChangesParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &props)
+QByteArray QQuickPropertyChangesParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
{
- Q_UNUSED(objectIndex)
QList<QPair<QString, const QV4::CompiledData::Binding *> > data;
for (int ii = 0; ii < props.count(); ++ii)
compileList(data, QString(), qmlUnit, props.at(ii));
@@ -272,12 +272,13 @@ QByteArray QQuickPropertyChangesParser::compile(const QV4::CompiledData::QmlUnit
ds << data.count();
for (int ii = 0; ii < data.count(); ++ii) {
const QV4::CompiledData::Binding *binding = data.at(ii).second;
+ ds << data.at(ii).first << int(binding->type);
QVariant var;
- bool isScript = binding->type == QV4::CompiledData::Binding::Type_Script;
- QQmlBinding::Identifier id = QQmlBinding::Invalid;
switch (binding->type) {
case QV4::CompiledData::Binding::Type_Script:
- // ### pre-compile binding
+ ds << bindingIdentifier(binding);
+ // Fall through as we also need the expression string.
+ // Signal handlers still need to be constructed by string ;(
case QV4::CompiledData::Binding::Type_String:
var = binding->valueAsString(&qmlUnit->header);
break;
@@ -289,13 +290,12 @@ QByteArray QQuickPropertyChangesParser::compile(const QV4::CompiledData::QmlUnit
break;
case QV4::CompiledData::Binding::Type_Translation:
case QV4::CompiledData::Binding::Type_TranslationById:
- Q_UNREACHABLE();
+ ds << binding->value.translationData.commentIndex << binding->value.translationData.number;
+ var = binding->stringIndex;
default:
break;
}
- ds << data.at(ii).first << isScript << var;
- if (isScript)
- ds << id;
+ ds << var;
}
return rv;
@@ -313,36 +313,30 @@ void QQuickPropertyChangesPrivate::decode()
ds >> count;
for (int ii = 0; ii < count; ++ii) {
QString name;
- bool isScript;
+ int type;
QVariant data;
QQmlBinding::Identifier id = QQmlBinding::Invalid;
+ QV4::CompiledData::TranslationData tsd;
ds >> name;
- ds >> isScript;
- ds >> data;
- if (isScript)
+ ds >> type;
+
+ if (type == QV4::CompiledData::Binding::Type_Script) {
ds >> id;
+ } else if (type == QV4::CompiledData::Binding::Type_Translation
+ || type == QV4::CompiledData::Binding::Type_TranslationById) {
+ ds >> tsd.commentIndex >> tsd.number;
+ }
+
+ ds >> data;
QQmlProperty prop = property(name); //### better way to check for signal property?
if (prop.type() & QQmlProperty::SignalProperty) {
- QString expression = data.toString();
- QUrl url = QUrl();
- int line = -1;
- int column = -1;
-
- QQmlData *ddata = QQmlData::get(q);
- if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
- url = ddata->outerContext->url;
- line = ddata->lineNumber;
- column = ddata->columnNumber;
- }
-
QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
handler->property = prop;
handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
- QQmlContextData::get(qmlContext(q)), object, expression,
- url.toString(), line, column));
+ QQmlContextData::get(qmlContext(q)), object, cdata->functionForBindingId(id)));
signalReplacements << handler;
- } else if (isScript) { // binding
+ } else if (type == QV4::CompiledData::Binding::Type_Script) { // binding
QString expression = data.toString();
QUrl url = QUrl();
int line = -1;
@@ -357,6 +351,14 @@ void QQuickPropertyChangesPrivate::decode()
expressions << ExpressionChange(name, id, expression, url, line, column);
} else {
+ if (type == QV4::CompiledData::Binding::Type_Translation
+ || type == QV4::CompiledData::Binding::Type_TranslationById) {
+ QV4::CompiledData::Binding tmpBinding;
+ tmpBinding.type = type;
+ tmpBinding.stringIndex = data.toInt();
+ tmpBinding.value.translationData = tsd;
+ data = tmpBinding.valueAsString(&cdata->qmlUnit->header);
+ }
properties << qMakePair(name, data);
}
}
@@ -364,12 +366,12 @@ void QQuickPropertyChangesPrivate::decode()
data.clear();
}
-void QQuickPropertyChangesParser::setCustomData(QObject *object,
- const QByteArray &data)
+void QQuickPropertyChangesParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *cdata)
{
QQuickPropertyChangesPrivate *p =
static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(object));
p->data = data;
+ p->cdata = cdata;
p->decoded = false;
}
diff --git a/src/quick/util/qquickpropertychanges_p.h b/src/quick/util/qquickpropertychanges_p.h
index 6d238f5ca5..3eed151d11 100644
--- a/src/quick/util/qquickpropertychanges_p.h
+++ b/src/quick/util/qquickpropertychanges_p.h
@@ -94,8 +94,8 @@ public:
void compileList(QList<QPair<QString, const QV4::CompiledData::Binding *> > &list, const QString &pre, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding);
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &props);
- virtual void setCustomData(QObject *, const QByteArray &);
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
+ virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *);
};
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index a0e6c36830..a23f7a5df6 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -313,6 +313,13 @@ void QSmoothedAnimation::init()
}
}
+void QSmoothedAnimation::debugAnimation(QDebug d) const
+{
+ d << "SmoothedAnimationJob(" << hex << (void *) this << dec << ")" << "duration:" << userDuration
+ << "velocity:" << velocity << "target:" << target.object() << "property:" << target.name()
+ << "to:" << to << "current velocity:" << trackVelocity;
+}
+
/*!
\qmltype SmoothedAnimation
\instantiates QQuickSmoothedAnimation
diff --git a/src/quick/util/qquicksmoothedanimation_p_p.h b/src/quick/util/qquicksmoothedanimation_p_p.h
index 7835d0328b..3c85f09b04 100644
--- a/src/quick/util/qquicksmoothedanimation_p_p.h
+++ b/src/quick/util/qquicksmoothedanimation_p_p.h
@@ -105,6 +105,7 @@ public:
protected:
virtual void updateCurrentTime(int);
virtual void updateState(QAbstractAnimationJob::State, QAbstractAnimationJob::State);
+ void debugAnimation(QDebug d) const;
private:
qreal easeFollow(qreal);
diff --git a/src/quick/util/qquickspringanimation.cpp b/src/quick/util/qquickspringanimation.cpp
index f237c09bf9..4b1abcef8c 100644
--- a/src/quick/util/qquickspringanimation.cpp
+++ b/src/quick/util/qquickspringanimation.cpp
@@ -101,6 +101,7 @@ public:
protected:
virtual void updateCurrentTime(int time);
virtual void updateState(QAbstractAnimationJob::State, QAbstractAnimationJob::State);
+ void debugAnimation(QDebug d) const;
private:
QQuickSpringAnimationPrivate *animationTemplate;
@@ -320,6 +321,15 @@ void QSpringAnimation::updateState(QAbstractAnimationJob::State newState, QAbstr
init();
}
+void QSpringAnimation::debugAnimation(QDebug d) const
+{
+ d << "SpringAnimationJob(" << hex << (void *) this << dec << ")" << "velocity:" << maxVelocity
+ << "spring:" << spring << "damping:" << damping << "epsilon:" << epsilon << "modulus:" << modulus
+ << "mass:" << mass << "target:" << target.object() << "property:" << target.name()
+ << "to:" << to << "current velocity:" << velocity;
+}
+
+
void QQuickSpringAnimationPrivate::updateMode()
{
if (spring == 0. && maxVelocity == 0.)
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index f2b2d2af06..80586bd45b 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -89,7 +89,7 @@ public:
QQmlContext *context,
bool preloadImages,
bool *fontSizeModified)
- : text(t), layout(l), imgTags(&imgTags), baseFont(layout.font()), baseUrl(baseUrl), hasNewLine(false), nbImages(0), updateImagePositions(false)
+ : text(t), layout(l), imgTags(&imgTags), baseFont(layout.font()), baseUrl(baseUrl), hasNewLine(true), nbImages(0), updateImagePositions(false)
, preFormat(false), prependSpace(false), hasSpace(true), preloadImages(preloadImages), fontSizeModified(fontSizeModified), context(context)
{
}
diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp
index 94e1f30215..f9928c4d00 100644
--- a/src/quick/util/qquicktimeline.cpp
+++ b/src/quick/util/qquicktimeline.cpp
@@ -723,6 +723,11 @@ void QQuickTimeLine::updateCurrentTime(int v)
}
}
+void QQuickTimeLine::debugAnimation(QDebug d) const
+{
+ d << "QuickTimeLine(" << hex << (void *) this << dec << ")";
+}
+
bool operator<(const QPair<int, Update> &lhs,
const QPair<int, Update> &rhs)
{
diff --git a/src/quick/util/qquicktimeline_p_p.h b/src/quick/util/qquicktimeline_p_p.h
index a99a515f0a..0172ecbfcf 100644
--- a/src/quick/util/qquicktimeline_p_p.h
+++ b/src/quick/util/qquicktimeline_p_p.h
@@ -109,6 +109,7 @@ Q_SIGNALS:
protected:
virtual void updateCurrentTime(int);
+ void debugAnimation(QDebug d) const;
private:
void remove(QQuickTimeLineObject *);
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 46db2ddfeb..e20e5f22ab 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -66,10 +66,29 @@ QT_BEGIN_NAMESPACE
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
+class QQuickWidgetRenderControl : public QQuickRenderControl
+{
+public:
+ QQuickWidgetRenderControl(QQuickWidget *quickwidget) : m_quickWidget(quickwidget) {}
+ QWindow *renderWindow(QPoint *offset) {
+ if (offset)
+ *offset = m_quickWidget->mapTo(m_quickWidget->window(), QPoint());
+ return m_quickWidget->window()->windowHandle();
+ }
+private:
+ QQuickWidget *m_quickWidget;
+};
+
void QQuickWidgetPrivate::init(QQmlEngine* e)
{
Q_Q(QQuickWidget);
+ renderControl = new QQuickWidgetRenderControl(q);
+ offscreenWindow = new QQuickWindow(renderControl);
+ offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
+ // Do not call create() on offscreenWindow.
+ createOffscreenSurface();
+
setRenderToTexture();
engine = e;
@@ -97,22 +116,17 @@ void QQuickWidgetPrivate::handleWindowChange()
QQuickWidgetPrivate::QQuickWidgetPrivate()
: root(0)
, component(0)
+ , offscreenWindow(0)
+ , offscreenSurface(0)
+ , renderControl(0)
, fbo(0)
, context(0)
, resizeMode(QQuickWidget::SizeViewToRootObject)
, initialSize(0,0)
- , updateTimer(0)
, eventPending(false)
, updatePending(false)
, fakeHidden(false)
{
- renderControl = new QQuickRenderControl;
- offscreenWindow = new QQuickWindow(renderControl);
- offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
- // Do not call create() on offscreenWindow.
- offscreenSurface = new QOffscreenSurface;
- offscreenSurface->setFormat(offscreenWindow->requestedFormat());
- offscreenSurface->create();
}
QQuickWidgetPrivate::~QQuickWidgetPrivate()
@@ -125,6 +139,15 @@ QQuickWidgetPrivate::~QQuickWidgetPrivate()
delete fbo;
}
+void QQuickWidgetPrivate::createOffscreenSurface()
+{
+ delete offscreenSurface;
+ offscreenSurface = 0;
+ offscreenSurface = new QOffscreenSurface;
+ offscreenSurface->setFormat(offscreenWindow->requestedFormat());
+ offscreenSurface->create();
+}
+
void QQuickWidgetPrivate::execute()
{
Q_Q(QQuickWidget);
@@ -188,11 +211,28 @@ void QQuickWidgetPrivate::renderSceneGraph()
}
/*!
+ \module QtQuickWidgets
+ \title Qt Quick Widgets C++ Classes
+ \ingroup modules
+ \brief The C++ API provided by the Qt Quick Widgets module
+ \qtvariable quickwidgets
+
+ To link against the module, add this line to your \l qmake
+ \c .pro file:
+
+ \code
+ QT += quickwidgets
+ \endcode
+
+ For more information, see the QQuickWidget class documentation.
+*/
+
+/*!
\class QQuickWidget
\since 5.3
\brief The QQuickWidget class provides a widget for displaying a Qt Quick user interface.
- \inmodule QtQuick
+ \inmodule QtQuickWidgets
This is a convenience wrapper for QQuickWindow which will automatically load and display a QML
scene when given the URL of the main source file. Alternatively, you can instantiate your own
@@ -225,7 +265,7 @@ void QQuickWidgetPrivate::renderSceneGraph()
some of the benefits of threaded rendering, for example \l Animator classes and vsync driven
animations, will not be available.
- \sa {Exposing Attributes of C++ Types to QML}, QQuickView
+ \sa {Exposing Attributes of C++ Types to QML}, {Qt Quick Widgets Example}, QQuickView
*/
@@ -395,12 +435,12 @@ QQmlContext* QQuickWidget::rootContext() const
/*!
\fn void QQuickWidget::sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message)
- This signal is emitted when an error occurred during scene graph initialization.
+ This signal is emitted when an \a error occurred during scene graph initialization.
Applications should connect to this signal if they wish to handle errors,
like OpenGL context creation failures, in a custom way. When no slot is
connected to the signal, the behavior will be different: Quick will print
- the message, or show a message box, and terminate the application.
+ the \a message, or show a message box, and terminate the application.
This signal will be emitted from the gui thread.
@@ -560,10 +600,10 @@ void QQuickWidgetPrivate::createContext()
context = new QOpenGLContext;
context->setFormat(offscreenWindow->requestedFormat());
- if (QSGContext::sharedOpenGLContext())
- context->setShareContext(QSGContext::sharedOpenGLContext()); // ??? is this correct
+ if (QOpenGLContextPrivate::globalShareContext())
+ context->setShareContext(QOpenGLContextPrivate::globalShareContext());
if (!context->create()) {
- const bool isEs = context->isES();
+ const bool isEs = context->isOpenGLES();
delete context;
context = 0;
handleContextCreationFailure(offscreenWindow->requestedFormat(), isEs);
@@ -604,7 +644,7 @@ void QQuickWidget::createFramebufferObject()
}
context->makeCurrent(d->offscreenSurface);
- d->fbo = new QOpenGLFramebufferObject(size());
+ d->fbo = new QOpenGLFramebufferObject(size() * window()->devicePixelRatio());
d->fbo->setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
d->offscreenWindow->setRenderTarget(d->fbo);
@@ -687,7 +727,8 @@ void QQuickWidgetPrivate::setRootObject(QObject *obj)
}
if (root) {
initialSize = rootObjectSize();
- if ((resizeMode == QQuickWidget::SizeViewToRootObject || q->width() <= 1 || q->height() <= 1) &&
+ bool resized = q->testAttribute(Qt::WA_Resized);
+ if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
initialSize != q->size()) {
q->resize(initialSize);
}
@@ -702,8 +743,7 @@ GLuint QQuickWidgetPrivate::textureId() const
/*!
\internal
- If the \l {QTimerEvent} {timer event} \a e is this
- view's resize timer, sceneResized() is emitted.
+ Handle item resize and scene updates.
*/
void QQuickWidget::timerEvent(QTimerEvent* e)
{
@@ -711,6 +751,11 @@ void QQuickWidget::timerEvent(QTimerEvent* e)
if (!e || e->timerId() == d->resizetimer.timerId()) {
d->updateSize();
d->resizetimer.stop();
+ } else if (e->timerId() == d->updateTimer.timerId()) {
+ d->eventPending = false;
+ d->updateTimer.stop();
+ if (d->updatePending)
+ d->renderSceneGraph();
}
}
@@ -902,14 +947,6 @@ bool QQuickWidget::event(QEvent *e)
Q_D(QQuickWidget);
switch (e->type()) {
- case QEvent::Timer:
- d->eventPending = false;
- killTimer(d->updateTimer);
- d->updateTimer = 0;
- if (d->updatePending)
- d->renderSceneGraph();
- return true;
-
case QEvent::TouchBegin:
case QEvent::TouchEnd:
case QEvent::TouchUpdate:
@@ -936,9 +973,47 @@ void QQuickWidget::triggerUpdate()
d->updatePending = true;
if (!d->eventPending) {
const int exhaustDelay = 5;
- d->updateTimer = startTimer(exhaustDelay, Qt::PreciseTimer);
+ d->updateTimer.start(exhaustDelay, Qt::PreciseTimer, this);
d->eventPending = true;
}
}
+/*!
+ Sets the surface \a format for the context and offscreen surface used
+ by this widget.
+
+ Call this function when there is a need to request a context for a
+ given OpenGL version or profile. The sizes for depth, stencil and
+ alpha buffers are taken care of automatically and there is no need
+ to request those explicitly.
+
+ \sa QWindow::setFormat(), QWindow::format(), format()
+*/
+void QQuickWidget::setFormat(const QSurfaceFormat &format)
+{
+ Q_D(QQuickWidget);
+ QSurfaceFormat currentFormat = d->offscreenWindow->format();
+ QSurfaceFormat newFormat = format;
+ newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
+ newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
+ newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
+ if (currentFormat != newFormat) {
+ d->offscreenWindow->setFormat(newFormat);
+ d->createOffscreenSurface();
+ }
+}
+
+/*!
+ Returns the actual surface format.
+
+ If the widget has not yet been shown, the requested format is returned.
+
+ \sa setFormat()
+*/
+QSurfaceFormat QQuickWidget::format() const
+{
+ Q_D(const QQuickWidget);
+ return d->offscreenWindow->format();
+}
+
QT_END_NAMESPACE
diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h
index 2c021c85fb..81e9af02fb 100644
--- a/src/quickwidgets/qquickwidget.h
+++ b/src/quickwidgets/qquickwidget.h
@@ -89,6 +89,9 @@ public:
QSize sizeHint() const;
QSize initialSize() const;
+ void setFormat(const QSurfaceFormat &format);
+ QSurfaceFormat format() const;
+
public Q_SLOTS:
void setSource(const QUrl&);
void setContent(const QUrl& url, QQmlComponent *component, QObject *item);
diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
index 1ba06162f9..5cf2bfbf1d 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -87,6 +87,7 @@ public:
void createContext();
void destroyContext();
void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs);
+ void createOffscreenSurface();
GLuint textureId() const Q_DECL_OVERRIDE;
@@ -112,7 +113,7 @@ public:
QSize initialSize;
QElapsedTimer frameTimer;
- int updateTimer;
+ QBasicTimer updateTimer;
bool eventPending;
bool updatePending;
bool fakeHidden;
diff --git a/src/src.pro b/src/src.pro
index 0cffc9abc0..0f09f34211 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -15,6 +15,6 @@ SUBDIRS += \
imports \
qmldevtools
-qtHaveModule(widgets):SUBDIRS += quickwidgets
+qtHaveModule(quick):qtHaveModule(widgets): SUBDIRS += quickwidgets
qmldevtools.CONFIG = host_build
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index 6dbdc83b08..a918e23a05 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -208,7 +208,9 @@ void QQmlProfilerClient::messageReceived(const QByteArray &message)
switch (data.detailType) {
case QQmlProfilerClient::AnimationFrame: {
- stream >> data.framerate >> data.animationcount;
+ int threadId;
+ stream >> data.framerate >> data.animationcount >> threadId;
+ QVERIFY(threadId >= 0);
QVERIFY(data.framerate != -1);
QVERIFY(data.animationcount != -1);
break;
@@ -396,6 +398,7 @@ void tst_QQmlProfilerService::nonBlockingConnect()
m_client->setTraceState(true);
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
+ QVERIFY(m_client->traceMessages.count());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
@@ -422,7 +425,8 @@ void tst_QQmlProfilerService::pixmapCacheData()
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 20);
+ QVERIFY2(m_client->traceMessages.count() >= 20,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
@@ -495,7 +499,8 @@ void tst_QQmlProfilerService::profileOnExit()
m_client->setTraceState(true);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 2);
+ QVERIFY2(m_client->traceMessages.count() >= 2,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
@@ -514,7 +519,8 @@ void tst_QQmlProfilerService::controlFromJS()
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 2);
+ QVERIFY2(m_client->traceMessages.count() >= 2,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
@@ -537,22 +543,26 @@ void tst_QQmlProfilerService::signalSourceLocation()
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 20);
+ QVERIFY2(m_client->traceMessages.count() >= 20,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
+
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace);
- QVERIFY(m_client->traceMessages[14].messageType == QQmlProfilerClient::RangeLocation);
- QVERIFY(m_client->traceMessages[14].detailType == QQmlProfilerClient::HandlingSignal);
- QVERIFY(m_client->traceMessages[14].detailData.endsWith("signalSourceLocation.qml"));
- QVERIFY(m_client->traceMessages[14].line == 8);
- QVERIFY(m_client->traceMessages[14].column == 28);
+ QCOMPARE(m_client->traceMessages[14].messageType, (int)QQmlProfilerClient::RangeLocation);
+ QCOMPARE(m_client->traceMessages[14].detailType, (int)QQmlProfilerClient::HandlingSignal);
+ QVERIFY2(m_client->traceMessages[14].detailData.endsWith("signalSourceLocation.qml"),
+ m_client->traceMessages[14].detailData.toUtf8().constData());
+ QCOMPARE(m_client->traceMessages[14].line, 8);
+ QCOMPARE(m_client->traceMessages[14].column, 28);
- QVERIFY(m_client->traceMessages[19].messageType == QQmlProfilerClient::RangeLocation);
- QVERIFY(m_client->traceMessages[19].detailType == QQmlProfilerClient::HandlingSignal);
- QVERIFY(m_client->traceMessages[19].detailData.endsWith("signalSourceLocation.qml"));
- QVERIFY(m_client->traceMessages[19].line == 7);
- QVERIFY(m_client->traceMessages[19].column == 21);
+ QCOMPARE(m_client->traceMessages[19].messageType, (int)QQmlProfilerClient::RangeLocation);
+ QCOMPARE(m_client->traceMessages[19].detailType, (int)QQmlProfilerClient::HandlingSignal);
+ QVERIFY2(m_client->traceMessages[19].detailData.endsWith("signalSourceLocation.qml"),
+ m_client->traceMessages[19].detailData.toUtf8().constData());
+ QCOMPARE(m_client->traceMessages[19].line, 7);
+ QCOMPARE(m_client->traceMessages[19].column, 21);
// must end with "EndTrace"
QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event);
@@ -571,26 +581,29 @@ void tst_QQmlProfilerService::javascript()
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 36);
+ QVERIFY2(m_client->traceMessages.count() >= 36,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace);
- QVERIFY(m_client->traceMessages[32].messageType == QQmlProfilerClient::RangeStart);
- QVERIFY(m_client->traceMessages[32].detailType == QQmlProfilerClient::Javascript);
+ QCOMPARE(m_client->traceMessages[32].messageType, (int)QQmlProfilerClient::RangeStart);
+ QCOMPARE(m_client->traceMessages[32].detailType, (int)QQmlProfilerClient::Javascript);
- QVERIFY(m_client->traceMessages[33].messageType == QQmlProfilerClient::RangeLocation);
- QVERIFY(m_client->traceMessages[33].detailType == QQmlProfilerClient::Javascript);
- QVERIFY(m_client->traceMessages[33].detailData.endsWith("javascript.qml"));
- QVERIFY(m_client->traceMessages[33].line == 4);
- QVERIFY(m_client->traceMessages[33].column == 5);
+ QCOMPARE(m_client->traceMessages[33].messageType, (int)QQmlProfilerClient::RangeLocation);
+ QCOMPARE(m_client->traceMessages[33].detailType, (int)QQmlProfilerClient::Javascript);
+ QVERIFY2(m_client->traceMessages[33].detailData.endsWith("javascript.qml"),
+ m_client->traceMessages[33].detailData.toUtf8().constData());
+ QCOMPARE(m_client->traceMessages[33].line, 4);
+ QCOMPARE(m_client->traceMessages[33].column, 5);
- QVERIFY(m_client->traceMessages[34].messageType == QQmlProfilerClient::RangeData);
- QVERIFY(m_client->traceMessages[34].detailType == QQmlProfilerClient::Javascript);
- QVERIFY(m_client->traceMessages[34].detailData == "something");
+ QCOMPARE(m_client->traceMessages[34].messageType, (int)QQmlProfilerClient::RangeData);
+ QCOMPARE(m_client->traceMessages[34].detailType, (int)QQmlProfilerClient::Javascript);
+ QVERIFY2(m_client->traceMessages[34].detailData == "something",
+ m_client->traceMessages[34].detailData.toUtf8().constData());
- QVERIFY(m_client->traceMessages[35].messageType == QQmlProfilerClient::RangeEnd);
- QVERIFY(m_client->traceMessages[35].detailType == QQmlProfilerClient::Javascript);
+ QCOMPARE(m_client->traceMessages[35].messageType, (int)QQmlProfilerClient::RangeEnd);
+ QCOMPARE(m_client->traceMessages[35].detailType, (int)QQmlProfilerClient::Javascript);
// must end with "EndTrace"
QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event);
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 53e86268a6..b2723b02fd 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -48,6 +48,7 @@
#include <qstandarditemmodel.h>
#include <QtCore/qnumeric.h>
#include <qqmlengine.h>
+#include <qqmlcomponent.h>
#include <stdlib.h>
#include <private/qv4alloca_p.h>
@@ -115,7 +116,8 @@ private slots:
void jsForInStatement_prototypeProperties();
void jsForInStatement_mutateWhileIterating();
void jsForInStatement_arrays();
- void jsForInStatement_nullAndUndefined();
+ void jsForInStatement_constant();
+ void with_constant();
void stringObjects();
void jsStringPrototypeReplaceBugs();
void getterSetterThisObject_global();
@@ -150,6 +152,11 @@ private slots:
void regexpLastMatch();
void indexedAccesses();
+ void prototypeChainGc();
+ void prototypeChainGc_QTBUG38299();
+
+ void dynamicProperties();
+
signals:
void testSignal();
};
@@ -162,6 +169,9 @@ tst_QJSEngine::~tst_QJSEngine()
{
}
+Q_DECLARE_METATYPE(Qt::KeyboardModifier)
+Q_DECLARE_METATYPE(Qt::KeyboardModifiers)
+
class OverloadedSlots : public QObject
{
Q_OBJECT
@@ -174,6 +184,7 @@ signals:
void slotWithoutArgCalled();
void slotWithSingleArgCalled(const QString &arg);
void slotWithArgumentsCalled(const QString &arg1, const QString &arg2, const QString &arg3);
+ void slotWithOverloadedArgumentsCalled(const QString &arg, Qt::KeyboardModifier modifier, Qt::KeyboardModifiers moreModifiers);
public slots:
void slotToCall() { emit slotWithoutArgCalled(); }
@@ -182,6 +193,10 @@ public slots:
{
slotWithArgumentsCalled(arg, arg2, arg3);
}
+ void slotToCall(const QString &arg, Qt::KeyboardModifier modifier, Qt::KeyboardModifiers blah = Qt::ShiftModifier)
+ {
+ emit slotWithOverloadedArgumentsCalled(arg, modifier, blah);
+ }
};
void tst_QJSEngine::callQObjectSlot()
@@ -227,6 +242,18 @@ void tst_QJSEngine::callQObjectSlot()
QCOMPARE(arguments.at(1).toString(), QString("arg2"));
QCOMPARE(arguments.at(2).toString(), QString("arg3"));
}
+
+ {
+ QSignalSpy spy(&dummy, SIGNAL(slotWithOverloadedArgumentsCalled(QString, Qt::KeyboardModifier, Qt::KeyboardModifiers)));
+ eng.evaluate(QStringLiteral("dummy.slotToCall('arg', %1);").arg(QString::number(Qt::ControlModifier)));
+ QCOMPARE(spy.count(), 1);
+
+ const QList<QVariant> arguments = spy.first();
+ QCOMPARE(arguments.at(0).toString(), QString("arg"));
+ QCOMPARE(arguments.at(1).toInt(), int(Qt::ControlModifier));
+ QCOMPARE(int(qvariant_cast<Qt::KeyboardModifiers>(arguments.at(2))), int(Qt::ShiftModifier));
+
+ }
}
void tst_QJSEngine::constructWithParent()
@@ -1011,6 +1038,8 @@ void tst_QJSEngine::evaluate_data()
QTest::newRow("/a/g") << QString("/a/g") << -1 << false << -1;
QTest::newRow("/a/gim") << QString("/a/gim") << -1 << false << -1;
QTest::newRow("/a/gimp") << QString("/a/gimp") << 1 << true << 1;
+ QTest::newRow("empty-array-concat") << QString("var a = []; var b = [1]; var c = a.concat(b); ") << 1 << false << -1;
+ QTest::newRow("object-literal") << QString("var a = {\"0\":\"#\",\"2\":\"#\",\"5\":\"#\",\"8\":\"#\",\"6\":\"#\",\"12\":\"#\",\"13\":\"#\",\"16\":\"#\",\"18\":\"#\",\"39\":\"#\",\"40\":\"#\"}") << 1 << false << -1;
}
void tst_QJSEngine::evaluate()
@@ -1207,6 +1236,14 @@ void tst_QJSEngine::valueConversion_QVariant()
QCOMPARE(qjsvalue_cast<QVariant>(QJSValue(123)), QVariant(123));
QVERIFY(eng.toScriptValue(QVariant(QMetaType::VoidStar, 0)).isNull());
+
+ {
+ QVariantMap map;
+ map.insert("42", "the answer to life the universe and everything");
+ QJSValue val = eng.toScriptValue(map);
+ QVERIFY(val.isObject());
+ QCOMPARE(val.property(42).toString(), map.value(QStringLiteral("42")).toString());
+ }
}
void tst_QJSEngine::valueConversion_basic2()
@@ -1982,7 +2019,7 @@ void tst_QJSEngine::jsForInStatement_arrays()
}
}
-void tst_QJSEngine::jsForInStatement_nullAndUndefined()
+void tst_QJSEngine::jsForInStatement_constant()
{
QJSEngine eng;
{
@@ -1995,6 +2032,34 @@ void tst_QJSEngine::jsForInStatement_nullAndUndefined()
QVERIFY(ret.isBool());
QVERIFY(ret.toBool());
}
+ {
+ QJSValue ret = eng.evaluate("r = false; for (var p in 1) r = true; r");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+ {
+ QJSValue ret = eng.evaluate("r = false; for (var p in 'abc') r = true; r");
+ QVERIFY(ret.isBool());
+ QVERIFY(ret.toBool());
+ }
+}
+
+void tst_QJSEngine::with_constant()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("r = false; with(null) { r= true; } r");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("r = false; with(undefined) { r= true; } r");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("r = false; with(1) { r= true; } r");
+ QVERIFY(ret.isBool());
+ QVERIFY(ret.toBool());
+ }
}
void tst_QJSEngine::stringObjects()
@@ -2883,6 +2948,69 @@ void tst_QJSEngine::indexedAccesses()
QVERIFY(v.isUndefined());
}
+void tst_QJSEngine::prototypeChainGc()
+{
+ QJSEngine engine;
+
+ QJSValue getProto = engine.evaluate("Object.getPrototypeOf");
+
+ QJSValue factory = engine.evaluate("function() { return Object.create(Object.create({})); }");
+ QVERIFY(factory.isCallable());
+ QJSValue obj = factory.call();
+ engine.collectGarbage();
+
+ QJSValue proto = getProto.call(QJSValueList() << obj);
+ proto = getProto.call(QJSValueList() << proto);
+ QVERIFY(proto.isObject());
+}
+
+void tst_QJSEngine::prototypeChainGc_QTBUG38299()
+{
+ QJSEngine engine;
+ engine.evaluate("var mapping = {"
+ "'prop1': \"val1\",\n"
+ "'prop2': \"val2\"\n"
+ "}\n"
+ "\n"
+ "delete mapping.prop2\n"
+ "delete mapping.prop1\n"
+ "\n");
+ // Don't hang!
+ engine.collectGarbage();
+}
+
+void tst_QJSEngine::dynamicProperties()
+{
+ {
+ QJSEngine engine;
+ QObject *obj = new QObject;
+ QJSValue wrapper = engine.newQObject(obj);
+ wrapper.setProperty("someRandomProperty", 42);
+ QCOMPARE(wrapper.property("someRandomProperty").toInt(), 42);
+ QVERIFY(!qmlContext(obj));
+ }
+ {
+ QQmlEngine qmlEngine;
+ QQmlComponent component(&qmlEngine);
+ component.setData("import QtQml 2.0; QtObject { property QtObject subObject: QtObject {} }", QUrl());
+ QObject *root = component.create(0);
+ QVERIFY(root);
+ QVERIFY(qmlContext(root));
+
+ QJSValue wrapper = qmlEngine.newQObject(root);
+ wrapper.setProperty("someRandomProperty", 42);
+ QVERIFY(!wrapper.hasProperty("someRandomProperty"));
+
+ QObject *subObject = qvariant_cast<QObject*>(root->property("subObject"));
+ QVERIFY(subObject);
+ QVERIFY(qmlContext(subObject));
+
+ wrapper = qmlEngine.newQObject(subObject);
+ wrapper.setProperty("someRandomProperty", 42);
+ QVERIFY(!wrapper.hasProperty("someRandomProperty"));
+ }
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 74369685f5..c909a2d35a 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -68,7 +68,7 @@ qtHaveModule(widgets) {
SUBDIRS += $$PUBLICTESTS
SUBDIRS += $$METATYPETESTS
-SUBDIRS += debugger
+!winrt: SUBDIRS += debugger # no QProcess on winrt
contains(QT_CONFIG, private_tests) {
SUBDIRS += $$PRIVATETESTS
diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
index dbf48779d6..1cd1583f22 100644
--- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
+++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
@@ -251,10 +251,9 @@ void tst_qqmlconnections::rewriteErrors()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("rewriteError-unnamed.qml"));
+ QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal uses unnamed parameter followed by named parameter.").toLatin1());
TestObject *obj = qobject_cast<TestObject*>(c.create());
QVERIFY(obj != 0);
-
- QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal uses unnamed parameter followed by named parameter.").toLatin1());
obj->unnamedArgumentSignal(1, .5, "hello");
QCOMPARE(obj->ran(), false);
@@ -264,10 +263,10 @@ void tst_qqmlconnections::rewriteErrors()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("rewriteError-global.qml"));
+ QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal parameter \"parseInt\" hides global variable.").toLatin1());
TestObject *obj = qobject_cast<TestObject*>(c.create());
QVERIFY(obj != 0);
- QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal parameter \"parseInt\" hides global variable.").toLatin1());
obj->signalWithGlobalName(10);
QCOMPARE(obj->ran(), false);
diff --git a/tests/auto/qml/qqmlecmascript/data/SubObject.qml b/tests/auto/qml/qqmlecmascript/data/SubObject.qml
new file mode 100644
index 0000000000..4658edd1db
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/SubObject.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+QtObject {
+ property int testValue: -1
+ property int subValue;
+ onSubValueChanged: {
+ testValue = this.someExpression
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/Types.js b/tests/auto/qml/qqmlecmascript/data/Types.js
new file mode 100644
index 0000000000..8da80a9565
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/Types.js
@@ -0,0 +1,3 @@
+.pragma library
+
+var Foo = 0;
diff --git a/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml b/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml
new file mode 100644
index 0000000000..33b21c74a8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+QtObject {
+ property SubObject subObject: SubObject {
+ subValue: 20;
+ property int someExpression: {
+ return someValue;
+ }
+ }
+ property int someValue: 42
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importedScriptsAccessOnObjectWithInvalidContext.qml b/tests/auto/qml/qqmlecmascript/data/importedScriptsAccessOnObjectWithInvalidContext.qml
new file mode 100644
index 0000000000..74310c6d6b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importedScriptsAccessOnObjectWithInvalidContext.qml
@@ -0,0 +1,42 @@
+import QtQuick 2.0
+
+import "Types.js" as Types
+
+Rectangle {
+ id: root
+ property bool success: false
+
+ color: "white"
+ height: 100
+ width: 100
+
+ signal modelChanged
+
+ Timer {
+ id: timer
+ interval: 100
+ onTriggered: {
+ root.modelChanged();
+ root.success = true;
+ }
+ }
+
+ Loader{
+ id: weekPage
+ sourceComponent: Component {
+ Item{
+ function createAllDayEvents() {
+ if (3 == Types.Foo) {
+ console.log("Hello")
+ }
+ }
+ }
+ }
+ onLoaded: root.modelChanged.connect(item.createAllDayEvents);
+ }
+
+ Component.onCompleted: {
+ weekPage.sourceComponent = null
+ timer.running = true
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 2809124028..770d6b8197 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -320,6 +320,8 @@ private slots:
void singletonWithEnum();
void lazyBindingEvaluation();
void varPropertyAccessOnObjectWithInvalidContext();
+ void importedScriptsAccessOnObjectWithInvalidContext();
+ void contextObjectOnLazyBindings();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -2316,7 +2318,7 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::ValueRef o,
ctx->catchException();
return false;
}
- return Runtime::strictEqual(value, result);
+ return QV4::Runtime::strictEqual(value, result);
}
static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::ValueRef o,
@@ -7579,6 +7581,28 @@ void tst_qqmlecmascript::varPropertyAccessOnObjectWithInvalidContext()
QVERIFY(obj->property("success") == true);
}
+void tst_qqmlecmascript::importedScriptsAccessOnObjectWithInvalidContext()
+{
+ QQmlComponent component(&engine, testFileUrl("importedScriptsAccessOnObjectWithInvalidContext.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
+ qDebug() << component.errors().first().toString();
+ QVERIFY(!obj.isNull());
+ QTRY_VERIFY(obj->property("success") == true);
+}
+
+void tst_qqmlecmascript::contextObjectOnLazyBindings()
+{
+ QQmlComponent component(&engine, testFileUrl("contextObjectOnLazyBindings.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
+ qDebug() << component.errors().first().toString();
+ QVERIFY(!obj.isNull());
+ QObject *subObject = qvariant_cast<QObject*>(obj->property("subObject"));
+ QVERIFY(subObject);
+ QCOMPARE(subObject->property("testValue").toInt(), int(42));
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlincubator/data/objectDeleted.qml b/tests/auto/qml/qqmlincubator/data/objectDeleted.qml
index f00f975923..c9f6f8b564 100644
--- a/tests/auto/qml/qqmlincubator/data/objectDeleted.qml
+++ b/tests/auto/qml/qqmlincubator/data/objectDeleted.qml
@@ -2,7 +2,9 @@ import QtQuick 2.0
import Qt.test 1.0
Item {
- SelfRegistering {
- value: 11
+ SelfRegisteringOuter {
+ value: SelfRegistering {
+ value: 11
+ }
}
}
diff --git a/tests/auto/qml/qqmlincubator/testtypes.cpp b/tests/auto/qml/qqmlincubator/testtypes.cpp
index d926b6ae9b..b35636dd86 100644
--- a/tests/auto/qml/qqmlincubator/testtypes.cpp
+++ b/tests/auto/qml/qqmlincubator/testtypes.cpp
@@ -58,6 +58,25 @@ void SelfRegisteringType::clearMe()
m_me = 0;
}
+SelfRegisteringOuterType *SelfRegisteringOuterType::m_me = 0;
+bool SelfRegisteringOuterType::beenDeleted = false;
+SelfRegisteringOuterType::SelfRegisteringOuterType()
+: m_v(0)
+{
+ m_me = this;
+ beenDeleted = false;
+}
+
+SelfRegisteringOuterType::~SelfRegisteringOuterType()
+{
+ beenDeleted = true;
+}
+
+SelfRegisteringOuterType *SelfRegisteringOuterType::me()
+{
+ return m_me;
+}
+
CompletionRegisteringType *CompletionRegisteringType::m_me = 0;
CompletionRegisteringType::CompletionRegisteringType()
{
@@ -131,6 +150,7 @@ void CompletionCallbackType::registerCallback(callback c, void *d)
void registerTypes()
{
qmlRegisterType<SelfRegisteringType>("Qt.test", 1,0, "SelfRegistering");
+ qmlRegisterType<SelfRegisteringOuterType>("Qt.test", 1,0, "SelfRegisteringOuter");
qmlRegisterType<CompletionRegisteringType>("Qt.test", 1,0, "CompletionRegistering");
qmlRegisterType<CallbackRegisteringType>("Qt.test", 1,0, "CallbackRegistering");
qmlRegisterType<CompletionCallbackType>("Qt.test", 1,0, "CompletionCallback");
diff --git a/tests/auto/qml/qqmlincubator/testtypes.h b/tests/auto/qml/qqmlincubator/testtypes.h
index fedff61510..8202cdd9dc 100644
--- a/tests/auto/qml/qqmlincubator/testtypes.h
+++ b/tests/auto/qml/qqmlincubator/testtypes.h
@@ -63,6 +63,27 @@ private:
int m_v;
};
+class SelfRegisteringOuterType : public QObject
+{
+Q_OBJECT
+Q_PROPERTY(QObject* value READ value WRITE setValue);
+public:
+ SelfRegisteringOuterType();
+ ~SelfRegisteringOuterType();
+
+ static bool beenDeleted;
+
+ QObject *value() const { return m_v; }
+ void setValue(QObject *v) { m_v = v; }
+
+ static SelfRegisteringOuterType *me();
+
+private:
+ static SelfRegisteringOuterType *m_me;
+
+ QObject *m_v;
+};
+
class CallbackRegisteringType : public QObject
{
Q_OBJECT
diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
index d6d0b0402a..0b9872f94c 100644
--- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
+++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
@@ -52,6 +52,8 @@
#include <QQmlComponent>
#include <QQmlIncubator>
#include "../../shared/util.h"
+#include <private/qqmlincubator_p.h>
+#include <private/qqmlobjectcreator_p.h>
class tst_qqmlincubator : public QQmlDataTest
{
@@ -141,35 +143,50 @@ void tst_qqmlincubator::incubationMode()
void tst_qqmlincubator::objectDeleted()
{
- SelfRegisteringType::clearMe();
+ {
+ QQmlEngine engine;
+ QQmlIncubationController controller;
+ engine.setIncubationController(&controller);
+ SelfRegisteringType::clearMe();
- QQmlComponent component(&engine, testFileUrl("objectDeleted.qml"));
- QVERIFY(component.isReady());
+ QQmlComponent component(&engine, testFileUrl("objectDeleted.qml"));
+ QVERIFY(component.isReady());
- QQmlIncubator incubator;
- component.create(incubator);
+ QQmlIncubator incubator;
+ component.create(incubator);
- QCOMPARE(incubator.status(), QQmlIncubator::Loading);
- QVERIFY(SelfRegisteringType::me() == 0);
+ QCOMPARE(incubator.status(), QQmlIncubator::Loading);
+ QVERIFY(SelfRegisteringType::me() == 0);
- while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
- bool b = false;
- controller.incubateWhile(&b);
- }
+ while (SelfRegisteringOuterType::me() == 0 && incubator.isLoading()) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ }
- QVERIFY(SelfRegisteringType::me() != 0);
- QVERIFY(incubator.isLoading());
+ QVERIFY(SelfRegisteringOuterType::me() != 0);
+ QVERIFY(incubator.isLoading());
- delete SelfRegisteringType::me();
+ while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ }
- {
- bool b = true;
- controller.incubateWhile(&b);
- }
+ // We have to cheat and manually remove it from the creator->allCreatedObjects
+ // otherwise we will do a double delete
+ QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(&incubator);
+ incubatorPriv->creator->allCreatedObjects().pop();
+ delete SelfRegisteringType::me();
- QVERIFY(incubator.isError());
- VERIFY_ERRORS(incubator, "objectDeleted.errors.txt");
- QVERIFY(incubator.object() == 0);
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ QVERIFY(incubator.isError());
+ VERIFY_ERRORS(incubator, "objectDeleted.errors.txt");
+ QVERIFY(incubator.object() == 0);
+ }
+ QVERIFY(SelfRegisteringOuterType::beenDeleted);
}
void tst_qqmlincubator::clear()
@@ -1111,6 +1128,10 @@ void tst_qqmlincubator::selfDelete()
QVERIFY(SelfRegisteringType::me() != 0);
QVERIFY(incubator->isLoading());
+ // We have to cheat and manually remove it from the creator->allCreatedObjects
+ // otherwise we will do a double delete
+ QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubator);
+ incubatorPriv->creator->allCreatedObjects().pop();
delete SelfRegisteringType::me();
{
diff --git a/tests/auto/qml/qqmllanguage/data/SubType.qml b/tests/auto/qml/qqmllanguage/data/SubType.qml
new file mode 100644
index 0000000000..0698ae2349
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SubType.qml
@@ -0,0 +1,3 @@
+import QtQml 2.0
+QtObject {
+}
diff --git a/tests/auto/qml/qqmllanguage/data/assignNullStrings.qml b/tests/auto/qml/qqmllanguage/data/assignNullStrings.qml
new file mode 100644
index 0000000000..5e1c3a9b03
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/assignNullStrings.qml
@@ -0,0 +1,9 @@
+import Test 1.0
+MyTypeObject {
+ stringProperty: ""
+ byteArrayProperty: ""
+ function assignNullStringsFromJs() {
+ stringProperty = ""
+ byteArrayProperty = ""
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/customParserProperties.qml b/tests/auto/qml/qqmllanguage/data/customParserProperties.qml
new file mode 100644
index 0000000000..5d72edb8e5
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/customParserProperties.qml
@@ -0,0 +1,7 @@
+import Test 1.0
+import QtQml 2.0
+SimpleObjectWithCustomParser {
+ intProperty: 42
+ property string qmlString: "Hello"
+ property var someObject: QtObject {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/idProperty.qml b/tests/auto/qml/qqmllanguage/data/idProperty.qml
index bf048ea60a..dbb242804a 100644
--- a/tests/auto/qml/qqmllanguage/data/idProperty.qml
+++ b/tests/auto/qml/qqmllanguage/data/idProperty.qml
@@ -5,4 +5,8 @@ MyContainer {
MyTypeObject {
id: "myObjectId"
}
+
+ MyTypeObject {
+ selfGroupProperty.id: "name.with.dots"
+ }
}
diff --git a/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.errors.txt b/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.errors.txt
new file mode 100644
index 0000000000..d62dbd703d
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.errors.txt
@@ -0,0 +1 @@
+3:5:Cannot assign to non-existent property "nonExistantGrouped"
diff --git a/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.qml b/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.qml
new file mode 100644
index 0000000000..3b66a5f6c7
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.qml
@@ -0,0 +1,4 @@
+import Test 1.0
+MyQmlObject {
+ nonExistantGrouped.blah: MyQmlObject {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/rootObjectInCreationNotForSubObjects.qml b/tests/auto/qml/qqmllanguage/data/rootObjectInCreationNotForSubObjects.qml
new file mode 100644
index 0000000000..afba278ade
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/rootObjectInCreationNotForSubObjects.qml
@@ -0,0 +1,7 @@
+import QtQml 2.0
+import Test 1.0
+RootObjectInCreationTester {
+ subObject: SubType {
+ property int testValue: 42;
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/scriptString7.qml b/tests/auto/qml/qqmllanguage/data/scriptString7.qml
new file mode 100644
index 0000000000..a9d5b47e2b
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/scriptString7.qml
@@ -0,0 +1,6 @@
+import Test 1.0
+
+MyTypeObject {
+ intProperty: 100;
+ scriptProperty: intProperty;
+}
diff --git a/tests/auto/qml/qqmllanguage/data/{subdir}/Test.qml b/tests/auto/qml/qqmllanguage/data/{subdir}/Test.qml
new file mode 100644
index 0000000000..f789a905f2
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/{subdir}/Test.qml
@@ -0,0 +1,2 @@
+import QtQuick 2.0
+Rectangle { }
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index fad5c1e65d..8ffa327cf2 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -92,6 +92,9 @@ void registerTypes()
qmlRegisterType<MyCreateableDerivedClass,1>("Test", 1, 1, "MyCreateableDerivedClass");
qmlRegisterCustomType<CustomBinding>("Test", 1, 0, "CustomBinding", new CustomBindingParser);
+ qmlRegisterCustomType<SimpleObjectWithCustomParser>("Test", 1, 0, "SimpleObjectWithCustomParser", new SimpleObjectCustomParser);
+
+ qmlRegisterType<RootObjectInCreationTester>("Test", 1, 0, "RootObjectInCreationTester");
}
QVariant myCustomVariantTypeConverter(const QString &data)
@@ -102,9 +105,8 @@ QVariant myCustomVariantTypeConverter(const QString &data)
}
-QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings)
+QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
- Q_UNUSED(objectIndex)
QByteArray result;
QDataStream ds(&result, QIODevice::WriteOnly);
@@ -123,7 +125,7 @@ QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUni
return result;
}
-void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data)
+void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*)
{
CustomBinding *customBinding = qobject_cast<CustomBinding*>(object);
Q_ASSERT(customBinding);
@@ -155,10 +157,9 @@ void CustomBinding::componentComplete()
}
}
-QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings)
+QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
Q_UNUSED(qmlUnit)
- Q_UNUSED(objectIndex)
if (bindings.count() != 1) {
error(bindings.first(), QStringLiteral("Custom parser invoked incorrectly for unit test"));
@@ -189,3 +190,35 @@ QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit
return QByteArray();
}
+
+
+QByteArray SimpleObjectCustomParser::compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings)
+{
+ return QByteArray::number(bindings.count());
+}
+
+void SimpleObjectCustomParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*)
+{
+ SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object);
+ Q_ASSERT(o);
+ bool ok = false;
+ o->setCustomBindingsCount(data.toInt(&ok));
+ Q_ASSERT(ok);
+}
+
+
+MyQmlObject::MyQmlObject()
+ : m_value(-1)
+ , m_interface(0)
+ , m_qmlobject(0)
+ , m_childAddedEventCount(0)
+{
+ qRegisterMetaType<MyCustomVariantType>("MyCustomVariantType");
+}
+
+bool MyQmlObject::event(QEvent *event)
+{
+ if (event->type() == QEvent::ChildAdded)
+ m_childAddedEventCount++;
+ return QObject::event(event);
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index a1e2b76bd1..1c13a2e21c 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -119,7 +119,7 @@ class MyQmlObject : public QObject, public MyInterface
Q_INTERFACES(MyInterface)
public:
- MyQmlObject() : m_value(-1), m_interface(0), m_qmlobject(0) { qRegisterMetaType<MyCustomVariantType>("MyCustomVariantType"); }
+ MyQmlObject();
int value() const { return m_value; }
void setValue(int v) { m_value = v; }
@@ -161,6 +161,8 @@ public:
QJSValue qjsvalue() const { return m_qjsvalue; }
void setQJSValue(const QJSValue &value) { m_qjsvalue = value; emit qjsvalueChanged(); }
+ int childAddedEventCount() const { return m_childAddedEventCount; }
+
public slots:
void basicSlot() { qWarning("MyQmlObject::basicSlot"); }
void basicSlotWithArgs(int v) { qWarning("MyQmlObject::basicSlotWithArgs(%d)", v); }
@@ -173,6 +175,9 @@ signals:
void signalWithDefaultArg(int parameter = 5);
void qjsvalueChanged();
+protected:
+ virtual bool event(QEvent *event);
+
private:
friend class tst_qqmllanguage;
int m_value;
@@ -181,6 +186,7 @@ private:
MyCustomVariantType m_custom;
int m_propertyWithNotify;
QJSValue m_qjsvalue;
+ int m_childAddedEventCount;
};
QML_DECLARE_TYPE(MyQmlObject)
QML_DECLARE_TYPEINFO(MyQmlObject, QML_HAS_ATTACHED_PROPERTIES)
@@ -230,6 +236,7 @@ class MyTypeObject : public QObject
Q_PROPERTY(MyMirroredEnum mirroredEnumProperty READ mirroredEnumProperty WRITE setMirroredEnumProperty NOTIFY mirroredEnumPropertyChanged)
Q_PROPERTY(MyEnumContainer::RelatedEnum relatedEnumProperty READ relatedEnumProperty WRITE setRelatedEnumProperty)
Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringPropertyChanged)
+ Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty NOTIFY byteArrayPropertyChanged)
Q_PROPERTY(uint uintProperty READ uintProperty WRITE setUintProperty NOTIFY uintPropertyChanged)
Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intPropertyChanged)
Q_PROPERTY(qreal realProperty READ realProperty WRITE setRealProperty NOTIFY realPropertyChanged)
@@ -351,6 +358,15 @@ public:
emit stringPropertyChanged();
}
+ QByteArray byteArrayPropertyValue;
+ QByteArray byteArrayProperty() const {
+ return byteArrayPropertyValue;
+ }
+ void setByteArrayProperty(const QByteArray &v) {
+ byteArrayPropertyValue = v;
+ emit byteArrayPropertyChanged();
+ }
+
uint uintPropertyValue;
uint uintProperty() const {
return uintPropertyValue;
@@ -564,6 +580,7 @@ signals:
void qtEnumPropertyChanged();
void mirroredEnumPropertyChanged();
void stringPropertyChanged();
+ void byteArrayPropertyChanged();
void uintPropertyChanged();
void intPropertyChanged();
void realPropertyChanged();
@@ -722,15 +739,15 @@ class MyCustomParserType : public QObject
class MyCustomParserTypeParser : public QQmlCustomParser
{
public:
- QByteArray compile(const QV4::CompiledData::QmlUnit *, int, const QList<const QV4::CompiledData::Binding *> &) { return QByteArray(); }
- void setCustomData(QObject *, const QByteArray &) {}
+ QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) { return QByteArray(); }
+ void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {}
};
class EnumSupportingCustomParser : public QQmlCustomParser
{
public:
- QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings);
- void setCustomData(QObject *, const QByteArray &) {}
+ QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
+ void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {}
};
class MyParserStatus : public QObject, public QQmlParserStatus
@@ -1100,8 +1117,52 @@ public:
class CustomBindingParser : public QQmlCustomParser
{
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings);
- virtual void setCustomData(QObject *object, const QByteArray &data);
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
+ virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *);
+};
+
+class SimpleObjectWithCustomParser : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
+public:
+ SimpleObjectWithCustomParser()
+ : m_intProperty(0)
+ , m_customBindingsCount(0)
+ {}
+
+ int intProperty() const { return m_intProperty; }
+ void setIntProperty(int value) { m_intProperty = value; }
+
+ void setCustomBindingsCount(int count) { m_customBindingsCount = count; }
+ int customBindingsCount() const { return m_customBindingsCount; }
+
+private:
+ int m_intProperty;
+ int m_customBindingsCount;
+};
+
+class SimpleObjectCustomParser : public QQmlCustomParser
+{
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings);
+ virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *);
+};
+
+class RootObjectInCreationTester : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *subObject READ subObject WRITE setSubObject FINAL)
+ Q_CLASSINFO("DeferredPropertyNames", "subObject");
+public:
+ RootObjectInCreationTester()
+ : obj(0)
+ {}
+
+ QObject *subObject() const { return obj; }
+ void setSubObject(QObject *o) { obj = o; }
+
+private:
+ QObject *obj;
};
void registerTypes();
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index cf43352c40..be417df325 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -65,6 +65,17 @@
DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
+static inline bool isCaseSensitiveFileSystem(const QString &path) {
+ Q_UNUSED(path)
+#if defined(Q_OS_MAC)
+ return pathconf(path.toLatin1().constData(), _PC_CASE_SENSITIVE);
+#elif defined(Q_OS_WIN)
+ return false;
+#else
+ return true;
+#endif
+}
+
/*
This test case covers QML language issues. This covers everything that does not
involve evaluating ECMAScript expressions and bindings.
@@ -99,6 +110,7 @@ private slots:
void assignLiteralToVariant();
void assignLiteralToVar();
void assignLiteralToJSValue();
+ void assignNullStrings();
void bindJSValueToVar();
void bindJSValueToVariant();
void bindJSValueToType();
@@ -218,10 +230,15 @@ private slots:
void customParserBindingScopes();
void customParserEvaluateEnum();
+ void customParserProperties();
void preservePropertyCacheOnGroupObjects();
void propertyCacheInSync();
+ void rootObjectInCreationNotForSubObjects();
+
+ void noChildEvents();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -328,6 +345,7 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("nonexistantProperty.4") << "nonexistantProperty.4.qml" << "nonexistantProperty.4.errors.txt" << false;
QTest::newRow("nonexistantProperty.5") << "nonexistantProperty.5.qml" << "nonexistantProperty.5.errors.txt" << false;
QTest::newRow("nonexistantProperty.6") << "nonexistantProperty.6.qml" << "nonexistantProperty.6.errors.txt" << false;
+ QTest::newRow("nonexistantProperty.7") << "nonexistantProperty.7.qml" << "nonexistantProperty.7.errors.txt" << false;
QTest::newRow("wrongType (string for int)") << "wrongType.1.qml" << "wrongType.1.errors.txt" << false;
QTest::newRow("wrongType (int for bool)") << "wrongType.2.qml" << "wrongType.2.errors.txt" << false;
@@ -493,13 +511,11 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("notAvailable") << "notAvailable.qml" << "notAvailable.errors.txt" << false;
QTest::newRow("singularProperty") << "singularProperty.qml" << "singularProperty.errors.txt" << false;
QTest::newRow("singularProperty.2") << "singularProperty.2.qml" << "singularProperty.2.errors.txt" << false;
- QTest::newRow("incorrectCase") << "incorrectCase.qml"
-#if defined(Q_OS_MAC) || defined(Q_OS_WIN32)
- << "incorrectCase.errors.insensitive.txt"
-#else
- << "incorrectCase.errors.sensitive.txt"
-#endif
- << false;
+
+ const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ?
+ QStringLiteral("incorrectCase.errors.sensitive.txt") :
+ QStringLiteral("incorrectCase.errors.insensitive.txt");
+ QTest::newRow("incorrectCase") << "incorrectCase.qml" << expectedError << false;
QTest::newRow("metaobjectRevision.1") << "metaobjectRevision.1.qml" << "metaobjectRevision.1.errors.txt" << false;
QTest::newRow("metaobjectRevision.2") << "metaobjectRevision.2.qml" << "metaobjectRevision.2.errors.txt" << false;
@@ -859,6 +875,19 @@ void tst_qqmllanguage::assignLiteralToJSValue()
}
}
+void tst_qqmllanguage::assignNullStrings()
+{
+ QQmlComponent component(&engine, testFileUrl("assignNullStrings.qml"));
+ VERIFY_ERRORS(0);
+ MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QVERIFY(object != 0);
+ QVERIFY(object->stringProperty().isNull());
+ QVERIFY(object->byteArrayProperty().isNull());
+ QMetaObject::invokeMethod(object, "assignNullStringsFromJs", Qt::DirectConnection);
+ QVERIFY(object->stringProperty().isNull());
+ QVERIFY(object->byteArrayProperty().isNull());
+}
+
void tst_qqmllanguage::bindJSValueToVar()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
@@ -1175,12 +1204,17 @@ void tst_qqmllanguage::idProperty()
VERIFY_ERRORS(0);
MyContainer *object = qobject_cast<MyContainer *>(component.create());
QVERIFY(object != 0);
- QCOMPARE(object->getChildren()->count(), 1);
+ QCOMPARE(object->getChildren()->count(), 2);
MyTypeObject *child =
qobject_cast<MyTypeObject *>(object->getChildren()->at(0));
QVERIFY(child != 0);
QCOMPARE(child->id(), QString("myObjectId"));
QCOMPARE(object->property("object"), QVariant::fromValue((QObject *)child));
+
+ child =
+ qobject_cast<MyTypeObject *>(object->getChildren()->at(1));
+ QVERIFY(child != 0);
+ QCOMPARE(child->id(), QString("name.with.dots"));
}
// Tests automatic connection to notify signals if "onBlahChanged" syntax is used
@@ -1874,6 +1908,28 @@ void tst_qqmllanguage::scriptString()
QVERIFY(object != 0);
QCOMPARE(object->scriptProperty().isUndefinedLiteral(), true);
}
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptString7.qml"));
+ VERIFY_ERRORS(0);
+
+ MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QVERIFY(object != 0);
+ QQmlScriptString ss = object->scriptProperty();
+
+ {
+ QQmlExpression expr(ss, /*context*/0, object);
+ QCOMPARE(expr.evaluate().toInt(), int(100));
+ }
+
+ {
+ SimpleObjectWithCustomParser testScope;
+ QVERIFY(testScope.metaObject()->indexOfProperty("intProperty") != object->metaObject()->indexOfProperty("intProperty"));
+
+ testScope.setIntProperty(42);
+ QQmlExpression expr(ss, /*context*/0, &testScope);
+ QCOMPARE(expr.evaluate().toInt(), int(42));
+ }
+ }
}
// Check that default property assignments are correctly spliced into explicit
@@ -2208,6 +2264,11 @@ void tst_qqmllanguage::importsLocal_data()
"Test {}"
<< (!qmlCheckTypes()?"TestType":"")
<< (!qmlCheckTypes()?"":"Test is ambiguous. Found in org/qtproject/Test/ and in subdir/");
+ QTest::newRow("file URL survives percent-encoding")
+ << "import \"" + QUrl::fromLocalFile(QDir::currentPath() + "/{subdir}").toString() + "\"\n"
+ "Test {}"
+ << "QQuickRectangle"
+ << "";
}
void tst_qqmllanguage::importsLocal()
@@ -2574,12 +2635,9 @@ void tst_qqmllanguage::importIncorrectCase()
QList<QQmlError> errors = component.errors();
QCOMPARE(errors.count(), 1);
-#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
- QString expectedError = QLatin1String("File name case mismatch");
-#else
- QString expectedError = QLatin1String("File not found");
-#endif
-
+ const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ?
+ QStringLiteral("File not found") :
+ QStringLiteral("File name case mismatch");
QCOMPARE(errors.at(0).description(), expectedError);
engine.setImportPathList(defaultImportPathList);
@@ -3591,6 +3649,20 @@ void tst_qqmllanguage::customParserEvaluateEnum()
QVERIFY(!o.isNull());
}
+void tst_qqmllanguage::customParserProperties()
+{
+ QQmlComponent component(&engine, testFile("customParserProperties.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ SimpleObjectWithCustomParser *testObject = qobject_cast<SimpleObjectWithCustomParser*>(o.data());
+ QVERIFY(testObject);
+ QCOMPARE(testObject->customBindingsCount(), 0);
+ QCOMPARE(testObject->intProperty(), 42);
+ QCOMPARE(testObject->property("qmlString").toString(), QStringLiteral("Hello"));
+ QVERIFY(!testObject->property("someObject").isNull());
+}
+
void tst_qqmllanguage::preservePropertyCacheOnGroupObjects()
{
QQmlComponent component(&engine, testFile("preservePropertyCacheOnGroupObjects.qml"));
@@ -3630,6 +3702,41 @@ void tst_qqmllanguage::propertyCacheInSync()
QCOMPARE(anchors->property("margins").toInt(), 50);
}
+void tst_qqmllanguage::rootObjectInCreationNotForSubObjects()
+{
+ QQmlComponent component(&engine, testFile("rootObjectInCreationNotForSubObjects.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+
+ // QQmlComponent should have set this back to false anyway
+ QQmlData *ddata = QQmlData::get(o.data());
+ QVERIFY(!ddata->rootObjectInCreation);
+
+ QObject *subObject = qvariant_cast<QObject*>(o->property("subObject"));
+ QVERIFY(!subObject);
+
+ qmlExecuteDeferred(o.data());
+
+ subObject = qvariant_cast<QObject*>(o->property("subObject"));
+ QVERIFY(subObject);
+
+ ddata = QQmlData::get(subObject);
+ // This should never have been set in the first place as there is no
+ // QQmlComponent to set it back to false.
+ QVERIFY(!ddata->rootObjectInCreation);
+}
+
+void tst_qqmllanguage::noChildEvents()
+{
+ QQmlComponent component(&engine);
+ component.setData("import QtQml 2.0; import Test 1.0; MyQmlObject { property QtObject child: QtObject {} }", QUrl());
+ VERIFY_ERRORS(0);
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->childAddedEventCount(), 0);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index bdc0646b8e..9b57eeffa9 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -101,6 +101,8 @@ private slots:
void static_types_data();
void static_i18n();
void static_i18n_data();
+ void dynamic_i18n();
+ void dynamic_i18n_data();
void static_nestedElements();
void static_nestedElements_data();
void dynamic_data();
@@ -296,17 +298,17 @@ void tst_qqmllistmodel::static_i18n_data()
QTest::newRow("QT_TR_NOOP extra param")
<< QString::fromUtf8("ListElement { foo: QT_TR_NOOP(\"hello\",\"world\") }")
<< QVariant(QString())
- << QString("ListElement: improperly specified QT_TR_NOOP");
+ << QString("ListElement: cannot use script for property value");
QTest::newRow("QT_TRANSLATE_NOOP missing params")
<< "ListElement { foo: QT_TRANSLATE_NOOP() }"
<< QVariant(QString())
- << QString("ListElement: improperly specified QT_TRANSLATE_NOOP");
+ << QString("ListElement: cannot use script for property value");
QTest::newRow("QT_TRID_NOOP missing param")
<< QString::fromUtf8("ListElement { foo: QT_TRID_NOOP() }")
<< QVariant(QString())
- << QString("ListElement: improperly specified QT_TRID_NOOP");
+ << QString("ListElement: cannot use script for property value");
}
void tst_qqmllistmodel::static_i18n()
@@ -341,6 +343,54 @@ void tst_qqmllistmodel::static_i18n()
delete obj;
}
+void tst_qqmllistmodel::dynamic_i18n_data()
+{
+ QTest::addColumn<QString>("qml");
+ QTest::addColumn<QVariant>("value");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("qsTr")
+ << QString::fromUtf8("ListElement { foo: qsTr(\"test\") }")
+ << QVariant(QString::fromUtf8("test"))
+ << QString("ListElement: cannot use script for property value");
+
+ QTest::newRow("qsTrId")
+ << "ListElement { foo: qsTrId(\"qtn_test\") }"
+ << QVariant(QString("qtn_test"))
+ << QString("ListElement: cannot use script for property value");
+}
+
+void tst_qqmllistmodel::dynamic_i18n()
+{
+ QFETCH(QString, qml);
+ QFETCH(QVariant, value);
+ QFETCH(QString, error);
+
+ qml = "import QtQuick 2.0\nItem { property variant test: model.get(0).foo; ListModel { id: model; " + qml + " } }";
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(qml.toUtf8(),
+ QUrl::fromLocalFile(QString("dummy.qml")));
+
+ if (!error.isEmpty()) {
+ QVERIFY(component.isError());
+ QCOMPARE(component.errors().at(0).description(), error);
+ return;
+ }
+
+ QVERIFY(!component.isError());
+
+ QObject *obj = component.create();
+ QVERIFY(obj != 0);
+
+ QVariant actual = obj->property("test");
+
+ QCOMPARE(actual, value);
+ QCOMPARE(actual.toString(), value.toString());
+
+ delete obj;
+}
void tst_qqmllistmodel::static_nestedElements()
{
QFETCH(int, elementCount);
@@ -528,6 +578,8 @@ void tst_qqmllistmodel::dynamic_data()
QTest::newRow("nested-count") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]}); get(0).bars.count}" << 3 << "" << dr;
QTest::newRow("nested-clear") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]}); get(0).bars.clear(); get(0).bars.count}" << 0 << "" << dr;
}
+
+ QTest::newRow("jsarray") << "{append({'foo':['1', '2', '3']});get(0).foo.get(0)}" << 0 << "" << false;
}
void tst_qqmllistmodel::dynamic()
diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
index 0eb38d92e6..9653cac988 100644
--- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
+++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
@@ -932,7 +932,6 @@ void tst_qqmllocale::dateFromLocaleString_data()
void tst_qqmllocale::dateFromLocaleString()
{
- QSKIP("Needs fixes in our date time parser");
QFETCH(QString, locale);
QFETCH(QString, format);
@@ -977,7 +976,6 @@ void tst_qqmllocale::dateFromLocaleDateString_data()
void tst_qqmllocale::dateFromLocaleDateString()
{
- QSKIP("Needs fixes in our date time parser");
QFETCH(QString, locale);
QFETCH(QString, format);
@@ -1022,7 +1020,6 @@ void tst_qqmllocale::dateFromLocaleTimeString_data()
void tst_qqmllocale::dateFromLocaleTimeString()
{
- QSKIP("Needs fixes in our date time parser");
QFETCH(QString, locale);
QFETCH(QString, format);
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml b/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml
index f44f4f926c..b35c31d513 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml
@@ -8,7 +8,7 @@ Item {
SequentialAnimation {
id: anim
- PauseAnimation { duration: 525 } // delay mode is 500 msec.
+ PauseAnimation { duration: 1000 } // delay mode is 500 msec.
ScriptAction { script: loadcomponent(0) }
PauseAnimation { duration: 525 } // delay mode is 500 msec.
ScriptAction { script: loadcomponent(1) }
diff --git a/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro b/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro
index f1fbfde0ec..fcfdf23d33 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro
+++ b/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro
@@ -2,8 +2,6 @@ CONFIG += testcase
TARGET = tst_qqmlxmlhttprequest
macx:CONFIG -= app_bundle
-CONFIG+=insignificant_test # QTQAINFRA-573
-
INCLUDEPATH += ../../shared/
HEADERS += ../../shared/testhttpserver.h
diff --git a/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test1.html b/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test1.html
new file mode 100644
index 0000000000..4da4639310
--- /dev/null
+++ b/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test1.html
@@ -0,0 +1 @@
+<P>This file contains some HTML.</P>
diff --git a/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test2.html b/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test2.html
new file mode 100644
index 0000000000..4da4639310
--- /dev/null
+++ b/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test2.html
@@ -0,0 +1 @@
+<P>This file contains some HTML.</P>
diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
index a6e6345223..4296ae4f09 100644
--- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
+++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
@@ -73,6 +73,7 @@ private slots:
void basicProperties();
void showFiles();
void resetFiltering();
+ void nameFilters();
void refresh();
void cdUp();
#ifdef Q_OS_WIN32
@@ -169,26 +170,50 @@ void tst_qquickfolderlistmodel::resetFiltering()
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
QVERIFY(flm != 0);
+ flm->setProperty("folder", testFileUrl("resetfiltering"));
+ // _q_directoryUpdated may be triggered if model was empty before, but there won't be a rowsRemoved signal
+ QTRY_COMPARE(flm->property("count").toInt(),3); // all files visible
+
+ flm->setProperty("folder", testFileUrl("resetfiltering/innerdir"));
+ // _q_directoryChanged is triggered so it's a total model refresh
+ QTRY_COMPARE(flm->property("count").toInt(),1); // should just be "test2.txt" visible
+
+ flm->setProperty("folder", testFileUrl("resetfiltering"));
+ // _q_directoryChanged is triggered so it's a total model refresh
+ QTRY_COMPARE(flm->property("count").toInt(),3); // all files visible
+}
+
+void tst_qquickfolderlistmodel::nameFilters()
+{
+ // see QTBUG-36576
+ QQmlComponent component(&engine, testFileUrl("resetFiltering.qml"));
+ checkNoErrors(component);
+
+ QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
+ QVERIFY(flm != 0);
+
connect(flm, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(removed(QModelIndex,int,int)));
+ QTRY_VERIFY(flm->rowCount() > 0);
flm->setProperty("folder", testFileUrl("resetfiltering"));
- QTRY_COMPARE(flm->property("count").toInt(),1); // should just be "test.txt" visible
+ QTRY_COMPARE(flm->property("count").toInt(),3); // all files visible
+
int count = flm->rowCount();
+ flm->setProperty("nameFilters", QStringList() << "*.txt");
+ // _q_directoryUpdated triggered with range 0:1
+ QTRY_COMPARE(flm->property("count").toInt(),1);
+ QCOMPARE(flm->data(flm->index(0),FileNameRole), QVariant("test.txt"));
QCOMPARE(removeStart, 0);
QCOMPARE(removeEnd, count-1);
- flm->setProperty("folder", testFileUrl("resetfiltering/innerdir"));
- QTRY_COMPARE(flm->property("count").toInt(),1); // should just be "test2.txt" visible
- count = flm->rowCount();
- QCOMPARE(removeStart, 0);
- QCOMPARE(removeEnd, count-1);
+ flm->setProperty("nameFilters", QStringList() << "*.html");
+ QTRY_COMPARE(flm->property("count").toInt(),2);
+ QCOMPARE(flm->data(flm->index(0),FileNameRole), QVariant("test1.html"));
+ QCOMPARE(flm->data(flm->index(1),FileNameRole), QVariant("test2.html"));
- flm->setProperty("folder", testFileUrl("resetfiltering"));
- QTRY_COMPARE(flm->property("count").toInt(),1); // should just be "test.txt" visible
- count = flm->rowCount();
- QCOMPARE(removeStart, 0);
- QCOMPARE(removeEnd, count-1);
+ flm->setProperty("nameFilters", QStringList());
+ QTRY_COMPARE(flm->property("count").toInt(),3); // all files visible
}
void tst_qquickfolderlistmodel::refresh()
diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
index 15a6acc272..b7e5cf48e0 100644
--- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
@@ -48,6 +48,9 @@
using namespace QV4;
using namespace QV4::Debugging;
+typedef QV4::ReturnedValue (*InjectedFunction)(QV4::CallContext*);
+Q_DECLARE_METATYPE(InjectedFunction)
+
static bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000)
{
QEventLoop loop;
@@ -80,9 +83,7 @@ public:
QV4::ExecutionEngine *v4Engine() { return QV8Engine::getV4(this); }
- typedef QV4::ReturnedValue (*InjectedFunction)(QV4::CallContext*);
-
- Q_INVOKABLE void injectFunction(const QString &functionName, TestEngine::InjectedFunction injectedFunction)
+ Q_INVOKABLE void injectFunction(const QString &functionName, InjectedFunction injectedFunction)
{
QV4::ExecutionEngine *v4 = v4Engine();
QV4::Scope scope(v4);
@@ -96,7 +97,6 @@ signals:
void evaluateFinished();
};
-Q_DECLARE_METATYPE(TestEngine::InjectedFunction)
namespace {
class TestCollector: public QV4::Debugging::Debugger::Collector
@@ -404,7 +404,7 @@ void tst_qv4debugger::removeBreakPointForNextInstruction()
"var i = 42;";
QMetaObject::invokeMethod(m_engine, "injectFunction", Qt::BlockingQueuedConnection,
- Q_ARG(QString, "someCall"), Q_ARG(TestEngine::InjectedFunction, someCall));
+ Q_ARG(QString, "someCall"), Q_ARG(InjectedFunction, someCall));
m_debuggerAgent->addBreakPoint("removeBreakPointForNextInstruction", 2);
diff --git a/tests/auto/qmldevtools/compile/tst_compile.cpp b/tests/auto/qmldevtools/compile/tst_compile.cpp
index 6b13d1b4bb..31b5c02250 100644
--- a/tests/auto/qmldevtools/compile/tst_compile.cpp
+++ b/tests/auto/qmldevtools/compile/tst_compile.cpp
@@ -44,6 +44,10 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmlirbuilder_p.h>
+#include <private/qv4value_inl_p.h>
+#include <private/qv4codegen_p.h>
+#include <private/qqmldirparser_p.h>
int main()
{
diff --git a/tests/auto/qmltest/animators/tst_mixed.qml b/tests/auto/qmltest/animators/tst_mixed.qml
new file mode 100644
index 0000000000..1eb0cf019f
--- /dev/null
+++ b/tests/auto/qmltest/animators/tst_mixed.qml
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtTest 1.0
+
+Item {
+ id: root;
+ width: 200
+ height: 200
+
+ TestCase {
+ id: testCase
+ name: "animators-mixed"
+ when: !rootAnimation.running
+ function test_endresult() {
+ compare(box.rootStart, 2);
+ compare(box.rootEnd, 2);
+
+ compare(parallelWithOneSequential.before, 4);
+ compare(parallelWithOneSequential.scaleUpdates, 4);
+
+ compare(parallelWithTwoSequentialNormalEndsLast.beforeAnimator, 4);
+ compare(parallelWithTwoSequentialNormalEndsLast.scaleUpdates, 4);
+ compare(parallelWithTwoSequentialNormalEndsLast.afterAnimator, 4);
+ compare(parallelWithTwoSequentialNormalEndsLast.beforePause, 4);
+ compare(parallelWithTwoSequentialNormalEndsLast.afterPause, 4);
+
+ compare(parallelWithTwoSequentialNormalEndsFirst.beforeAnimator, 4);
+ compare(parallelWithTwoSequentialNormalEndsFirst.scaleUpdates, 4);
+ compare(parallelWithTwoSequentialNormalEndsFirst.afterAnimator, 4);
+ compare(parallelWithTwoSequentialNormalEndsFirst.beforePause, 4);
+ compare(parallelWithTwoSequentialNormalEndsFirst.afterPause, 4);
+
+ }
+ }
+
+ Box {
+ id: box
+
+ property int rootStart : 0
+ property int rootEnd : 0;
+
+ SequentialAnimation {
+ id: rootAnimation
+
+ running: true
+ loops: 2
+
+ ScriptAction { script: box.rootStart++; }
+
+ ParallelAnimation {
+ id: parallelWithOneSequential
+ property int before : 0;
+ property int scaleUpdates : 0;
+ loops: 2
+ SequentialAnimation {
+ ScriptAction { script: {
+ parallelWithOneSequential.before++;
+ box.scale = 1;
+ box.scaleChangeCounter = 0;
+ }
+ }
+ ScaleAnimator { target: box; from: 1; to: 2; duration: 100; }
+ ScriptAction { script: {
+ parallelWithOneSequential.scaleUpdates += box.scaleChangeCounter;
+ }
+ }
+ }
+ }
+
+ ParallelAnimation {
+ id: parallelWithTwoSequentialNormalEndsLast
+ property int beforeAnimator : 0;
+ property int scaleUpdates : 0;
+ property int afterAnimator : 0;
+ property int beforePause : 0;
+ property int afterPause : 0;
+ loops: 2
+ SequentialAnimation {
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsLast.beforeAnimator++;
+ box.scale = 1;
+ box.scaleChangeCounter = 0;
+ }
+ }
+ ScaleAnimator { target: box; from: 1; to: 2; duration: 100; }
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsLast.scaleUpdates += box.scaleChangeCounter;
+ parallelWithTwoSequentialNormalEndsLast.afterAnimator++;
+ }
+ }
+ }
+ SequentialAnimation {
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsLast.beforePause++
+ }
+ }
+ PauseAnimation { duration: 200 }
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsLast.afterPause++
+ }
+ }
+ }
+ }
+
+ ParallelAnimation {
+ id: parallelWithTwoSequentialNormalEndsFirst
+ property int beforeAnimator : 0;
+ property int scaleUpdates : 0;
+ property int afterAnimator : 0;
+ property int beforePause : 0;
+ property int afterPause : 0;
+ loops: 2
+ SequentialAnimation {
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsFirst.beforeAnimator++;
+ box.scale = 1;
+ box.scaleChangeCounter = 0;
+ }
+ }
+ ScaleAnimator { target: box; from: 1; to: 2; duration: 200; }
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsFirst.scaleUpdates += box.scaleChangeCounter;
+ parallelWithTwoSequentialNormalEndsFirst.afterAnimator++;
+ }
+ }
+ }
+ SequentialAnimation {
+ ScriptAction { script: parallelWithTwoSequentialNormalEndsFirst.beforePause++ }
+ PauseAnimation { duration: 100 }
+ ScriptAction { script: parallelWithTwoSequentialNormalEndsFirst.afterPause++ }
+ }
+ }
+
+ ScriptAction { script: box.rootEnd++; }
+ }
+
+ }
+
+}
diff --git a/tests/auto/qmltest/animators/tst_on.qml b/tests/auto/qmltest/animators/tst_on.qml
index 7930dc5be3..b3fc719dcc 100644
--- a/tests/auto/qmltest/animators/tst_on.qml
+++ b/tests/auto/qmltest/animators/tst_on.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -54,7 +54,7 @@ Item {
&& !anims.running && !animr.running
&& !animo.running;
function test_endresult() {
- compare(box.xChangeCounter, 1);
+ tryCompare(box, 'xChangeCounter', 1);
compare(box.yChangeCounter, 1);
compare(box.scaleChangeCounter, 1);
compare(box.rotationChangeCounter, 1);
diff --git a/tests/auto/qmltest/listview/tst_listview.qml b/tests/auto/qmltest/listview/tst_listview.qml
index 0589e7c46b..03be57909f 100644
--- a/tests/auto/qmltest/listview/tst_listview.qml
+++ b/tests/auto/qmltest/listview/tst_listview.qml
@@ -102,6 +102,23 @@ Item {
}
}
+ ListView {
+ id: listViewDelegateModelAfterCreate
+ anchors.fill: parent
+ property int createdDelegates: 0
+ }
+
+ Component {
+ id: delegateModelAfterCreateComponent
+ Rectangle {
+ width: 140
+ height: 140
+ border.color: "black"
+ color: "red"
+ Component.onCompleted: listViewDelegateModelAfterCreate.createdDelegates++;
+ }
+ }
+
ListModel { id: emptymodel }
ListModel { id: manyitems }
ListModel { id: firstmodel; ListElement { name: "FirstModelElement0" } }
@@ -249,5 +266,11 @@ Item {
asyncListViewLoaderView.currentIndex = 4;
}
}
+
+ function test_set_delegate_model_after_list_creation() {
+ listViewDelegateModelAfterCreate.delegate = delegateModelAfterCreateComponent;
+ listViewDelegateModelAfterCreate.model = 40;
+ verify(listViewDelegateModelAfterCreate.createdDelegates > 0);
+ }
}
}
diff --git a/tests/auto/qmltest/pathview/tst_pathview.qml b/tests/auto/qmltest/pathview/tst_pathview.qml
new file mode 100644
index 0000000000..820034c960
--- /dev/null
+++ b/tests/auto/qmltest/pathview/tst_pathview.qml
@@ -0,0 +1,35 @@
+import QtQuick 2.1
+import QtTest 1.0
+
+Item {
+ id: top
+
+ PathView {
+ id: pathViewDelegateModelAfterCreate
+ anchors.fill: parent
+ property int createdDelegates: 0
+ path: Path { startX: 120; startY: 100 }
+ }
+
+ Component {
+ id: delegateModelAfterCreateComponent
+ Rectangle {
+ width: 140
+ height: 140
+ border.color: "black"
+ color: "red"
+ Component.onCompleted: pathViewDelegateModelAfterCreate.createdDelegates++;
+ }
+ }
+
+ TestCase {
+ name: "PathView"
+ when: windowShown
+
+ function test_set_delegate_model_after_path_creation() {
+ pathViewDelegateModelAfterCreate.delegate = delegateModelAfterCreateComponent;
+ pathViewDelegateModelAfterCreate.model = 40;
+ verify(pathViewDelegateModelAfterCreate.createdDelegates > 0);
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
index 54eb3509bd..7d50e130f2 100644
--- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
+++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
@@ -131,6 +131,8 @@ void tst_QQuickAccessible::initTestCase()
QQmlDataTest::initTestCase();
QTestAccessibility::initialize();
QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration();
+ if (!pfIntegration->accessibility())
+ QSKIP("This platform does not support accessibility");
pfIntegration->accessibility()->setActive(true);
}
diff --git a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
index e299147b36..70682bed0b 100644
--- a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
@@ -16,7 +16,6 @@ TestCase {
if (type === "2d")
return [
{ tag:"image threaded", properties:{width:100, height:100, renderTarget:Canvas.Image, renderStrategy:Canvas.Threaded}},
- { tag:"image canvas invisible", properties:{visible: false, width:100, height:100, renderTarget:Canvas.Image, renderStrategy:Canvas.Threaded}},
// { tag:"image cooperative", properties:{width:100, height:100, renderTarget:Canvas.Image, renderStrategy:Canvas.Cooperative}},
{ tag:"image immediate", properties:{width:100, height:100, renderTarget:Canvas.Image, renderStrategy:Canvas.Immediate}},
// { tag:"fbo cooperative", properties:{width:100, height:100, renderTarget:Canvas.FramebufferObject, renderStrategy:Canvas.Cooperative}},
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
index b92f6354a5..d90eb3971e 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
@@ -180,20 +180,28 @@ CanvasTestCase {
tryCompare(c, "availableChangedCount", 1);
//scene graph could be available immediately
//in this case, we force waiting a short while until the init paint finished
- if (c.visible) {
- tryCompare(c, "paintedCount", 1);
- } else {
- tryCompare(c, "paintedCount", 0);
- }
+ tryCompare(c, "paintedCount", 1);
ctx.fillRect(0, 0, c.width, c.height);
c.toDataURL();
- if (c.visible) {
- tryCompare(c, "paintCount", 1);
- tryCompare(c, "paintedCount", 2);
- } else {
- tryCompare(c, "paintCount", 0);
- tryCompare(c, "paintedCount", 1);
- }
+ tryCompare(c, "paintedCount", 2);
+ tryCompare(c, "paintCount", 1);
+ // implicit repaint when visible and resized
+ testCase.visible = true;
+ c.width += 1;
+ c.height += 1;
+ tryCompare(c, "paintCount", 2);
+ tryCompare(c, "paintedCount", 2);
+ // allow explicit repaint even when hidden
+ testCase.visible = false;
+ c.requestPaint();
+ tryCompare(c, "paintCount", 3);
+ tryCompare(c, "paintedCount", 2);
+ // no implicit repaint when resized but hidden
+ c.width += 1;
+ c.height += 1;
+ waitForRendering(c);
+ compare(c.paintCount, 3);
+ tryCompare(c, "paintedCount", 2);
c.destroy();
}
function test_loadImage(row) {
diff --git a/tests/auto/quick/qquickgridview/data/boundZValues.qml b/tests/auto/quick/qquickgridview/data/boundZValues.qml
new file mode 100644
index 0000000000..7a1ca48a81
--- /dev/null
+++ b/tests/auto/quick/qquickgridview/data/boundZValues.qml
@@ -0,0 +1,46 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+
+ GridView {
+ id: grid
+
+ property real itemZ: 342
+ property real headerZ: 341
+ property real footerZ: 340
+ property real highlightZ: 339
+
+ anchors.fill: parent
+ objectName: "grid"
+ model: ListModel { ListElement { text: "text" } }
+ currentIndex: 0
+
+ delegate: Text {
+ objectName: "wrapper"
+ font.pointSize: 20
+ text: index
+ z: grid.itemZ
+ }
+
+ header: Rectangle {
+ width: 240
+ height: 30
+ z: grid.headerZ
+ }
+
+ footer: Rectangle {
+ width: 240
+ height: 30
+ z: grid.footerZ
+ }
+
+ highlight: Rectangle {
+ width: 240
+ height: 30
+ z: grid.highlightZ
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickgridview/data/constantZValues.qml b/tests/auto/quick/qquickgridview/data/constantZValues.qml
new file mode 100644
index 0000000000..7cf564a12e
--- /dev/null
+++ b/tests/auto/quick/qquickgridview/data/constantZValues.qml
@@ -0,0 +1,46 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+
+ GridView {
+ id: grid
+
+ property real itemZ: 241
+ property real headerZ: 242
+ property real footerZ: 243
+ property real highlightZ: 244
+
+ anchors.fill: parent
+ objectName: "grid"
+ model: ListModel { ListElement { text: "text" } }
+ currentIndex: 0
+
+ delegate: Text {
+ objectName: "wrapper"
+ font.pointSize: 20
+ text: index
+ z: 241
+ }
+
+ header: Rectangle {
+ width: 240
+ height: 30
+ z: 242
+ }
+
+ footer: Rectangle {
+ width: 240
+ height: 30
+ z: 243
+ }
+
+ highlight: Rectangle {
+ width: 240
+ height: 30
+ z: 244
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickgridview/data/initialZValues.qml b/tests/auto/quick/qquickgridview/data/defaultZValues.qml
index 9768b2c695..53f11bb2da 100644
--- a/tests/auto/quick/qquickgridview/data/initialZValues.qml
+++ b/tests/auto/quick/qquickgridview/data/defaultZValues.qml
@@ -7,11 +7,15 @@ Rectangle {
GridView {
id: grid
- property real initialZ: 342
+ property real itemZ: 1
+ property real headerZ: 1
+ property real footerZ: 1
+ property real highlightZ: 0
anchors.fill: parent
objectName: "grid"
- model: ListModel {}
+ model: ListModel { ListElement { text: "text" } }
+ currentIndex: 0
delegate: Text {
objectName: "wrapper"
@@ -22,13 +26,11 @@ Rectangle {
header: Rectangle {
width: 240
height: 30
- z: grid.initialZ
}
footer: Rectangle {
width: 240
height: 30
- z: grid.initialZ
}
}
}
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
index f4eec18690..890174e2a8 100644
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
@@ -121,6 +121,7 @@ private slots:
void footer();
void footer_data();
void initialZValues();
+ void initialZValues_data();
void header();
void header_data();
void extents();
@@ -3200,8 +3201,9 @@ void tst_QQuickGridView::footer_data()
void tst_QQuickGridView::initialZValues()
{
+ QFETCH(QString, fileName);
QQuickView *window = createView();
- window->setSource(testFileUrl("initialZValues.qml"));
+ window->setSource(testFileUrl(fileName));
qApp->processEvents();
QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
@@ -3209,15 +3211,29 @@ void tst_QQuickGridView::initialZValues()
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != 0);
+ QVERIFY(gridview->currentItem());
+ QTRY_COMPARE(gridview->currentItem()->z(), gridview->property("itemZ").toReal());
+
QVERIFY(gridview->headerItem());
- QTRY_COMPARE(gridview->headerItem()->z(), gridview->property("initialZ").toReal());
+ QTRY_COMPARE(gridview->headerItem()->z(), gridview->property("headerZ").toReal());
QVERIFY(gridview->footerItem());
- QTRY_COMPARE(gridview->footerItem()->z(), gridview->property("initialZ").toReal());
+ QTRY_COMPARE(gridview->footerItem()->z(), gridview->property("footerZ").toReal());
+
+ QVERIFY(gridview->highlightItem());
+ QTRY_COMPARE(gridview->highlightItem()->z(), gridview->property("highlightZ").toReal());
delete window;
}
+void tst_QQuickGridView::initialZValues_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::newRow("defaults") << "defaultZValues.qml";
+ QTest::newRow("constants") << "constantZValues.qml";
+ QTest::newRow("bindings") << "boundZValues.qml";
+}
+
void tst_QQuickGridView::header()
{
QFETCH(QQuickGridView::Flow, flow);
diff --git a/tests/auto/quick/qquickimage/data/heart-highdpi@2x.png b/tests/auto/quick/qquickimage/data/heart-highdpi@2x.png
new file mode 100644
index 0000000000..abe97fee4b
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/heart-highdpi@2x.png
Binary files differ
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index b73dcdfcde..7951cb07cf 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -105,6 +105,7 @@ private slots:
void progressAndStatusChanges();
void sourceSizeChanges();
void correctStatus();
+ void highdpi();
private:
QQmlEngine engine;
@@ -307,6 +308,10 @@ void tst_qquickimage::mirror()
qreal height = 250;
foreach (QQuickImage::FillMode fillMode, fillModes) {
+#if defined(Q_OS_BLACKBERRY)
+ QWindow dummy; // On BlackBerry first window is always full screen,
+ dummy.showFullScreen(); // so make test window a second window.
+#endif
QQuickView *window = new QQuickView;
window->setSource(testFileUrl("mirror.qml"));
@@ -315,7 +320,7 @@ void tst_qquickimage::mirror()
obj->setFillMode(fillMode);
obj->setProperty("mirror", true);
- window->show();
+ window->showNormal();
QVERIFY(QTest::qWaitForWindowExposed(window));
QImage screenshot = window->grabWindow();
@@ -928,6 +933,49 @@ void tst_qquickimage::correctStatus()
delete obj;
}
+void tst_qquickimage::highdpi()
+{
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
+ server.serveDirectory(dataDirectory());
+
+ QString componentStr = "import QtQuick 2.0\nImage { source: srcImage ; }";
+ QQmlComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QQmlContext *ctxt = engine.rootContext();
+
+ // Testing "@2x" high-dpi image loading:
+ // The basic case is as follows. Suppose you have foo.png,
+ // which is a 64x64 png that fits in a QML layout. Now,
+ // on a high-dpi system that pixmap would not provide
+ // enough pixels. To fix this the app developer provides
+ // a 128x128 foo@2x.png, which Qt automatically loads.
+ // The image continues to be referred to as "foo.png" in
+ // the QML sources, and reports a size of 64x64.
+ //
+
+ // Load "heart-highdpi@2x.png", which is a 300x300 png. As a 2x scale image it
+ // should render and report a geometry of 150x150.
+ ctxt->setContextProperty("srcImage", testFileUrl("heart-highdpi@2x.png"));
+
+ QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ QCOMPARE(obj->width(), 150.0);
+ QCOMPARE(obj->height(), 150.0);
+ QCOMPARE(obj->paintedWidth(), 150.0);
+ QCOMPARE(obj->paintedHeight(), 150.0);
+
+ // Load a normal 1x image.
+ ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
+ QCOMPARE(obj->width(), 300.0);
+ QCOMPARE(obj->height(), 300.0);
+ QCOMPARE(obj->paintedWidth(), 300.0);
+ QCOMPARE(obj->paintedHeight(), 300.0);
+
+ delete obj;
+}
+
QTEST_MAIN(tst_qquickimage)
#include "tst_qquickimage.moc"
diff --git a/tests/auto/quick/qquickitem/data/visualParentOwnershipWindow.qml b/tests/auto/quick/qquickitem/data/visualParentOwnershipWindow.qml
new file mode 100644
index 0000000000..30fc844d7a
--- /dev/null
+++ b/tests/auto/quick/qquickitem/data/visualParentOwnershipWindow.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import QtQuick.Window 2.1
+
+Window {
+ Component {
+ id: factory
+ Item {}
+ }
+
+ property Item keepAliveProperty;
+
+ function createItemWithoutParent() {
+ return factory.createObject(/*parent*/ null);
+ }
+}
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index 8db515432a..40327b0666 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -170,6 +170,7 @@ private slots:
void acceptedMouseButtons();
void visualParentOwnership();
+ void visualParentOwnershipWindow();
private:
@@ -1189,8 +1190,9 @@ static inline QByteArray msgItem(const QQuickItem *item)
void tst_qquickitem::mouseGrab()
{
-#if defined(Q_OS_WIN) && defined(QT_OPENGL_ES_2)
- QSKIP("Fails in the CI for ANGLE builds on Windows, QTBUG-32664");
+#ifdef Q_OS_WIN
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES)
+ QSKIP("Fails in the CI for ANGLE builds on Windows, QTBUG-32664");
#endif
QQuickWindow window;
window.setFramePosition(QPoint(100, 100));
@@ -1824,6 +1826,63 @@ void tst_qquickitem::visualParentOwnership()
}
}
+void tst_qquickitem::visualParentOwnershipWindow()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("visualParentOwnershipWindow.qml"));
+
+ QQuickWindow *window = qobject_cast<QQuickWindow*>(component.create());
+ QVERIFY(window);
+ QQuickItem *root = window->contentItem();
+
+ QVariant newObject;
+ {
+ QVERIFY(QMetaObject::invokeMethod(window, "createItemWithoutParent", Q_RETURN_ARG(QVariant, newObject)));
+ QPointer<QQuickItem> newItem = qvariant_cast<QQuickItem*>(newObject);
+ QVERIFY(!newItem.isNull());
+
+ QVERIFY(!newItem->parent());
+ QVERIFY(!newItem->parentItem());
+
+ newItem->setParentItem(root);
+
+ gc(engine);
+
+ QVERIFY(!newItem.isNull());
+ newItem->setParentItem(0);
+
+ gc(engine);
+ QVERIFY(newItem.isNull());
+ }
+ {
+ QVERIFY(QMetaObject::invokeMethod(window, "createItemWithoutParent", Q_RETURN_ARG(QVariant, newObject)));
+ QPointer<QQuickItem> firstItem = qvariant_cast<QQuickItem*>(newObject);
+ QVERIFY(!firstItem.isNull());
+
+ firstItem->setParentItem(root);
+
+ QVERIFY(QMetaObject::invokeMethod(window, "createItemWithoutParent", Q_RETURN_ARG(QVariant, newObject)));
+ QPointer<QQuickItem> secondItem = qvariant_cast<QQuickItem*>(newObject);
+ QVERIFY(!firstItem.isNull());
+
+ secondItem->setParentItem(firstItem);
+
+ gc(engine);
+
+ delete firstItem;
+
+ window->setProperty("keepAliveProperty", newObject);
+
+ gc(engine);
+ QVERIFY(!secondItem.isNull());
+
+ window->setProperty("keepAliveProperty", QVariant());
+
+ gc(engine);
+ QVERIFY(secondItem.isNull());
+ }
+}
+
QTEST_MAIN(tst_qquickitem)
#include "tst_qquickitem.moc"
diff --git a/tests/auto/quick/qquickitem2/data/activeFocusOnTab9.qml b/tests/auto/quick/qquickitem2/data/activeFocusOnTab9.qml
new file mode 100644
index 0000000000..09bb73639a
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/activeFocusOnTab9.qml
@@ -0,0 +1,50 @@
+import QtQuick 2.1
+
+Item {
+ id: main
+ objectName: "main"
+ width: 300
+ height: 300
+ TextInput {
+ id: textinput1
+ objectName: "textinput1"
+ width: 300
+ height: 75
+ activeFocusOnTab: true
+ text: "Text Input 1"
+ anchors.top: parent.top
+ anchors.left: parent.left
+ }
+ TextInput {
+ id: textinput2
+ objectName: "textinput2"
+ width: 300
+ height: 75
+ activeFocusOnTab: true
+ text: "Text Input 2"
+ readOnly: true
+ anchors.top: textinput1.bottom
+ anchors.left: parent.left
+ }
+ TextEdit {
+ id: textedit1
+ objectName: "textedit1"
+ width: 300
+ height: 75
+ activeFocusOnTab: true
+ text: "Text Edit 1"
+ anchors.top: textinput2.bottom
+ anchors.left: parent.left
+ }
+ TextEdit {
+ id: textedit2
+ objectName: "textedit2"
+ width: 300
+ height: 75
+ activeFocusOnTab: true
+ text: "Text Edit 2"
+ readOnly: true
+ anchors.top: textedit1.bottom
+ anchors.left: parent.left
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/keysforward.qml b/tests/auto/quick/qquickitem2/data/keysforward.qml
new file mode 100644
index 0000000000..f0cb4d9508
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/keysforward.qml
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property alias source: source
+ property alias primaryTarget: primaryTarget
+ property alias secondaryTarget: secondaryTarget
+
+ property var pressedKeys: []
+ property var releasedKeys: []
+ Keys.onPressed: { var keys = pressedKeys; keys.push(event.key); pressedKeys = keys }
+ Keys.onReleased: { var keys = releasedKeys; keys.push(event.key); releasedKeys = keys }
+
+ Item {
+ id: primaryTarget
+ objectName: "primary"
+ property var pressedKeys: []
+ property var releasedKeys: []
+ Keys.forwardTo: secondaryTarget
+ Keys.onPressed: { event.accepted = event.key === Qt.Key_P; var keys = pressedKeys; keys.push(event.key); pressedKeys = keys }
+ Keys.onReleased: { event.accepted = event.key === Qt.Key_P; var keys = releasedKeys; keys.push(event.key); releasedKeys = keys }
+
+ Item {
+ id: source
+ objectName: "source"
+ property var pressedKeys: []
+ property var releasedKeys: []
+ Keys.forwardTo: primaryTarget
+ Keys.onPressed: { var keys = pressedKeys; keys.push(event.key); pressedKeys = keys }
+ Keys.onReleased: { var keys = releasedKeys; keys.push(event.key); releasedKeys = keys }
+ }
+ }
+
+ Item {
+ id: secondaryTarget
+ objectName: "secondary"
+ property var pressedKeys: []
+ property var releasedKeys: []
+ Keys.onPressed: { event.accepted = event.key === Qt.Key_S; var keys = pressedKeys; keys.push(event.key); pressedKeys = keys }
+ Keys.onReleased: { event.accepted = event.key === Qt.Key_S; var keys = releasedKeys; keys.push(event.key); releasedKeys = keys }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 10f4aa2c83..9d2188253a 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -73,6 +73,8 @@ private slots:
void activeFocusOnTab6();
void activeFocusOnTab7();
void activeFocusOnTab8();
+ void activeFocusOnTab9();
+ void activeFocusOnTab10();
void nextItemInFocusChain();
void nextItemInFocusChain2();
@@ -83,6 +85,7 @@ private slots:
void standardKeys();
void keysProcessingOrder();
void keysim();
+ void keysForward();
void keyNavigation_data();
void keyNavigation();
void keyNavigation_RightToLeft();
@@ -856,6 +859,140 @@ void tst_QQuickItem::activeFocusOnTab8()
delete window;
}
+void tst_QQuickItem::activeFocusOnTab9()
+{
+ if (qt_tab_all_widgets())
+ QSKIP("This function doesn't support iterating all.");
+
+ QQuickView *window = new QQuickView(0);
+ window->setBaseSize(QSize(300,300));
+
+ window->setSource(testFileUrl("activeFocusOnTab9.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QVERIFY(QGuiApplication::focusWindow() == window);
+
+ QQuickItem *content = window->contentItem();
+ QVERIFY(content);
+ QVERIFY(content->hasActiveFocus());
+
+ QQuickItem *textinput1 = findItem<QQuickItem>(window->rootObject(), "textinput1");
+ QVERIFY(textinput1);
+ QQuickItem *textedit1 = findItem<QQuickItem>(window->rootObject(), "textedit1");
+ QVERIFY(textedit1);
+
+ QVERIFY(!textinput1->hasActiveFocus());
+ textinput1->forceActiveFocus();
+ QVERIFY(textinput1->hasActiveFocus());
+
+ // Tab: textinput1->textedit1
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textedit1->hasActiveFocus());
+
+ // BackTab: textedit1->textinput1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textinput1->hasActiveFocus());
+
+ // BackTab: textinput1->textedit1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textedit1->hasActiveFocus());
+
+ delete window;
+}
+
+void tst_QQuickItem::activeFocusOnTab10()
+{
+ if (!qt_tab_all_widgets())
+ QSKIP("This function doesn't support NOT iterating all.");
+
+ QQuickView *window = new QQuickView(0);
+ window->setBaseSize(QSize(300,300));
+
+ window->setSource(testFileUrl("activeFocusOnTab9.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QVERIFY(QGuiApplication::focusWindow() == window);
+
+ QQuickItem *content = window->contentItem();
+ QVERIFY(content);
+ QVERIFY(content->hasActiveFocus());
+
+ QQuickItem *textinput1 = findItem<QQuickItem>(window->rootObject(), "textinput1");
+ QVERIFY(textinput1);
+ QQuickItem *textedit1 = findItem<QQuickItem>(window->rootObject(), "textedit1");
+ QVERIFY(textedit1);
+ QQuickItem *textinput2 = findItem<QQuickItem>(window->rootObject(), "textinput2");
+ QVERIFY(textinput2);
+ QQuickItem *textedit2 = findItem<QQuickItem>(window->rootObject(), "textedit2");
+ QVERIFY(textedit2);
+
+ QVERIFY(!textinput1->hasActiveFocus());
+ textinput1->forceActiveFocus();
+ QVERIFY(textinput1->hasActiveFocus());
+
+ // Tab: textinput1->textinput2
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textinput2->hasActiveFocus());
+
+ // Tab: textinput2->textedit1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textedit1->hasActiveFocus());
+
+ // BackTab: textedit1->textinput2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textinput2->hasActiveFocus());
+
+ // BackTab: textinput2->textinput1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textinput1->hasActiveFocus());
+
+ // BackTab: textinput1->textedit2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textedit2->hasActiveFocus());
+
+ // BackTab: textedit2->textedit1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textedit1->hasActiveFocus());
+
+ // BackTab: textedit1->textinput2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ QVERIFY(textinput2->hasActiveFocus());
+
+ delete window;
+}
+
void tst_QQuickItem::nextItemInFocusChain()
{
if (!qt_tab_all_widgets())
@@ -1268,6 +1405,78 @@ void tst_QQuickItem::keysim()
delete window;
}
+void tst_QQuickItem::keysForward()
+{
+ QQuickView window;
+ window.setBaseSize(QSize(240,320));
+
+ window.setSource(testFileUrl("keysforward.qml"));
+ window.show();
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+ QVERIFY(QGuiApplication::focusWindow() == &window);
+
+ QQuickItem *rootItem = qobject_cast<QQuickItem *>(window.rootObject());
+ QVERIFY(rootItem);
+ QQuickItem *sourceItem = rootItem->property("source").value<QQuickItem *>();
+ QVERIFY(sourceItem);
+ QQuickItem *primaryTarget = rootItem->property("primaryTarget").value<QQuickItem *>();
+ QVERIFY(primaryTarget);
+ QQuickItem *secondaryTarget = rootItem->property("secondaryTarget").value<QQuickItem *>();
+ QVERIFY(secondaryTarget);
+
+ // primary target accepts/consumes Key_P
+ QKeyEvent pressKeyP(QEvent::KeyPress, Qt::Key_P, Qt::NoModifier, "P");
+ QCoreApplication::sendEvent(sourceItem, &pressKeyP);
+ QCOMPARE(rootItem->property("pressedKeys").toList(), QVariantList());
+ QCOMPARE(sourceItem->property("pressedKeys").toList(), QVariantList());
+ QCOMPARE(primaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P);
+ QCOMPARE(secondaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P);
+ QVERIFY(pressKeyP.isAccepted());
+
+ QKeyEvent releaseKeyP(QEvent::KeyRelease, Qt::Key_P, Qt::NoModifier, "P");
+ QCoreApplication::sendEvent(sourceItem, &releaseKeyP);
+ QCOMPARE(rootItem->property("releasedKeys").toList(), QVariantList());
+ QCOMPARE(sourceItem->property("releasedKeys").toList(), QVariantList());
+ QCOMPARE(primaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P);
+ QCOMPARE(secondaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P);
+ QVERIFY(releaseKeyP.isAccepted());
+
+ // secondary target accepts/consumes Key_S
+ QKeyEvent pressKeyS(QEvent::KeyPress, Qt::Key_S, Qt::NoModifier, "S");
+ QCoreApplication::sendEvent(sourceItem, &pressKeyS);
+ QCOMPARE(rootItem->property("pressedKeys").toList(), QVariantList());
+ QCOMPARE(sourceItem->property("pressedKeys").toList(), QVariantList());
+ QCOMPARE(primaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P);
+ QCOMPARE(secondaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_S);
+ QVERIFY(pressKeyS.isAccepted());
+
+ QKeyEvent releaseKeyS(QEvent::KeyRelease, Qt::Key_S, Qt::NoModifier, "S");
+ QCoreApplication::sendEvent(sourceItem, &releaseKeyS);
+ QCOMPARE(rootItem->property("releasedKeys").toList(), QVariantList());
+ QCOMPARE(sourceItem->property("releasedKeys").toList(), QVariantList());
+ QCOMPARE(primaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P);
+ QCOMPARE(secondaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_S);
+ QVERIFY(releaseKeyS.isAccepted());
+
+ // neither target accepts/consumes Key_Q
+ QKeyEvent pressKeyQ(QEvent::KeyPress, Qt::Key_Q, Qt::NoModifier, "Q");
+ QCoreApplication::sendEvent(sourceItem, &pressKeyQ);
+ QCOMPARE(rootItem->property("pressedKeys").toList(), QVariantList());
+ QCOMPARE(sourceItem->property("pressedKeys").toList(), QVariantList() << Qt::Key_Q);
+ QCOMPARE(primaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_Q);
+ QCOMPARE(secondaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_S << Qt::Key_Q);
+ QVERIFY(!pressKeyQ.isAccepted());
+
+ QKeyEvent releaseKeyQ(QEvent::KeyRelease, Qt::Key_Q, Qt::NoModifier, "Q");
+ QCoreApplication::sendEvent(sourceItem, &releaseKeyQ);
+ QCOMPARE(rootItem->property("releasedKeys").toList(), QVariantList());
+ QCOMPARE(sourceItem->property("releasedKeys").toList(), QVariantList() << Qt::Key_Q);
+ QCOMPARE(primaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_Q);
+ QCOMPARE(secondaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_S << Qt::Key_Q);
+ QVERIFY(!releaseKeyQ.isAccepted());
+}
+
QQuickItemPrivate *childPrivate(QQuickItem *rootItem, const char * itemString)
{
QQuickItem *item = findItem<QQuickItem>(rootItem, QString(QLatin1String(itemString)));
diff --git a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
index 4f103bd1fa..b5980929a6 100644
--- a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
+++ b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
@@ -55,10 +55,14 @@ public:
QImage runTest(const QString &fileName)
{
+#if defined(Q_OS_BLACKBERRY)
+ QWindow dummy; // On BlackBerry first window is always full screen,
+ dummy.showFullScreen(); // so make test window a second window.
+#endif
QQuickView view;
view.setSource(testFileUrl(fileName));
- view.show();
+ view.showNormal();
QTest::qWaitForWindowExposed(&view);
return view.grabWindow();
diff --git a/tests/auto/quick/qquicklistview/data/boundZValues.qml b/tests/auto/quick/qquicklistview/data/boundZValues.qml
new file mode 100644
index 0000000000..10810e540d
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/boundZValues.qml
@@ -0,0 +1,55 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+
+ ListView {
+ id: list
+
+ property real itemZ: 342
+ property real headerZ: 341
+ property real footerZ: 340
+ property real highlightZ: 339
+ property real sectionZ: 338
+
+ anchors.fill: parent
+ objectName: "list"
+ model: ListModel { ListElement { text: "text" } }
+ currentIndex: 0
+
+ delegate: Text {
+ objectName: "wrapper"
+ font.pointSize: 20
+ text: index
+ z: list.itemZ
+ }
+
+ header: Rectangle {
+ width: 240
+ height: 30
+ z: list.headerZ
+ }
+
+ footer: Rectangle {
+ width: 240
+ height: 30
+ z: list.footerZ
+ }
+
+ highlight: Rectangle {
+ width: 240
+ height: 30
+ z: list.highlightZ
+ }
+
+ section.property: "text"
+ section.delegate: Text {
+ objectName: "section"
+ font.pointSize: 20
+ text: section
+ z: list.sectionZ
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquicklistview/data/constantZValues.qml b/tests/auto/quick/qquicklistview/data/constantZValues.qml
new file mode 100644
index 0000000000..48917fed4f
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/constantZValues.qml
@@ -0,0 +1,55 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+
+ ListView {
+ id: list
+
+ property real itemZ: 241
+ property real headerZ: 242
+ property real footerZ: 243
+ property real highlightZ: 244
+ property real sectionZ: 245
+
+ anchors.fill: parent
+ objectName: "list"
+ model: ListModel { ListElement { text: "text" } }
+ currentIndex: 0
+
+ delegate: Text {
+ objectName: "wrapper"
+ font.pointSize: 20
+ text: index
+ z: 241
+ }
+
+ header: Rectangle {
+ width: 240
+ height: 30
+ z: 242
+ }
+
+ footer: Rectangle {
+ width: 240
+ height: 30
+ z: 243
+ }
+
+ highlight: Rectangle {
+ width: 240
+ height: 30
+ z: 244
+ }
+
+ section.property: "text"
+ section.delegate: Text {
+ objectName: "section"
+ font.pointSize: 20
+ text: section
+ z: 245
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquicklistview/data/defaultZValues.qml b/tests/auto/quick/qquicklistview/data/defaultZValues.qml
new file mode 100644
index 0000000000..7326340ae4
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/defaultZValues.qml
@@ -0,0 +1,49 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+
+ ListView {
+ id: list
+
+ property real itemZ: 1
+ property real headerZ: 1
+ property real footerZ: 1
+ property real highlightZ: 0
+ property real sectionZ: 2
+
+ anchors.fill: parent
+ objectName: "list"
+ model: ListModel { ListElement { text: "text" } }
+ currentIndex: 0
+
+ delegate: Text {
+ objectName: "wrapper"
+ font.pointSize: 20
+ text: index
+ }
+
+ header: Rectangle {
+ width: 240
+ height: 30
+ }
+
+ footer: Rectangle {
+ width: 240
+ height: 30
+ }
+
+ highlight: Rectangle {
+ width: 240
+ height: 30
+ }
+
+ section.property: "text"
+ section.delegate: Text {
+ objectName: "section"
+ font.pointSize: 20
+ text: section
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/initialZValues.qml b/tests/auto/quick/qquicklistview/data/initialZValues.qml
deleted file mode 100644
index 3a8e78debb..0000000000
--- a/tests/auto/quick/qquicklistview/data/initialZValues.qml
+++ /dev/null
@@ -1,35 +0,0 @@
-import QtQuick 2.0
-
-Rectangle {
- width: 240
- height: 320
-
- ListView {
- id: list
-
- property real initialZ: 342
-
- anchors.fill: parent
- objectName: "list"
- model: ListModel {}
-
- delegate: Text {
- objectName: "wrapper"
- font.pointSize: 20
- text: index
- }
-
- header: Rectangle {
- width: 240
- height: 30
- z: list.initialZ
- }
-
- footer: Rectangle {
- width: 240
- height: 30
- z: list.initialZ
- }
- }
-}
-
diff --git a/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml b/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml
index 7903c392d1..c57cde5eda 100644
--- a/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml
+++ b/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml
@@ -42,13 +42,16 @@ import QtQuick 2.1
import QtTest 1.0
Item {
+ width: 300
+ height: 542
+
function resizeThirdItem(size) {
resizingListModel.setProperty(3, "size", size)
}
ListView {
- width: 300
- height: 542
+ id: list
+ anchors.fill: parent
model: ListModel {
id: resizingListModel
ListElement { size: 300; }
@@ -62,6 +65,9 @@ Item {
width: parent.width
color: index % 2 == 0 ? "red" : "blue"
height: size
+ Text { anchors.centerIn: parent; text: index }
}
}
+
+ Text { text: list.contentY; color: "white" }
}
diff --git a/tests/auto/quick/qquicklistview/data/roundingErrors.qml b/tests/auto/quick/qquicklistview/data/roundingErrors.qml
new file mode 100644
index 0000000000..aebdce04c3
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/roundingErrors.qml
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import QtQml.Models 2.1
+
+ListView {
+ id: listview
+
+ width: 600
+ height: 200
+
+ spacing: 8
+ orientation: ListView.Horizontal
+
+ Component.onCompleted: {
+ var colors = ["blue", "green", "red", "yellow", "orange", "purple", "cyan",
+ "magenta", "chartreuse", "aquamarine", "indigo", "lightsteelblue",
+ "violet", "grey", "springgreen", "salmon", "blanchedalmond",
+ "forestgreen", "pink", "navy", "goldenrod", "crimson", "teal" ]
+ for (var i = 0; i < 100; ++i)
+ colorModel.append( { nid: i, color: colors[i%colors.length] } )
+ }
+
+ model: DelegateModel {
+ id: visualModel
+
+ model: ListModel {
+ id: colorModel
+ }
+
+ delegate: MouseArea {
+ id: delegateRoot
+ objectName: model.nid
+
+ width: 107.35
+ height: 63.35
+
+ drag.target: icon
+
+ Rectangle{
+ id: icon
+ width: delegateRoot.width
+ height: delegateRoot.height
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ color: model.color
+
+ Drag.active: delegateRoot.drag.active
+ Drag.source: delegateRoot
+ Drag.hotSpot.x: 36
+ Drag.hotSpot.y: 36
+
+ Text {
+ id: text
+ anchors.fill: parent
+ font.pointSize: 40
+ text: model.nid
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ }
+
+ states: [
+ State {
+ when: icon.Drag.active
+ ParentChange {
+ target: icon
+ parent: delegateRoot.ListView.view
+ }
+
+ AnchorChanges {
+ target: icon
+ anchors.horizontalCenter: undefined
+ anchors.verticalCenter: undefined
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ DropArea {
+ anchors.fill: parent
+ onPositionChanged: {
+ var to = listview.indexAt(drag.x + listview.contentX, 0)
+ if (to !== -1) {
+ var from = drag.source.DelegateModel.itemsIndex
+ if (from !== to)
+ visualModel.items.move(from, to)
+ drag.accept()
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/qquicklistview.pro b/tests/auto/quick/qquicklistview/qquicklistview.pro
index 4ac47679da..2ae04d32fe 100644
--- a/tests/auto/quick/qquicklistview/qquicklistview.pro
+++ b/tests/auto/quick/qquicklistview/qquicklistview.pro
@@ -17,4 +17,3 @@ TESTDATA = data/*
QT += core-private gui-private qml-private quick-private testlib
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
-mac:CONFIG += insignificant_test # QTBUG-27740
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index efd0fa8103..29755e3890 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -147,6 +147,7 @@ private slots:
void modelChanges();
void manualHighlight();
void initialZValues();
+ void initialZValues_data();
void header();
void header_data();
void header_delayItemCreation();
@@ -223,6 +224,9 @@ private slots:
void QTBUG_36481();
void QTBUG_35920();
+ void roundingErrors();
+ void roundingErrors_data();
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -3346,9 +3350,9 @@ void tst_QQuickListView::modelChanges()
void tst_QQuickListView::QTBUG_9791()
{
QQuickView *window = createView();
-
window->setSource(testFileUrl("strictlyenforcerange.qml"));
- qApp->processEvents();
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject());
QTRY_VERIFY(listview != 0);
@@ -3465,8 +3469,9 @@ void tst_QQuickListView::QTBUG_11105()
void tst_QQuickListView::initialZValues()
{
+ QFETCH(QString, fileName);
QQuickView *window = createView();
- window->setSource(testFileUrl("initialZValues.qml"));
+ window->setSource(testFileUrl(fileName));
qApp->processEvents();
QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
@@ -3474,15 +3479,33 @@ void tst_QQuickListView::initialZValues()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != 0);
+ QVERIFY(listview->currentItem());
+ QTRY_COMPARE(listview->currentItem()->z(), listview->property("itemZ").toReal());
+
QVERIFY(listview->headerItem());
- QTRY_COMPARE(listview->headerItem()->z(), listview->property("initialZ").toReal());
+ QTRY_COMPARE(listview->headerItem()->z(), listview->property("headerZ").toReal());
QVERIFY(listview->footerItem());
- QTRY_COMPARE(listview->footerItem()->z(), listview->property("initialZ").toReal());
+ QTRY_COMPARE(listview->footerItem()->z(), listview->property("footerZ").toReal());
+
+ QVERIFY(listview->highlightItem());
+ QTRY_COMPARE(listview->highlightItem()->z(), listview->property("highlightZ").toReal());
+
+ QQuickText *sectionItem = 0;
+ QTRY_VERIFY(sectionItem = findItem<QQuickText>(contentItem, "section"));
+ QTRY_COMPARE(sectionItem->z(), listview->property("sectionZ").toReal());
delete window;
}
+void tst_QQuickListView::initialZValues_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::newRow("defaults") << "defaultZValues.qml";
+ QTest::newRow("constants") << "constantZValues.qml";
+ QTest::newRow("bindings") << "boundZValues.qml";
+}
+
void tst_QQuickListView::header()
{
QFETCH(QQuickListView::Orientation, orientation);
@@ -7027,9 +7050,7 @@ void tst_QQuickListView::outsideViewportChangeNotAffectingView()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
- flick(window, QPoint(20, 200), QPoint(20, 20), 10);
-
- QTRY_COMPARE(listview->isFlicking(), false);
+ listview->setContentY(1250);
QTRY_COMPARE(listview->indexAt(0, listview->contentY()), 4);
QTRY_COMPARE(listview->itemAt(0, listview->contentY())->y(), 1200.);
@@ -7127,12 +7148,12 @@ void tst_QQuickListView::displayMargin()
void tst_QQuickListView::highlightItemGeometryChanges()
{
- QQmlEngine engine;
- QQmlComponent component(&engine, testFileUrl("HighlightResize.qml"));
-
- QScopedPointer<QObject> object(component.create());
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("HighlightResize.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- QQuickListView *listview = qobject_cast<QQuickListView *>(object.data());
+ QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject());
QVERIFY(listview);
QCOMPARE(listview->count(), 5);
@@ -7183,6 +7204,63 @@ void tst_QQuickListView::QTBUG_35920()
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(10,100));
}
+void tst_QQuickListView::roundingErrors()
+{
+ QFETCH(bool, pixelAligned);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("roundingErrors.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject());
+ QVERIFY(listview);
+ listview->setPixelAligned(pixelAligned);
+ listview->positionViewAtIndex(20, QQuickListView::Beginning);
+
+ QQuickItem *content = listview->contentItem();
+ QVERIFY(content);
+
+ const QPoint viewPos(150, 36);
+ const QPointF contentPos = content->mapFromItem(listview, viewPos);
+
+ QPointer<QQuickItem> item = listview->itemAt(contentPos.x(), contentPos.y());
+ QVERIFY(item);
+
+ // QTBUG-37339: drag an item and verify that it doesn't
+ // get prematurely released due to rounding errors
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, viewPos);
+ for (int i = 0; i < 150; i += 5) {
+ QTest::mouseMove(window.data(), viewPos - QPoint(i, 0));
+ QVERIFY(item);
+ }
+ QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(0, 36));
+
+ // maintain position relative to the right edge
+ listview->setLayoutDirection(Qt::RightToLeft);
+ const qreal contentX = listview->contentX();
+ listview->setContentX(contentX + 0.2);
+ QCOMPARE(listview->contentX(), pixelAligned ? qRound(contentX + 0.2) : contentX + 0.2);
+ listview->setWidth(listview->width() - 0.2);
+ QCOMPARE(listview->contentX(), pixelAligned ? qRound(contentX + 0.2) : contentX + 0.2);
+
+ // maintain position relative to the bottom edge
+ listview->setOrientation(QQuickListView::Vertical);
+ listview->setVerticalLayoutDirection(QQuickListView::BottomToTop);
+ const qreal contentY = listview->contentY();
+ listview->setContentY(contentY + 0.2);
+ QCOMPARE(listview->contentY(), pixelAligned ? qRound(contentY + 0.2) : contentY + 0.2);
+ listview->setHeight(listview->height() - 0.2);
+ QCOMPARE(listview->contentY(), pixelAligned ? qRound(contentY + 0.2) : contentY + 0.2);
+}
+
+void tst_QQuickListView::roundingErrors_data()
+{
+ QTest::addColumn<bool>("pixelAligned");
+ QTest::newRow("pixelAligned=true") << true;
+ QTest::newRow("pixelAligned=false") << false;
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"
diff --git a/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp b/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp
index 650ce09dfa..7642583bb1 100644
--- a/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp
+++ b/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp
@@ -61,6 +61,7 @@ private slots:
void behavior();
void deleteOnUpdate();
void zeroDuration();
+ void noStart();
private:
QQmlEngine engine;
@@ -263,6 +264,27 @@ void tst_qquicksmoothedanimation::zeroDuration()
delete rect;
}
+//verify that an empty SmoothedAnimation does not fire up the animation system
+//and keep it running forever
+void tst_qquicksmoothedanimation::noStart()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("smoothedanimation1.qml"));
+ QQuickSmoothedAnimation *obj = qobject_cast<QQuickSmoothedAnimation*>(c.create());
+
+ QVERIFY(obj != 0);
+
+ obj->start();
+ QCOMPARE(obj->isRunning(), false);
+ QTest::qWait(100);
+ QCOMPARE(obj->isRunning(), false);
+ //this could fail if the test is being run in parallel with other tests
+ //or if an earlier test failed and didn't clean up (left an animation running)
+ //QCOMPARE(QUnifiedTimer::instance()->runningAnimationCount(), 0);
+
+ delete obj;
+}
+
QTEST_MAIN(tst_qquicksmoothedanimation)
#include "tst_qquicksmoothedanimation.moc"
diff --git a/tests/auto/quick/qquickstates/data/QTBUG-38492.qml b/tests/auto/quick/qquickstates/data/QTBUG-38492.qml
new file mode 100644
index 0000000000..d6d6d81fd3
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/QTBUG-38492.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property string text;
+
+ states: [
+ State {
+ name: 'apply'
+ PropertyChanges {
+ target: root
+ text: qsTr("Test")
+ }
+ }
+ ]
+}
diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
index 0c9b75636f..6b46ab1fae 100644
--- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp
+++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
@@ -148,6 +148,7 @@ private slots:
void QTBUG_14830();
void avoidFastForward();
void revertListBug();
+ void QTBUG_38492();
};
void tst_qquickstates::initTestCase()
@@ -1626,6 +1627,21 @@ void tst_qquickstates::revertListBug()
QCOMPARE(rect2->parentItem(), origParent2); //QTBUG-22583 causes rect2's parent item to be origParent1
}
+void tst_qquickstates::QTBUG_38492()
+{
+ QQmlEngine engine;
+
+ QQmlComponent rectComponent(&engine, testFileUrl("QTBUG-38492.qml"));
+ QQuickItem *item = qobject_cast<QQuickItem*>(rectComponent.create());
+ QVERIFY(item != 0);
+
+ QQuickItemPrivate::get(item)->setState("apply");
+
+ QCOMPARE(item->property("text").toString(), QString("Test"));
+
+ delete item;
+}
+
QTEST_MAIN(tst_qquickstates)
#include "tst_qquickstates.moc"
diff --git a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
index a2e05ba883..be46f362d6 100644
--- a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
+++ b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
@@ -126,26 +126,26 @@ void tst_qquickstyledtext::textOutput_data()
QTest::newRow("paragraph closed") << "text<p>more text</p>more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false;
QTest::newRow("paragraph closed bold") << "<b>text<p>more text</p>more text</b>" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << (FormatList() << Format(Format::Bold, 0, 24)) << false;
QTest::newRow("unknown tag") << "<a href='#'><foo>underline</foo></a> not" << "underline not" << (FormatList() << Format(Format::Underline, 0, 9)) << false;
- QTest::newRow("ordered list") << "<ol><li>one<li>two" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false;
- QTest::newRow("ordered list closed") << "<ol><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list alpha") << "<ol type=\"a\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("a.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("b.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list upper alpha") << "<ol type=\"A\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("A.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("B.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list roman") << "<ol type=\"i\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("i.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("ii.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list upper roman") << "<ol type=\"I\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("I.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("II.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list bad") << "<ol type=\"z\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("unordered list") << "<ul><li>one<li>two" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false;
- QTest::newRow("unordered list closed") << "<ul><li>one</li><li>two</li></ul>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("unordered list disc") << "<ul type=\"disc\"><li>one</li><li>two</li></ul>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("unordered list square") << "<ul type=\"square\"><li>one</li><li>two</li></ul>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("unordered list bad") << "<ul type=\"bad\"><li>one</li><li>two</li></ul>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("header close") << "<h1>head</h1>more" << QChar(QChar::LineSeparator) + QLatin1String("head") + QChar(QChar::LineSeparator) + QLatin1String("more") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
+ QTest::newRow("ordered list") << "<ol><li>one<li>two" << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false;
+ QTest::newRow("ordered list closed") << "<ol><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list alpha") << "<ol type=\"a\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("a.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("b.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list upper alpha") << "<ol type=\"A\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("A.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("B.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list roman") << "<ol type=\"i\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("i.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("ii.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list upper roman") << "<ol type=\"I\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("I.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("II.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list bad") << "<ol type=\"z\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("unordered list") << "<ul><li>one<li>two" << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false;
+ QTest::newRow("unordered list closed") << "<ul><li>one</li><li>two</li></ul>" << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("unordered list disc") << "<ul type=\"disc\"><li>one</li><li>two</li></ul>" << QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("unordered list square") << "<ul type=\"square\"><li>one</li><li>two</li></ul>" << QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("unordered list bad") << "<ul type=\"bad\"><li>one</li><li>two</li></ul>" << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("header close") << "<h1>head</h1>more" << QLatin1String("head") + QChar(QChar::LineSeparator) + QLatin1String("more") << (FormatList() << Format(Format::Bold, 0, 4)) << true;
QTest::newRow("h0") << "<h0>head" << "head" << FormatList() << false;
- QTest::newRow("h1") << "<h1>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h2") << "<h2>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h3") << "<h3>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h4") << "<h4>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h5") << "<h5>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h6") << "<h6>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
+ QTest::newRow("h1") << "<h1>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h2") << "<h2>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h3") << "<h3>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h4") << "<h4>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h5") << "<h5>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h6") << "<h6>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
QTest::newRow("h7") << "<h7>head" << "head" << FormatList() << false;
QTest::newRow("pre") << "normal<pre>pre text</pre>normal" << QLatin1String("normal") + QChar(QChar::LineSeparator) + QLatin1String("pre") + QChar(QChar::Nbsp) + QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("normal") << (FormatList() << Format(0, 6, 9)) << false;
QTest::newRow("pre lb") << "normal<pre>pre\n text</pre>normal" << QLatin1String("normal") + QChar(QChar::LineSeparator) + QLatin1String("pre") + QChar(QChar::LineSeparator) + QChar(QChar::Nbsp) + QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("normal") << (FormatList() << Format(0, 6, 10)) << false;
@@ -155,7 +155,7 @@ void tst_qquickstyledtext::textOutput_data()
QTest::newRow("consecutive whitespace") << " consecutive \t \n whitespace" << "consecutive whitespace" << FormatList() << false;
QTest::newRow("space after newline") << "text<br/> more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false;
QTest::newRow("space after paragraph") << "text<p> more text</p> more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false;
- QTest::newRow("space in header") << "<h1> head</h1> " << QChar(QChar::LineSeparator) + QLatin1String("head") + QChar(QChar::LineSeparator) << (FormatList() << Format(Format::Bold, 0, 5)) << true;
+ QTest::newRow("space in header") << "<h1> head</h1> " << QLatin1String("head") + QChar(QChar::LineSeparator) << (FormatList() << Format(Format::Bold, 0, 4)) << true;
QTest::newRow("space before bold") << "this is <b>bold</b>" << "this is bold" << (FormatList() << Format(Format::Bold, 8, 4)) << false;
QTest::newRow("space leading bold") << "this is<b> bold</b>" << "this is bold" << (FormatList() << Format(Format::Bold, 7, 5)) << false;
QTest::newRow("space trailing bold") << "this is <b>bold </b>" << "this is bold " << (FormatList() << Format(Format::Bold, 8, 5)) << false;
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index 3bf872569f..88b9c2d792 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -1296,7 +1296,7 @@ void tst_qquicktextedit::selectionOnFocusOut()
QVERIFY(edit2->hasActiveFocus());
edit2->setFocus(false, Qt::PopupFocusReason);
- QVERIFY(!edit2->hasActiveFocus());
+ QVERIFY(edit2->hasActiveFocus());
QCOMPARE(edit2->selectedText(), QLatin1String("text 2"));
}
diff --git a/tests/auto/quick/qquicktextinput/qquicktextinput.pro b/tests/auto/quick/qquicktextinput/qquicktextinput.pro
index c14b09c545..521f41df43 100644
--- a/tests/auto/quick/qquicktextinput/qquicktextinput.pro
+++ b/tests/auto/quick/qquicktextinput/qquicktextinput.pro
@@ -14,3 +14,5 @@ TESTDATA = data/*
QT += core-private gui-private qml-private quick-private testlib
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+macx: CONFIG+=insignificant_test # QTBUG-38363
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index 05cf0b9a5b..684229aa07 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -3606,7 +3606,8 @@ void tst_qquicktextinput::focusOutNotClearSelection()
input.setFocus(false, Qt::PopupFocusReason);
QGuiApplication::processEvents();
QTRY_COMPARE(input.selectedText(), QLatin1String("llo"));
- QTRY_COMPARE(input.hasActiveFocus(), false);
+ // QTBUG-36332 and 36292: a popup window does not take focus
+ QTRY_COMPARE(input.hasActiveFocus(), true);
input.setFocus(true);
QTRY_COMPARE(input.hasActiveFocus(), true);
diff --git a/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp b/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
index e9fbb5448c..9b62eb311c 100644
--- a/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
+++ b/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
@@ -53,6 +53,12 @@ private slots:
void tst_QQuickTimeLine::overflow()
{
+ // Test ensures that time value used in QQuickTimeLine::accel methods is always positive.
+ // On platforms where casting qreal value infinity to int yields a positive value this is
+ // always the case and the test would fail. Strictly speaking, the cast is undefined behavior.
+ if (static_cast<int>(qInf()) > 0)
+ QSKIP("Test is not applicable on this platform");
+
QQuickTimeLine timeline;
QQuickTimeLineValue value;
diff --git a/tests/auto/quick/qquickwindow/data/active.qml b/tests/auto/quick/qquickwindow/data/active.qml
index af0b7edeb2..4d47225b4e 100644
--- a/tests/auto/quick/qquickwindow/data/active.qml
+++ b/tests/auto/quick/qquickwindow/data/active.qml
@@ -14,7 +14,6 @@ Window {
anchors.fill: parent;
onPressed: window2.requestActivate();
}
- Component.onCompleted: window2.show();
}
Window {
@@ -22,6 +21,7 @@ Window {
objectName: "window2";
color: "#FF0000";
width: 100; height: 100;
+ visible: true
Item {
width: 100; height: 100;
}
diff --git a/tests/auto/quick/qquickwindow/data/windoworder.qml b/tests/auto/quick/qquickwindow/data/windoworder.qml
new file mode 100644
index 0000000000..33aea95694
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/windoworder.qml
@@ -0,0 +1,42 @@
+import QtQuick 2.1
+import QtQuick.Window 2.1
+
+Window {
+ id: window1;
+ objectName: "window1";
+ width: 100; height: 100;
+ visible: true
+ color: "blue"
+ property alias win2: window2
+ property alias win3: window3
+ property alias win4: window4
+ property alias win5: window5
+ Window {
+ id: window2;
+ objectName: "window2";
+ width: 100; height: 100;
+ visible: true
+ color: "green"
+ Window {
+ id: window3;
+ objectName: "window3";
+ width: 100; height: 100;
+ visible: true
+ }
+
+ Window { //Is invisible by default
+ id: window4
+ objectName: "window4";
+ height: 200
+ width: 200
+ color: "black"
+ Window {
+ id: window5
+ objectName: "window5";
+ height: 200
+ width: 200
+ visible: true
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickwindow/qquickwindow.pro b/tests/auto/quick/qquickwindow/qquickwindow.pro
index 2d1d62c135..e95b7dbb10 100644
--- a/tests/auto/quick/qquickwindow/qquickwindow.pro
+++ b/tests/auto/quick/qquickwindow/qquickwindow.pro
@@ -15,6 +15,7 @@ OTHER_FILES += \
data/active.qml \
data/AnimationsWhileHidden.qml \
data/Headless.qml \
- data/showHideAnimate.qml
+ data/showHideAnimate.qml \
+ data/windoworder.qml
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index de4067b6e5..a2e2980223 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -343,6 +343,8 @@ private slots:
void requestActivate();
+ void testWindowVisibilityOrder();
+
void blockClosing();
void crashWhenHoverItemDeleted();
@@ -1132,6 +1134,43 @@ void tst_qquickwindow::animationsWhileHidden()
QTRY_VERIFY(window->isVisible());
}
+// When running on native Nvidia graphics cards on linux, the
+// distance field glyph pixels have a measurable, but not visible
+// pixel error. Use a custom compare function to avoid
+//
+// This was GT-216 with the ubuntu "nvidia-319" driver package.
+// llvmpipe does not show the same issue.
+//
+bool compareImages(const QImage &ia, const QImage &ib)
+{
+ if (ia.size() != ib.size())
+ qDebug() << "images are of different size" << ia.size() << ib.size();
+ Q_ASSERT(ia.size() == ib.size());
+ Q_ASSERT(ia.format() == ib.format());
+
+ int w = ia.width();
+ int h = ia.height();
+ const int tolerance = 5;
+ for (int y=0; y<h; ++y) {
+ const uint *as= (const uint *) ia.constScanLine(y);
+ const uint *bs= (const uint *) ib.constScanLine(y);
+ for (int x=0; x<w; ++x) {
+ uint a = as[x];
+ uint b = bs[x];
+
+ // No tolerance for error in the alpha.
+ if ((a & 0xff000000) != (b & 0xff000000))
+ return false;
+ if (qAbs(qRed(a) - qRed(b)) > tolerance)
+ return false;
+ if (qAbs(qRed(a) - qRed(b)) > tolerance)
+ return false;
+ if (qAbs(qRed(a) - qRed(b)) > tolerance)
+ return false;
+ }
+ }
+ return true;
+}
void tst_qquickwindow::headless()
{
@@ -1179,8 +1218,7 @@ void tst_qquickwindow::headless()
// Verify that the visual output is the same
QImage newContent = window->grabWindow();
-
- QCOMPARE(originalContent, newContent);
+ QVERIFY(compareImages(newContent, originalContent));
}
void tst_qquickwindow::noUpdateWhenNothingChanges()
@@ -1600,7 +1638,8 @@ void tst_qquickwindow::requestActivate()
QVERIFY(windows.at(0)->objectName() == "window2");
window1->show();
- window1->requestActivate();
+ QVERIFY(QTest::qWaitForWindowExposed(windows.at(0))); //We wait till window 2 comes up
+ window1->requestActivate(); // and then transfer the focus to window1
QTRY_VERIFY(QGuiApplication::focusWindow() == window1);
QVERIFY(window1->isActive() == true);
@@ -1626,6 +1665,54 @@ void tst_qquickwindow::requestActivate()
QTRY_VERIFY(QGuiApplication::focusWindow() == windows.at(0));
QVERIFY(windows.at(0)->isActive());
+ delete window1;
+}
+
+void tst_qquickwindow::testWindowVisibilityOrder()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("windoworder.qml"));
+ QQuickWindow *window1 = qobject_cast<QQuickWindow *>(component.create());
+ QQuickWindow *window2 = window1->property("win2").value<QQuickWindow*>();
+ QQuickWindow *window3 = window1->property("win3").value<QQuickWindow*>();
+ QQuickWindow *window4 = window1->property("win4").value<QQuickWindow*>();
+ QQuickWindow *window5 = window1->property("win5").value<QQuickWindow*>();
+ QVERIFY(window1);
+ QVERIFY(window2);
+ QVERIFY(window3);
+
+ QTest::qWaitForWindowExposed(window3);
+
+ QWindowList windows = QGuiApplication::topLevelWindows();
+ QTRY_COMPARE(windows.size(), 5);
+
+ QVERIFY(window3 == QGuiApplication::focusWindow());
+ QVERIFY(window1->isActive());
+ QVERIFY(window2->isActive());
+ QVERIFY(window3->isActive());
+
+ //Test if window4 is shown 2 seconds after the application startup
+ //with window4 visible window5 (transient child) should also become visible
+ QVERIFY(!window4->isVisible());
+ QVERIFY(!window5->isVisible());
+
+ window4->setVisible(true);
+
+ QTest::qWaitForWindowExposed(window5);
+ QVERIFY(window4->isVisible());
+ QVERIFY(window5->isVisible());
+ window4->hide();
+ window5->hide();
+
+ window3->hide();
+#if defined(Q_OS_OSX)
+ QEXPECT_FAIL("","Focus is not transferred to transient parent on window close (QTBUG-33423)", Continue);
+#endif
+ QTRY_COMPARE(window2 == QGuiApplication::focusWindow(), true);
+
+ window2->hide();
+ QTRY_COMPARE(window1 == QGuiApplication::focusWindow(), true);
}
void tst_qquickwindow::blockClosing()
diff --git a/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml b/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml
new file mode 100644
index 0000000000..c0c5a25e3c
--- /dev/null
+++ b/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import QtQuick.XmlListModel 2.0
+import SortFilterProxyModel 1.0
+
+SortFilterProxyModel {
+ source: XmlListModel {
+ XmlRole { }
+ }
+}
diff --git a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp b/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp
index a3cfa0011a..1d5518047f 100644
--- a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp
+++ b/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp
@@ -51,6 +51,7 @@
#include <QtCore/qtimer.h>
#include <QtCore/qfile.h>
#include <QtCore/qtemporaryfile.h>
+#include <QtCore/qsortfilterproxymodel.h>
#include "../../shared/util.h"
#include <private/qqmlengine_p.h>
@@ -106,6 +107,7 @@ private slots:
void selectAncestor();
void roleCrash();
+ void proxyCrash();
private:
QString errorString(QAbstractItemModel *model) {
@@ -988,6 +990,28 @@ void tst_qquickxmllistmodel::roleCrash()
delete model;
}
+class SortFilterProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *source READ source WRITE setSource)
+
+public:
+ SortFilterProxyModel(QObject *parent = 0) : QSortFilterProxyModel(parent) { sort(0); }
+ QObject *source() const { return sourceModel(); }
+ void setSource(QObject *source) { setSourceModel(qobject_cast<QAbstractItemModel *>(source)); }
+};
+
+void tst_qquickxmllistmodel::proxyCrash()
+{
+ qmlRegisterType<SortFilterProxyModel>("SortFilterProxyModel", 1, 0, "SortFilterProxyModel");
+
+ // don't crash
+ QQmlComponent component(&engine, testFileUrl("proxyCrash.qml"));
+ QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create());
+ QVERIFY(model != 0);
+ delete model;
+}
+
QTEST_MAIN(tst_qquickxmllistmodel)
#include "tst_qquickxmllistmodel.moc"
diff --git a/tests/auto/quick/scenegraph/data/render_bug37422.qml b/tests/auto/quick/scenegraph/data/render_bug37422.qml
new file mode 100644
index 0000000000..38e2b64da7
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/render_bug37422.qml
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+
+/*
+ The test verifies that batching does not interfere with overlapping
+ regions.
+
+ #samples: 8
+ PixelPos R G B Error-tolerance
+ #base: 0 0 1.0 0.0 0.0 0.05
+ #base: 1 1 0.0 0.0 1.0 0.05
+ #base: 10 10 1.0 0.0 0.0 0.05
+ #base: 1 11 0.0 0.0 1.0 0.05
+
+ #final: 0 0 1.0 0.0 0.0 0.05
+ #final: 1 1 0.0 1.0 0.0 0.05
+ #final: 10 10 1.0 0.0 0.0 0.05
+ #final: 1 11 0.0 1.0 0.0 0.05
+
+*/
+
+RenderTestBase
+{
+ id: root
+
+ opacity: 0.99
+
+ Rectangle {
+ width: 100
+ height: 9
+ color: Qt.rgba(1, 0, 0);
+
+ Rectangle {
+ id: box
+ width: 5
+ height: 5
+ x: 1
+ y: 1
+ color: Qt.rgba(0, 0, 1);
+ }
+ }
+
+ ShaderEffect { // Something which blends and is different than rectangle. Will get its own batch
+ width: 100
+ height: 9
+ y: 10
+ fragmentShader: "varying highp vec2 qt_TexCoord0; void main() { gl_FragColor = vec4(1, 0, 0, 1); }"
+
+ Rectangle {
+ width: 5
+ height: 5
+ x: 1
+ y: 1
+ color: box.color
+ }
+ }
+
+ onEnterFinalStage: {
+ box.color = Qt.rgba(0, 1, 0);
+ root.finalStageComplete = true;
+ }
+
+}
diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
index 5d393fedb5..ac4938e8bc 100644
--- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp
+++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
@@ -119,7 +119,7 @@ bool compareImages(const QImage &ia, const QImage &ib)
int w = ia.width();
int h = ia.height();
- const int tolerance = 1;
+ const int tolerance = 5;
for (int y=0; y<h; ++y) {
const uint *as= (const uint *) ia.constScanLine(y);
const uint *bs= (const uint *) ib.constScanLine(y);
@@ -328,6 +328,7 @@ void tst_SceneGraph::render_data()
<< "data/render_StackingOrder.qml"
<< "data/render_Mipmap.qml"
<< "data/render_ImageFiltering.qml"
+ << "data/render_bug37555.qml"
;
QRegExp sampleCount("#samples: *(\\d+)");
diff --git a/tests/manual/highdpi/fillmodes.qml b/tests/manual/highdpi/fillmodes.qml
new file mode 100644
index 0000000000..cff2bcc34c
--- /dev/null
+++ b/tests/manual/highdpi/fillmodes.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 700
+
+ // the images should have the same display size and appearance on each row.
+ Column {
+ anchors.centerIn: parent.Center
+ Row {
+ Image { width: 130; height: 70; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+ Image { width: 130; height: 70; fillMode: Image.Stretch; source : "heart.png" }
+ Image { width: 130; height: 70; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+ }
+ Row {
+ Image { width: 130; height: 100; fillMode: Image.PreserveAspectFit; source : "heart-lowdpi.png" }
+ Image { width: 130; height: 100; fillMode: Image.PreserveAspectFit; source : "heart.png" }
+ Image { width: 130; height: 100; fillMode: Image.PreserveAspectFit; source : "heart-highdpi@2x.png" }
+ }
+ Row {
+ Image { width: 130; height: 100; fillMode: Image.PreserveAspectCrop; source : "heart-lowdpi.png" }
+ Image { width: 130; height: 100; fillMode: Image.PreserveAspectCrop; source : "heart.png" }
+ Image { width: 130; height: 100; fillMode: Image.PreserveAspectCrop; source : "heart-highdpi@2x.png" }
+ }
+ Row {
+ Image { width: 230; height: 200; fillMode: Image.Tile; source : "heart-lowdpi.png" }
+ Image { width: 230; height: 200; fillMode: Image.Tile; source : "heart.png" }
+ Image { width: 230; height: 200; fillMode: Image.Tile; source : "heart-highdpi@2x.png" }
+ }
+ }
+}
diff --git a/tests/manual/highdpi/heart-highdpi@2x.png b/tests/manual/highdpi/heart-highdpi@2x.png
new file mode 100644
index 0000000000..a7a1ca89a4
--- /dev/null
+++ b/tests/manual/highdpi/heart-highdpi@2x.png
Binary files differ
diff --git a/tests/manual/highdpi/heart-lowdpi.png b/tests/manual/highdpi/heart-lowdpi.png
new file mode 100644
index 0000000000..deaec18274
--- /dev/null
+++ b/tests/manual/highdpi/heart-lowdpi.png
Binary files differ
diff --git a/tests/manual/highdpi/heart.png b/tests/manual/highdpi/heart.png
new file mode 100644
index 0000000000..deaec18274
--- /dev/null
+++ b/tests/manual/highdpi/heart.png
Binary files differ
diff --git a/tests/manual/highdpi/heart@2x.png b/tests/manual/highdpi/heart@2x.png
new file mode 100644
index 0000000000..a7a1ca89a4
--- /dev/null
+++ b/tests/manual/highdpi/heart@2x.png
Binary files differ
diff --git a/tests/manual/highdpi/image.qml b/tests/manual/highdpi/image.qml
new file mode 100644
index 0000000000..8deab5c734
--- /dev/null
+++ b/tests/manual/highdpi/image.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ Image {
+ source : "heart.png"
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/manual/highdpi/image2.qml b/tests/manual/highdpi/image2.qml
new file mode 100644
index 0000000000..b83c8006d8
--- /dev/null
+++ b/tests/manual/highdpi/image2.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ // These images should all have the same visual size:
+ Row {
+ anchors.centerIn: parent
+ // 1X only
+ Image {
+ source : "heart-lowdpi.png"
+ }
+ // 1X and 2x, switches on screen change.
+ Image {
+ source : "heart.png"
+ }
+ // 2x only
+ Image {
+ source : "heart-highdpi@2x.png"
+ }
+ }
+}
diff --git a/tests/manual/highdpi/imagesize.qml b/tests/manual/highdpi/imagesize.qml
new file mode 100644
index 0000000000..ee6719a6ee
--- /dev/null
+++ b/tests/manual/highdpi/imagesize.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ Column {
+ anchors.centerIn: parent.Center
+ Row {
+ Image { width: 50; height: 50; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+ Image { width: 50; height: 50; fillMode: Image.Stretch; source : "heart.png" }
+ Image { width: 50; height: 50; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+ }
+ Row {
+ Image { width: 100; height: 100; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+ Image { width: 100; height: 100; fillMode: Image.Stretch; source : "heart.png" }
+ Image { width: 100; height: 100; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+ }
+ Row {
+ Image { width: 150; height: 150; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+ Image { width: 150; height: 150; fillMode: Image.Stretch; source : "heart.png" }
+ Image { width: 150; height: 150; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+ }
+ Row {
+ Image { width: 200; height: 200; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+ Image { width: 200; height: 200; fillMode: Image.Stretch; source : "heart.png" }
+ Image { width: 200; height: 200; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+ }
+ Row {
+ Image { width: 300; height: 300; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+ Image { width: 300; height: 300; fillMode: Image.Stretch; source : "heart.png" }
+ Image { width: 300; height: 300; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+ }
+ }
+}
diff --git a/tests/manual/highdpi/mirror.qml b/tests/manual/highdpi/mirror.qml
new file mode 100644
index 0000000000..3a92a9abd4
--- /dev/null
+++ b/tests/manual/highdpi/mirror.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 700
+
+ // the images should have the same display size and appearance on each row.
+ Column {
+ anchors.centerIn: parent.Center
+ Row {
+ Image { mirror: true; source : "heart-lowdpi.png" }
+ Image { mirror: true; source : "heart.png" }
+ Image { mirror: true; source : "heart-highdpi@2x.png" }
+ }
+ }
+}
diff --git a/tests/manual/highdpi/sourcesize.qml b/tests/manual/highdpi/sourcesize.qml
new file mode 100644
index 0000000000..64bf8ad86b
--- /dev/null
+++ b/tests/manual/highdpi/sourcesize.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ // SourceSize is in device-independent pixels. These images
+ // should display at the same visual size.
+ Column {
+ anchors.centerIn: parent.Center
+ Row {
+
+ // standard image with no @2x version
+ Image {
+ sourceSize.width: 75
+ sourceSize.height: 75
+ source : "heart-lowdpi.png"
+ }
+
+ // image with "@2x" version on disk
+ Image {
+ sourceSize.width: 75
+ sourceSize.height: 75
+ source : "heart.png"
+ }
+
+ // direct use of "@2x" image
+ Image {
+ sourceSize.width: 75
+ sourceSize.height: 75
+ source : "heart-highdpi@2x.png"
+ }
+ }
+ }
+}
diff --git a/tests/testapplications/text/text.qml b/tests/testapplications/text/text.qml
index 56ca825d0a..b1e600a633 100644
--- a/tests/testapplications/text/text.qml
+++ b/tests/testapplications/text/text.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -130,7 +130,7 @@ Rectangle {
"value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+
"modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices.\n"+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime. "+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
textmodel.append({ "name": "Short",
@@ -143,7 +143,7 @@ Rectangle {
"value": "<b>Qt Quick</b> is a collection of technologies that are designed to help developers create the kind of <i>intuitive, "+
"modern, fluid</i> user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices.<br>"+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime. "+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
}
diff --git a/tests/testapplications/text/textedit.qml b/tests/testapplications/text/textedit.qml
index 6546abfe91..3baa307d8d 100644
--- a/tests/testapplications/text/textedit.qml
+++ b/tests/testapplications/text/textedit.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -127,7 +127,7 @@ Rectangle {
"value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+
"modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices."+texteditelement.newline+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime.\n"+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
textmodel.append({ "name": "Short",
@@ -140,7 +140,7 @@ Rectangle {
"value": "<b>Qt Quick</b> is a collection of technologies that are designed to help developers create the kind of <i>intuitive, "+
"modern, fluid</i> user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices.<br>"+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime. "+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
textmodel.append({ "name": "Links",
diff --git a/tests/testapplications/text/textinput.qml b/tests/testapplications/text/textinput.qml
index 556771bcb5..d15d02232a 100644
--- a/tests/testapplications/text/textinput.qml
+++ b/tests/testapplications/text/textinput.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -175,7 +175,7 @@ Rectangle {
"value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+
"modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices. "+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime. "+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
}
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 08095962be..3fa36ad8f7 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -351,11 +351,7 @@ static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
QStringList list = dir.entryList();
for (int i = 0; i < list.size(); ++i) {
QString qml = list.at(i);
- QFile f(dir.filePath(qml));
- f.open(QIODevice::ReadOnly);
- QByteArray data = f.readAll();
- QQmlComponent comp(&engine);
- comp.setData(data, QUrl());
+ QQmlComponent comp(&engine, dir.filePath(qml));
QObject *dummyData = comp.create();
if (comp.isError()) {
@@ -500,6 +496,10 @@ int main(int argc, char *argv[])
//Load files
LoadWatcher lw(&e, files.count());
+ // Load dummy data before loading QML-files
+ if (!dummyDir.isEmpty() && QFileInfo (dummyDir).isDir())
+ loadDummyDataFiles(e, dummyDir);
+
foreach (const QString &path, files) {
//QUrl::fromUserInput doesn't treat no scheme as relative file paths
QRegularExpression urlRe("[[:word:]]+://.*");
@@ -523,10 +523,6 @@ int main(int argc, char *argv[])
}
}
-
- if (!dummyDir.isEmpty() && QFileInfo (dummyDir).isDir())
- loadDummyDataFiles(e, dummyDir);
-
return app->exec();
}
diff --git a/tools/qmlbundle/main.cpp b/tools/qmlbundle/main.cpp
index 60d12e8574..d77db353e5 100644
--- a/tools/qmlbundle/main.cpp
+++ b/tools/qmlbundle/main.cpp
@@ -40,8 +40,9 @@
****************************************************************************/
#include <private/qqmlbundle_p.h>
-#include <private/qqmlscript_p.h>
#include <QtCore/QCoreApplication>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
#include <iostream>
static bool createBundle(const QString &fileName, const QStringList &fileNames)
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index d3c5c638e9..9ad315016f 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -43,7 +43,9 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
#include <private/qv4codegen_p.h>
+#include <private/qv4value_inl_p.h>
#include <private/qqmlpool_p.h>
+#include <private/qqmlirbuilder_p.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
@@ -238,38 +240,38 @@ QVariantList findQmlImportsInJavascriptFile(const QString &filePath)
QVariantList imports;
- // look for ".import Foo.Bar 2.0 as FooBar" lines
- do {
- QByteArray rawLine = file.readLine();
- QByteArray line = rawLine.simplified();
- if (line.simplified().startsWith(".import")) {
- QList<QByteArray> parts = line.split(' ');
-
- if (parts.count() < 2)
- continue;
-
- QVariantMap import;
- QByteArray name = parts.at(1);
- QByteArray version = parts.at(2);
-
- // handle import cases: .js file, diriectory (check for precense of "/"),
- // and module (the most common case)
- if (name.contains(".js")) {
- import[QStringLiteral("type")] = QStringLiteral("javascript");
- import[QStringLiteral("path")] = name;
- } else if (name.contains("/")) {
- import[QStringLiteral("type")] = QStringLiteral("directory");
- import[QStringLiteral("path")] = name;
+ QString sourceCode = QString::fromUtf8(file.readAll());
+ file.close();
+ QmlIR::Document doc(/*debug mode*/false);
+ QQmlJS::DiagnosticMessage error;
+ doc.extractScriptMetaData(sourceCode, &error);
+ if (!error.message.isEmpty())
+ return imports;
+
+ foreach (const QV4::CompiledData::Import *import, doc.imports) {
+ QVariantMap entry;
+ const QString name = doc.stringAt(import->uriIndex);
+ switch (import->type) {
+ case QV4::CompiledData::Import::ImportScript:
+ entry[QStringLiteral("type")] = QStringLiteral("javascript");
+ entry[QStringLiteral("path")] = name;
+ break;
+ case QV4::CompiledData::Import::ImportLibrary:
+ if (name.contains(QLatin1Char('/'))) {
+ entry[QStringLiteral("type")] = QStringLiteral("directory");
+ entry[QStringLiteral("name")] = name;
} else {
- import[QStringLiteral("type")] = QStringLiteral("module");
- import[QStringLiteral("name")] = name;
- import[QStringLiteral("version")] = version;
+ entry[QStringLiteral("type")] = QStringLiteral("module");
+ entry[QStringLiteral("name")] = name;
+ entry[QStringLiteral("version")] = QString::number(import->majorVersion) + QLatin1Char('.') + QString::number(import->minorVersion);
}
-
- imports.append(import);
+ break;
+ default:
+ Q_UNREACHABLE();
+ continue;
}
+ imports << entry;
}
- while (file.canReadLine());
return imports;
}
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index 1b4e2a3b94..bc55c40434 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -317,6 +317,29 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
return metas;
}
+class KnownAttributes {
+ QHash<QByteArray, int> m_properties;
+ QHash<QByteArray, QHash<int, int> > m_methods;
+public:
+ bool knownMethod(const QByteArray &name, int nArgs, int revision)
+ {
+ if (m_methods.contains(name)) {
+ QHash<int, int> overloads = m_methods.value(name);
+ if (overloads.contains(nArgs) && overloads.value(nArgs) <= revision)
+ return true;
+ }
+ m_methods[name][nArgs] = revision;
+ return false;
+ }
+
+ bool knownProperty(const QByteArray &name, int revision)
+ {
+ if (m_properties.contains(name) && m_properties.value(name) <= revision)
+ return true;
+ m_properties[name] = revision;
+ return false;
+ }
+};
class Dumper
{
@@ -350,12 +373,15 @@ public:
return exportString;
}
- void writeMetaContent(const QMetaObject *meta)
+ void writeMetaContent(const QMetaObject *meta, KnownAttributes *knownAttributes = 0)
{
QSet<QString> implicitSignals;
for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) {
const QMetaProperty &property = meta->property(index);
- dump(property);
+ dump(property, knownAttributes);
+ if (knownAttributes)
+ knownAttributes->knownMethod(QByteArray(property.name()).append("Changed"),
+ 0, property.revision());
implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name())));
}
@@ -368,38 +394,52 @@ public:
|| signature == QByteArrayLiteral("destroyed()")
|| signature == QByteArrayLiteral("deleteLater()"))
continue;
- dump(method, implicitSignals);
+ dump(method, implicitSignals, knownAttributes);
}
// and add toString(), destroy() and destroy(int)
- qml->writeStartObject(QLatin1String("Method"));
- qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString")));
- qml->writeEndObject();
- qml->writeStartObject(QLatin1String("Method"));
- qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy")));
- qml->writeEndObject();
- qml->writeStartObject(QLatin1String("Method"));
- qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy")));
- qml->writeStartObject(QLatin1String("Parameter"));
- qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("delay")));
- qml->writeScriptBinding(QLatin1String("type"), enquote(QLatin1String("int")));
- qml->writeEndObject();
- qml->writeEndObject();
+ if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("toString"), 0, 0)) {
+ qml->writeStartObject(QLatin1String("Method"));
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString")));
+ qml->writeEndObject();
+ }
+ if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("destroy"), 0, 0)) {
+ qml->writeStartObject(QLatin1String("Method"));
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy")));
+ qml->writeEndObject();
+ }
+ if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("destroy"), 1, 0)) {
+ qml->writeStartObject(QLatin1String("Method"));
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy")));
+ qml->writeStartObject(QLatin1String("Parameter"));
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("delay")));
+ qml->writeScriptBinding(QLatin1String("type"), enquote(QLatin1String("int")));
+ qml->writeEndObject();
+ qml->writeEndObject();
+ }
} else {
for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
- dump(meta->method(index), implicitSignals);
+ dump(meta->method(index), implicitSignals, knownAttributes);
}
}
- QString getPrototypeNameForCompositeType(const QMetaObject *metaObject, QSet<QByteArray> &defaultReachableNames)
+ QString getPrototypeNameForCompositeType(const QMetaObject *metaObject, QSet<QByteArray> &defaultReachableNames,
+ QList<const QMetaObject *> *objectsToMerge)
{
QString prototypeName;
if (!defaultReachableNames.contains(metaObject->className())) {
+ // dynamic meta objects can break things badly
+ // but extended types are usually fine
+ const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data);
+ if (!(mop->flags & DynamicMetaObject) && objectsToMerge
+ && !objectsToMerge->contains(metaObject))
+ objectsToMerge->append(metaObject);
const QMetaObject *superMetaObject = metaObject->superClass();
if (!superMetaObject)
prototypeName = "QObject";
else
- prototypeName = getPrototypeNameForCompositeType(superMetaObject, defaultReachableNames);
+ prototypeName = getPrototypeNameForCompositeType(
+ superMetaObject, defaultReachableNames, objectsToMerge);
} else {
prototypeName = convertToId(metaObject->className());
}
@@ -418,8 +458,11 @@ public:
const QMetaObject *mainMeta = object->metaObject();
+ QList<const QMetaObject *> objectsToMerge;
+ KnownAttributes knownAttributes;
// Get C++ base class name for the composite type
- QString prototypeName = getPrototypeNameForCompositeType(mainMeta, defaultReachableNames);
+ QString prototypeName = getPrototypeNameForCompositeType(mainMeta, defaultReachableNames,
+ &objectsToMerge);
qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName));
QString qmlTyName = compositeType->qmlTypeName();
@@ -430,11 +473,10 @@ public:
qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType->minorVersion()));
qml->writeBooleanBinding(QLatin1String("isComposite"), true);
- if (!compositeType->isCreatable())
+ if (compositeType->isSingleton()) {
qml->writeBooleanBinding(QLatin1String("isCreatable"), false);
-
- if (compositeType->isSingleton())
qml->writeBooleanBinding(QLatin1String("isSingleton"), true);
+ }
for (int index = mainMeta->classInfoCount() - 1 ; index >= 0 ; --index) {
QMetaClassInfo classInfo = mainMeta->classInfo(index);
@@ -444,25 +486,8 @@ public:
}
}
- QSet<const QMetaObject *> metas;
- QSet<const QMetaObject *> candidatesComposite;
- collectReachableMetaObjects(mainMeta, &candidatesComposite);
-
- // 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, candidatesComposite) {
- if (!defaultReachableNames.contains(mo->className()))
- metas.insert(mo);
- }
-
- // 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)
- nameToMeta.insert(convertToId(meta), meta);
-
- foreach (const QMetaObject *meta, nameToMeta)
- writeMetaContent(meta);
+ foreach (const QMetaObject *meta, objectsToMerge)
+ writeMetaContent(meta, &knownAttributes);
qml->writeEndObject();
}
@@ -580,21 +605,23 @@ private:
qml->writeScriptBinding(QLatin1String("isPointer"), QLatin1String("true"));
}
- void dump(const QMetaProperty &prop)
+ void dump(const QMetaProperty &prop, KnownAttributes *knownAttributes = 0)
{
+ int revision = prop.revision();
+ QByteArray propName = prop.name();
+ if (knownAttributes && knownAttributes->knownProperty(propName, revision))
+ return;
qml->writeStartObject("Property");
-
qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(prop.name())));
-#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 4))
- if (int revision = prop.revision())
+ if (revision)
qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision));
-#endif
writeTypeProperties(prop.typeName(), prop.isWritable());
qml->writeEndObject();
}
- void dump(const QMetaMethod &meth, const QSet<QString> &implicitSignals)
+ void dump(const QMetaMethod &meth, const QSet<QString> &implicitSignals,
+ KnownAttributes *knownAttributes = 0)
{
if (meth.methodType() == QMetaMethod::Signal) {
if (meth.access() != QMetaMethod::Public)
@@ -615,6 +642,9 @@ private:
return;
}
+ int revision = meth.revision();
+ if (knownAttributes && knownAttributes->knownMethod(name, meth.parameterNames().size(), revision))
+ return;
if (meth.methodType() == QMetaMethod::Signal)
qml->writeStartObject(QLatin1String("Signal"));
else
@@ -622,10 +652,8 @@ private:
qml->writeScriptBinding(QLatin1String("name"), enquote(name));
-#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 4))
- if (int revision = meth.revision())
+ if (revision)
qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision));
-#endif
if (typeName != QLatin1String("void"))
qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
diff --git a/tools/qmlplugindump/qmlplugindump.pro b/tools/qmlplugindump/qmlplugindump.pro
index 67af71c59f..6fdcd349d1 100644
--- a/tools/qmlplugindump/qmlplugindump.pro
+++ b/tools/qmlplugindump/qmlplugindump.pro
@@ -1,6 +1,8 @@
QT += qml qml-private quick-private core-private
-CONFIG += no_import_scan qpa_minimal_plugin
+CONFIG += no_import_scan
+
+QTPLUGIN.platforms = qminimal
SOURCES += \
main.cpp \
diff --git a/tools/qmlprofiler/qmlprofilerapplication.cpp b/tools/qmlprofiler/qmlprofilerapplication.cpp
index 6c3e697f56..4c05fe8d64 100644
--- a/tools/qmlprofiler/qmlprofilerapplication.cpp
+++ b/tools/qmlprofiler/qmlprofilerapplication.cpp
@@ -108,7 +108,7 @@ QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) :
&m_profilerData, SLOT(addQmlEvent(QQmlProfilerService::RangeType,QQmlProfilerService::BindingType,qint64,qint64,QStringList,QmlEventLocation)));
connect(&m_qmlProfilerClient, SIGNAL(traceFinished(qint64)), &m_profilerData, SLOT(setTraceEndTime(qint64)));
connect(&m_qmlProfilerClient, SIGNAL(traceStarted(qint64)), &m_profilerData, SLOT(setTraceStartTime(qint64)));
- connect(&m_qmlProfilerClient, SIGNAL(frame(qint64,int,int)), &m_profilerData, SLOT(addFrameEvent(qint64,int,int)));
+ connect(&m_qmlProfilerClient, SIGNAL(frame(qint64,int,int,int)), &m_profilerData, SLOT(addFrameEvent(qint64,int,int,int)));
connect(&m_qmlProfilerClient, SIGNAL(complete()), this, SLOT(qmlComplete()));
connect(&m_v8profilerClient, SIGNAL(enabledChanged()), this, SLOT(profilerClientEnabled()));
diff --git a/tools/qmlprofiler/qmlprofilerclient.cpp b/tools/qmlprofiler/qmlprofilerclient.cpp
index 25557af77f..23a75d0576 100644
--- a/tools/qmlprofiler/qmlprofilerclient.cpp
+++ b/tools/qmlprofiler/qmlprofilerclient.cpp
@@ -174,8 +174,11 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
d->maximumTime = qMax(time, d->maximumTime);
} else if (event == QQmlProfilerService::AnimationFrame) {
int frameRate, animationCount;
+ int threadId = 0;
stream >> frameRate >> animationCount;
- emit this->frame(time, frameRate, animationCount);
+ if (!stream.atEnd())
+ stream >> threadId;
+ emit this->frame(time, frameRate, animationCount, threadId);
d->maximumTime = qMax(time, d->maximumTime);
} else if (event == QQmlProfilerService::StartTrace) {
emit this->traceStarted(time);
diff --git a/tools/qmlprofiler/qmlprofilerclient.h b/tools/qmlprofiler/qmlprofilerclient.h
index e0bba0b660..29492c49ff 100644
--- a/tools/qmlprofiler/qmlprofilerclient.h
+++ b/tools/qmlprofiler/qmlprofilerclient.h
@@ -102,7 +102,7 @@ signals:
qint64 startTime, qint64 length,
const QStringList &data,
const QmlEventLocation &location);
- void frame(qint64 time, int frameRate, int animationCount);
+ void frame(qint64 time, int frameRate, int animationCount, int threadId);
protected:
virtual void messageReceived(const QByteArray &);
diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp
index 038d2177f9..00dc09901f 100644
--- a/tools/qmlprofiler/qmlprofilerdata.cpp
+++ b/tools/qmlprofiler/qmlprofilerdata.cpp
@@ -56,6 +56,9 @@ namespace Constants {
const char TYPE_BINDING_STR[] = "Binding";
const char TYPE_HANDLINGSIGNAL_STR[] = "HandlingSignal";
const char PROFILER_FILE_VERSION[] = "1.02";
+
+ // Save animation frames in "Qt5 style", 3 would mean Qt4
+ const int ANIMATION_FRAME_TYPE = 4;
}
struct QmlRangeEventData {
@@ -79,14 +82,15 @@ struct QmlRangeEventData {
struct QmlRangeEventStartInstance {
QmlRangeEventStartInstance() {} // never called
QmlRangeEventStartInstance(qint64 _startTime, qint64 _duration, int _frameRate,
- int _animationCount, QmlRangeEventData *_data)
+ int _animationCount, int _threadId, QmlRangeEventData *_data)
: startTime(_startTime), duration(_duration), frameRate(_frameRate),
- animationCount(_animationCount), data(_data)
+ animationCount(_animationCount), threadId(_threadId), data(_data)
{ }
qint64 startTime;
qint64 duration;
int frameRate;
int animationCount;
+ int threadId;
QmlRangeEventData *data;
};
@@ -122,7 +126,6 @@ public:
qint64 traceEndTime;
// internal state while collecting events
- QmlRangeEventStartInstance *lastFrameEvent;
qint64 qmlMeasuredTime;
qint64 v8MeasuredTime;
QHash<int, QV8EventInfo *> v8parents;
@@ -162,8 +165,6 @@ void QmlProfilerData::clear()
d->traceStartTime = -1;
d->qmlMeasuredTime = 0;
- d->lastFrameEvent = 0;
-
setState(Empty);
}
@@ -271,12 +272,12 @@ void QmlProfilerData::addQmlEvent(QQmlProfilerService::RangeType type,
d->eventDescriptions.insert(eventHashStr, newEvent);
}
- QmlRangeEventStartInstance rangeEventStartInstance(startTime, duration, 1e9/duration, -1, newEvent);
+ QmlRangeEventStartInstance rangeEventStartInstance(startTime, duration, -1, -1, -1, newEvent);
d->startInstanceList.append(rangeEventStartInstance);
}
-void QmlProfilerData::addFrameEvent(qint64 time, int framerate, int animationcount)
+void QmlProfilerData::addFrameEvent(qint64 time, int framerate, int animationcount, int threadId)
{
setState(AcquiringData);
@@ -292,18 +293,10 @@ void QmlProfilerData::addFrameEvent(qint64 time, int framerate, int animationcou
d->eventDescriptions.insert(eventHashStr, newEvent);
}
- qint64 duration = 1e9/framerate;
- // avoid overlap
- if (d->lastFrameEvent &&
- d->lastFrameEvent->startTime + d->lastFrameEvent->duration >= time) {
- d->lastFrameEvent->duration = time - 1 - d->lastFrameEvent->startTime;
- }
-
- QmlRangeEventStartInstance rangeEventStartInstance(time, duration, framerate, animationcount, newEvent);
+ QmlRangeEventStartInstance rangeEventStartInstance(time, -1, framerate, animationcount,
+ threadId, newEvent);
d->startInstanceList.append(rangeEventStartInstance);
-
- d->lastFrameEvent = &d->startInstanceList.last();
}
QString QmlProfilerData::rootEventName()
@@ -502,6 +495,9 @@ bool QmlProfilerData::save(const QString &filename)
stream.writeTextElement(QStringLiteral("details"), eventData->details);
if (eventData->eventType == QQmlProfilerService::Binding)
stream.writeTextElement(QStringLiteral("bindingType"), QString::number((int)eventData->bindingType));
+ else if (eventData->eventType == QQmlProfilerService::Painting)
+ stream.writeTextElement(QStringLiteral("animationFrame"),
+ QString::number(Constants::ANIMATION_FRAME_TYPE));
stream.writeEndElement();
}
stream.writeEndElement(); // eventData
@@ -510,12 +506,15 @@ bool QmlProfilerData::save(const QString &filename)
foreach (const QmlRangeEventStartInstance &rangedEvent, d->startInstanceList) {
stream.writeStartElement(QStringLiteral("range"));
stream.writeAttribute(QStringLiteral("startTime"), QString::number(rangedEvent.startTime));
- stream.writeAttribute(QStringLiteral("duration"), QString::number(rangedEvent.duration));
+ if (rangedEvent.duration >= 0)
+ stream.writeAttribute(QStringLiteral("duration"),
+ QString::number(rangedEvent.duration));
stream.writeAttribute(QStringLiteral("eventIndex"), QString::number(d->eventDescriptions.keys().indexOf(rangedEvent.data->eventHashStr)));
if (rangedEvent.data->eventType == QQmlProfilerService::Painting && rangedEvent.animationCount >= 0) {
// animation frame
stream.writeAttribute(QStringLiteral("framerate"), QString::number(rangedEvent.frameRate));
stream.writeAttribute(QStringLiteral("animationcount"), QString::number(rangedEvent.animationCount));
+ stream.writeAttribute(QStringLiteral("thread"), QString::number(rangedEvent.threadId));
}
stream.writeEndElement();
}
diff --git a/tools/qmlprofiler/qmlprofilerdata.h b/tools/qmlprofiler/qmlprofilerdata.h
index 134e7228af..a5d55ed6f6 100644
--- a/tools/qmlprofiler/qmlprofilerdata.h
+++ b/tools/qmlprofiler/qmlprofilerdata.h
@@ -88,7 +88,7 @@ public slots:
const QmlEventLocation &location);
void addV8Event(int depth, const QString &function, const QString &filename,
int lineNumber, double totalTime, double selfTime);
- void addFrameEvent(qint64 time, int framerate, int animationcount);
+ void addFrameEvent(qint64 time, int framerate, int animationcount, int threadId);
void complete();
bool save(const QString &filename);
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index fcf89afb9f..7512b5482f 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -58,6 +58,7 @@
#include <QtQuick/qquickview.h>
#include <private/qabstractanimation_p.h>
+#include <private/qopenglcontext_p.h>
#ifdef QT_WIDGETS_LIB
#include <QtWidgets/QApplication>
@@ -155,6 +156,7 @@ struct Options
, quitImmediately(false)
, resizeViewToRootItem(false)
, multisample(false)
+ , contextSharing(true)
{
}
@@ -171,6 +173,7 @@ struct Options
bool quitImmediately;
bool resizeViewToRootItem;
bool multisample;
+ bool contextSharing;
QString translationFile;
};
@@ -323,11 +326,7 @@ static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
QStringList list = dir.entryList();
for (int i = 0; i < list.size(); ++i) {
QString qml = list.at(i);
- QFile f(dir.filePath(qml));
- f.open(QIODevice::ReadOnly);
- QByteArray data = f.readAll();
- QQmlComponent comp(&engine);
- comp.setData(data, QUrl());
+ QQmlComponent comp(&engine, dir.filePath(qml));
QObject *dummyData = comp.create();
if(comp.isError()) {
@@ -358,6 +357,7 @@ static void usage()
qWarning(" --slow-animations ......................... Run all animations in slow motion");
qWarning(" --resize-to-root .......................... Resize the window to the size of the root item");
qWarning(" --quit .................................... Quit immediately after starting");
+ qWarning(" --disable-context-sharing ................. Disable the use of a shared GL context for QtQuick Windows");
qWarning(" -I <path> ................................. Add <path> to the list of import paths");
qWarning(" -B <name> <file> .......................... Add a named bundle");
qWarning(" -translation <translationfile> ............ Set the language to run in");
@@ -397,6 +397,8 @@ int main(int argc, char ** argv)
options.resizeViewToRootItem = true;
else if (lowerArgument == QLatin1String("--multisample"))
options.multisample = true;
+ else if (lowerArgument == QLatin1String("--disable-context-sharing"))
+ options.contextSharing = false;
else if (lowerArgument == QLatin1String("-i") && i + 1 < argc)
imports.append(QString::fromLatin1(argv[++i]));
else if (lowerArgument == QLatin1String("-b") && i + 2 < argc) {
@@ -452,6 +454,15 @@ int main(int argc, char ** argv)
displayFileDialog(&options);
#endif
+ // QWebEngine needs a shared context in order for the GPU thread to
+ // upload textures.
+ QScopedPointer<QOpenGLContext> shareContext;
+ if (options.contextSharing) {
+ shareContext.reset(new QOpenGLContext);
+ shareContext->create();
+ QOpenGLContextPrivate::setGlobalShareContext(shareContext.data());
+ }
+
int exitCode = 0;
if (!options.file.isEmpty()) {
diff --git a/tools/qmlscene/qmlscene.pro b/tools/qmlscene/qmlscene.pro
index 07208ea703..0411fd8e31 100644
--- a/tools/qmlscene/qmlscene.pro
+++ b/tools/qmlscene/qmlscene.pro
@@ -1,4 +1,4 @@
-QT += qml quick core-private
+QT += qml quick quick-private gui-private core-private
qtHaveModule(widgets): QT += widgets
CONFIG += no_import_scan