aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf18
-rw-r--r--dist/changes-5.2.015
-rw-r--r--examples/quick/demos/samegame/content/+blackberry/Settings.qml47
-rw-r--r--examples/quick/demos/samegame/content/BBSettings.qml61
-rw-r--r--examples/quick/demos/samegame/content/BlockEmitter.qml4
-rw-r--r--examples/quick/demos/samegame/content/GameArea.qml2
-rw-r--r--examples/quick/demos/samegame/content/PaintEmitter.qml2
-rw-r--r--examples/quick/demos/samegame/content/SamegameText.qml2
-rw-r--r--examples/quick/demos/samegame/content/Settings.qml60
-rw-r--r--examples/quick/demos/samegame/content/qmldir14
-rwxr-xr-xexamples/quick/demos/samegame/content/samegame.js27
-rw-r--r--examples/quick/demos/samegame/samegame.qml5
-rw-r--r--examples/quick/demos/samegame/samegame.qrc6
-rw-r--r--examples/quick/demos/stocqt/content/StockChart.qml5
-rw-r--r--examples/quick/demos/stocqt/content/StockModel.qml11
-rw-r--r--examples/quick/demos/stocqt/content/StockView.qml2
-rw-r--r--examples/quick/demos/stocqt/stocqt.qml14
-rw-r--r--examples/quick/dialogs/systemdialogs/FileDialogs.qml10
-rw-r--r--examples/quick/dialogs/systemdialogs/MessageDialogs.qml42
-rw-r--r--examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc2
-rw-r--r--examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc2
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.cpp5
-rw-r--r--examples/quick/shared/Button.qml4
-rw-r--r--examples/quick/shared/TabSet.qml2
-rw-r--r--examples/quick/shared/shared.h8
-rw-r--r--examples/quick/ui-components/slideswitch/doc/src/example-slideswitch.qdoc2
-rw-r--r--examples/quick/window/ScreenInfo.qml3
-rw-r--r--examples/quick/window/window.qml1
-rw-r--r--src/3rdparty/double-conversion/cached-powers.cc1
-rw-r--r--src/3rdparty/double-conversion/fixed-dtoa.cc2
-rw-r--r--src/3rdparty/double-conversion/strtod.cc2
-rw-r--r--src/3rdparty/double-conversion/utils.h5
-rw-r--r--src/3rdparty/masm/masm-defs.pri5
-rw-r--r--src/3rdparty/masm/masm.pri3
-rw-r--r--src/3rdparty/masm/stubs/ExecutableAllocator.h2
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp66
-rw-r--r--src/3rdparty/masm/wtf/PageBlock.cpp4
-rw-r--r--src/3rdparty/masm/wtf/Platform.h5
-rw-r--r--src/imports/dialogs/DefaultColorDialog.qml52
-rw-r--r--src/imports/dialogs/DefaultFileDialog.qml207
-rw-r--r--src/imports/dialogs/DefaultFontDialog.qml682
-rw-r--r--src/imports/dialogs/DefaultMessageDialog.qml130
-rw-r--r--src/imports/dialogs/dialogs.pro2
-rw-r--r--src/imports/dialogs/doc/images/critical.pngbin0 -> 253 bytes
-rw-r--r--src/imports/dialogs/doc/images/information.pngbin0 -> 254 bytes
-rw-r--r--src/imports/dialogs/doc/images/question.pngbin0 -> 257 bytes
-rw-r--r--src/imports/dialogs/doc/images/replacefile.pngbin0 -> 4304 bytes
-rw-r--r--src/imports/dialogs/doc/images/warning.pngbin0 -> 224 bytes
-rw-r--r--src/imports/dialogs/doc/qtquickdialogs.qdocconf2
-rw-r--r--src/imports/dialogs/plugin.cpp14
-rw-r--r--src/imports/dialogs/plugins.qmltypes524
-rw-r--r--src/imports/dialogs/qml/Button.qml4
-rw-r--r--src/imports/dialogs/qml/DefaultWindowDecoration.qml3
-rw-r--r--src/imports/dialogs/qml/TextField.qml9
-rw-r--r--src/imports/dialogs/qquickabstractmessagedialog.cpp41
-rw-r--r--src/imports/dialogs/qquickabstractmessagedialog_p.h3
-rw-r--r--src/imports/dialogs/qquickdialogassets_p.h (renamed from src/imports/dialogs/qquickmessageattached_p.h)24
-rw-r--r--src/imports/dialogs/qquickplatformfontdialog.cpp1
-rw-r--r--src/imports/dialogs/qquickplatformmessagedialog.cpp222
-rw-r--r--src/imports/folderlistmodel/fileinfothread.cpp12
-rw-r--r--src/imports/folderlistmodel/fileinfothread_p.h2
-rw-r--r--src/imports/folderlistmodel/folderlistmodel.pro2
-rw-r--r--src/imports/folderlistmodel/plugin.cpp1
-rw-r--r--src/imports/folderlistmodel/plugins.qmltypes11
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp50
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.h7
-rw-r--r--src/imports/localstorage/plugin.cpp38
-rw-r--r--src/imports/localstorage/plugins.qmltypes3
-rw-r--r--src/imports/particles/plugins.qmltypes3
-rw-r--r--src/imports/qtquick2/plugins.qmltypes324
-rw-r--r--src/imports/settings/plugins.qmltypes3
-rw-r--r--src/imports/settings/qqmlsettings.cpp9
-rw-r--r--src/imports/testlib/plugins.qmltypes5
-rw-r--r--src/imports/widgets/plugins.qmltypes191
-rw-r--r--src/imports/widgets/qmessageboxhelper_p.h107
-rw-r--r--src/imports/widgets/qquickqmessagebox.cpp81
-rw-r--r--src/imports/widgets/qquickqmessagebox_p.h9
-rw-r--r--src/imports/widgets/widgets.pro1
-rw-r--r--src/imports/window/plugin.cpp2
-rw-r--r--src/imports/window/plugins.qmltypes36
-rw-r--r--src/imports/xmllistmodel/plugins.qmltypes3
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel.cpp2
-rw-r--r--src/particles/particles.pri12
-rw-r--r--src/particles/particles.qrc12
-rw-r--r--src/particles/qquickcustomparticle.cpp64
-rw-r--r--src/particles/qquickimageparticle.cpp408
-rw-r--r--src/particles/qquickimageparticle_p.h9
-rw-r--r--src/particles/qquickparticlesmodule.cpp7
-rw-r--r--src/particles/qquickv4particledata.cpp28
-rw-r--r--src/particles/shaders/customparticle.frag11
-rw-r--r--src/particles/shaders/customparticle.vert4
-rw-r--r--src/particles/shaders/customparticle_core.frag13
-rw-r--r--src/particles/shaders/customparticle_core.vert4
-rw-r--r--src/particles/shaders/customparticletemplate.vert28
-rw-r--r--src/particles/shaders/customparticletemplate_core.vert28
-rw-r--r--src/particles/shaders/imageparticle.frag42
-rw-r--r--src/particles/shaders/imageparticle.vert145
-rw-r--r--src/particles/shaders/imageparticle_core.frag44
-rw-r--r--src/particles/shaders/imageparticle_core.vert145
-rw-r--r--src/plugins/accessible/quick/qaccessiblequickview.h1
-rw-r--r--src/plugins/accessible/shared/qqmlaccessible.h1
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp2
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp295
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h56
-rw-r--r--src/qml/compiler/qv4codegen.cpp737
-rw-r--r--src/qml/compiler/qv4codegen_p.h46
-rw-r--r--src/qml/compiler/qv4compileddata.cpp34
-rw-r--r--src/qml/compiler/qv4compileddata_p.h32
-rw-r--r--src/qml/compiler/qv4compiler.cpp127
-rw-r--r--src/qml/compiler/qv4compiler_p.h12
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h333
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp397
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h117
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp505
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h26
-rw-r--r--src/qml/compiler/qv4isel_p.cpp52
-rw-r--r--src/qml/compiler/qv4isel_p.h19
-rw-r--r--src/qml/compiler/qv4isel_util_p.h65
-rw-r--r--src/qml/compiler/qv4jsir.cpp95
-rw-r--r--src/qml/compiler/qv4jsir_p.h125
-rw-r--r--src/qml/compiler/qv4regalloc.cpp105
-rw-r--r--src/qml/compiler/qv4ssa.cpp452
-rw-r--r--src/qml/compiler/qv4ssa_p.h7
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp2
-rw-r--r--src/qml/debugger/qqmldebugservice.cpp27
-rw-r--r--src/qml/debugger/qqmldebugservice_p_p.h1
-rw-r--r--src/qml/debugger/qv4debugservice.cpp1108
-rw-r--r--src/qml/debugger/qv4debugservice_p.h9
-rw-r--r--src/qml/debugger/qv8profilerservice.cpp4
-rw-r--r--src/qml/doc/qtqml.qdocconf2
-rw-r--r--src/qml/doc/src/cppintegration/contextproperties.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc4
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/topic.qdoc2
-rw-r--r--src/qml/doc/src/javascript/expressions.qdoc6
-rw-r--r--src/qml/doc/src/javascript/imports.qdoc2
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc49
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/scope.qdoc2
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc30
-rw-r--r--src/qml/doc/src/whatsnew.qdoc4
-rw-r--r--src/qml/jsapi/qjsengine.cpp14
-rw-r--r--src/qml/jsapi/qjsvalue.cpp92
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp23
-rw-r--r--src/qml/jsruntime/jsruntime.pri33
-rw-r--r--src/qml/jsruntime/qv4alloca_p.h8
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp121
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h12
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp175
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h44
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4context.cpp277
-rw-r--r--src/qml/jsruntime/qv4context_p.h81
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp161
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h98
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp800
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h169
-rw-r--r--src/qml/jsruntime/qv4engine.cpp227
-rw-r--r--src/qml/jsruntime/qv4engine_cxxabi.cpp156
-rw-r--r--src/qml/jsruntime/qv4engine_p.h57
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp16
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h6
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp1
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h8
-rw-r--r--src/qml/jsruntime/qv4function.cpp61
-rw-r--r--src/qml/jsruntime/qv4function_p.h20
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp214
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h23
-rw-r--r--src/qml/jsruntime/qv4global_p.h4
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp53
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h20
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp6
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp2
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h4
-rw-r--r--src/qml/jsruntime/qv4include.cpp50
-rw-r--r--src/qml/jsruntime/qv4include_p.h2
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp51
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h98
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp65
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp57
-rw-r--r--src/qml/jsruntime/qv4managed.cpp15
-rw-r--r--src/qml/jsruntime/qv4managed_p.h10
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp49
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h36
-rw-r--r--src/qml/jsruntime/qv4mm.cpp112
-rw-r--r--src/qml/jsruntime/qv4mm_p.h15
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp41
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h12
-rw-r--r--src/qml/jsruntime/qv4object.cpp101
-rw-r--r--src/qml/jsruntime/qv4object_p.h10
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp21
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp143
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h52
-rw-r--r--src/qml/jsruntime/qv4qmlextensions.cpp4
-rw-r--r--src/qml/jsruntime/qv4qmlextensions_p.h3
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp227
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h15
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp29
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp53
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h12
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp320
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h33
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h10
-rw-r--r--src/qml/jsruntime/qv4script.cpp86
-rw-r--r--src/qml/jsruntime/qv4script_p.h6
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp22
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp10
-rw-r--r--src/qml/jsruntime/qv4sparsearray.cpp6
-rw-r--r--src/qml/jsruntime/qv4string.cpp94
-rw-r--r--src/qml/jsruntime/qv4string_p.h49
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp111
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h42
-rw-r--r--src/qml/jsruntime/qv4unwindhelper.cpp82
-rw-r--r--src/qml/jsruntime/qv4unwindhelper_arm_p.h234
-rw-r--r--src/qml/jsruntime/qv4unwindhelper_dw2_p.h191
-rw-r--r--src/qml/jsruntime/qv4value.cpp24
-rw-r--r--src/qml/jsruntime/qv4value_def_p.h60
-rw-r--r--src/qml/jsruntime/qv4value_p.h20
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp388
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h2
-rw-r--r--src/qml/qml.pro3
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp131
-rw-r--r--src/qml/qml/qml.pri2
-rw-r--r--src/qml/qml/qqml.h18
-rw-r--r--src/qml/qml/qqmlabstractbinding.cpp3
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.cpp3
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor_p.h (renamed from src/qml/qml/qqmlabstracturlinterceptor.h)4
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp2
-rw-r--r--src/qml/qml/qqmlbinding.cpp10
-rw-r--r--src/qml/qml/qqmlbinding_p.h8
-rw-r--r--src/qml/qml/qqmlcompiler.cpp90
-rw-r--r--src/qml/qml/qqmlcompiler_p.h12
-rw-r--r--src/qml/qml/qqmlcomponent.cpp64
-rw-r--r--src/qml/qml/qqmlcontext.cpp2
-rw-r--r--src/qml/qml/qqmlcontext_p.h2
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp137
-rw-r--r--src/qml/qml/qqmlcontextwrapper_p.h25
-rw-r--r--src/qml/qml/qqmldata_p.h5
-rw-r--r--src/qml/qml/qqmldirparser.cpp18
-rw-r--r--src/qml/qml/qqmlengine.cpp26
-rw-r--r--src/qml/qml/qqmlengine_p.h15
-rw-r--r--src/qml/qml/qqmlfileselector.cpp69
-rw-r--r--src/qml/qml/qqmlfileselector.h12
-rw-r--r--src/qml/qml/qqmlfileselector_p.h14
-rw-r--r--src/qml/qml/qqmlimport.cpp11
-rw-r--r--src/qml/qml/qqmlinstruction_p.h11
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp52
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h13
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp6
-rw-r--r--src/qml/qml/qqmllocale.cpp176
-rw-r--r--src/qml/qml/qqmllocale_p.h22
-rw-r--r--src/qml/qml/qqmlmetatype.cpp8
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp27
-rw-r--r--src/qml/qml/qqmlproperty.cpp2
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp2
-rw-r--r--src/qml/qml/qqmlscript.cpp10
-rw-r--r--src/qml/qml/qqmlscript_p.h3
-rw-r--r--src/qml/qml/qqmltypeloader.cpp70
-rw-r--r--src/qml/qml/qqmltypeloader_p.h2
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp2
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp30
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h5
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp22
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvme.cpp14
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp21
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp265
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp154
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h106
-rw-r--r--src/qml/qml/v8/qv4domerrors_p.h2
-rw-r--r--src/qml/qml/v8/qv8engine.cpp9
-rw-r--r--src/qml/qml/v8/qv8engine_p.h4
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp38
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h6
-rw-r--r--src/qml/types/qqmlinstantiator.cpp2
-rw-r--r--src/qml/types/qqmltimer.cpp2
-rw-r--r--src/qml/types/qquickpackage.cpp3
-rw-r--r--src/qml/types/qquickworkerscript.cpp49
-rw-r--r--src/qml/util/qqmladaptormodel.cpp38
-rw-r--r--src/qml/util/qqmllistcompositor.cpp2
-rw-r--r--src/qmldevtools/qmldevtools.pro8
-rw-r--r--src/quick/designer/designerwindowmanager.cpp9
-rw-r--r--src/quick/designer/designerwindowmanager_p.h4
-rw-r--r--src/quick/doc/images/qml-xmllistmodel-example.pngbin0 -> 5252 bytes
-rw-r--r--src/quick/doc/qtquick.qdocconf2
-rw-r--r--src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc2
-rw-r--r--src/quick/doc/src/concepts/positioning/layouts.qdoc2
-rw-r--r--src/quick/doc/src/concepts/positioning/righttoleft.qdoc2
-rw-r--r--src/quick/doc/src/concepts/statesanimations/animations.qdoc16
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc5
-rw-r--r--src/quick/doc/src/cppextensionpoints.qdoc6
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc33
-rw-r--r--src/quick/doc/src/qtquick.qdoc61
-rw-r--r--src/quick/doc/src/tutorial.qdoc1
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp374
-rw-r--r--src/quick/items/items.pri17
-rw-r--r--src/quick/items/items.qrc16
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp55
-rw-r--r--src/quick/items/qquickborderimage.cpp10
-rw-r--r--src/quick/items/qquickflickable.cpp6
-rw-r--r--src/quick/items/qquickgridview.cpp2
-rw-r--r--src/quick/items/qquickimage.cpp16
-rw-r--r--src/quick/items/qquickitem.cpp11
-rw-r--r--src/quick/items/qquickitem_p.h7
-rw-r--r--src/quick/items/qquickitemanimation.cpp2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp11
-rw-r--r--src/quick/items/qquickitemview.cpp2
-rw-r--r--src/quick/items/qquicklistview.cpp5
-rw-r--r--src/quick/items/qquickmousearea.cpp2
-rw-r--r--src/quick/items/qquickpainteditem.cpp2
-rw-r--r--src/quick/items/qquickpathview.cpp4
-rw-r--r--src/quick/items/qquickscreen.cpp51
-rw-r--r--src/quick/items/qquickscreen_p.h3
-rw-r--r--src/quick/items/qquickshadereffect.cpp34
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp22
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp50
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h7
-rw-r--r--src/quick/items/qquicksprite.cpp2
-rw-r--r--src/quick/items/qquickspritesequence.cpp55
-rw-r--r--src/quick/items/qquicktext.cpp32
-rw-r--r--src/quick/items/qquicktextedit.cpp5
-rw-r--r--src/quick/items/qquicktextinput.cpp19
-rw-r--r--src/quick/items/qquicktextinput_p.h1
-rw-r--r--src/quick/items/qquicktextnode.cpp21
-rw-r--r--src/quick/items/qquicktextnode_p.h3
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp4
-rw-r--r--src/quick/items/qquicktranslate.cpp2
-rw-r--r--src/quick/items/qquickwindow.cpp128
-rw-r--r--src/quick/items/qquickwindow.h6
-rw-r--r--src/quick/items/qquickwindow_p.h3
-rw-r--r--src/quick/items/shaders/shadereffect.frag9
-rw-r--r--src/quick/items/shaders/shadereffect.vert12
-rw-r--r--src/quick/items/shaders/shadereffect_core.frag13
-rw-r--r--src/quick/items/shaders/shadereffect_core.vert14
-rw-r--r--src/quick/items/shaders/shadereffectfallback.frag4
-rw-r--r--src/quick/items/shaders/shadereffectfallback.vert8
-rw-r--r--src/quick/items/shaders/shadereffectfallback_core.frag8
-rw-r--r--src/quick/items/shaders/shadereffectfallback_core.vert10
-rw-r--r--src/quick/items/shaders/sprite.frag12
-rw-r--r--src/quick/items/shaders/sprite.vert23
-rw-r--r--src/quick/items/shaders/sprite_core.frag16
-rw-r--r--src/quick/items/shaders/sprite_core.vert24
-rw-r--r--src/quick/qtquick2.cpp7
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp175
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h31
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp63
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.h15
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader_p.h61
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater.cpp9
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater_p.h5
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp32
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h8
-rw-r--r--src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp29
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp5
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h4
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp591
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h107
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp142
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h10
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp168
-rw-r--r--src/quick/scenegraph/qsgdefaultimagenode.cpp76
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode.cpp66
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode.cpp9
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp250
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.h6
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h1
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp32
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h3
-rw-r--r--src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp1
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp681
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h30
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp29
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop_p.h7
-rw-r--r--src/quick/scenegraph/scenegraph.pri85
-rw-r--r--src/quick/scenegraph/scenegraph.qrc68
-rw-r--r--src/quick/scenegraph/shaders/24bittextmask.frag10
-rw-r--r--src/quick/scenegraph/shaders/24bittextmask_core.frag14
-rw-r--r--src/quick/scenegraph/shaders/8bittextmask.frag9
-rw-r--r--src/quick/scenegraph/shaders/8bittextmask_core.frag13
-rw-r--r--src/quick/scenegraph/shaders/distancefieldoutlinetext.frag16
-rw-r--r--src/quick/scenegraph/shaders/distancefieldoutlinetext_core.frag20
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext.frag17
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext.vert17
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext_core.frag20
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext_core.vert18
-rw-r--r--src/quick/scenegraph/shaders/distancefieldtext.frag13
-rw-r--r--src/quick/scenegraph/shaders/distancefieldtext.vert13
-rw-r--r--src/quick/scenegraph/shaders/distancefieldtext_core.frag16
-rw-r--r--src/quick/scenegraph/shaders/distancefieldtext_core.vert15
-rw-r--r--src/quick/scenegraph/shaders/flatcolor.frag6
-rw-r--r--src/quick/scenegraph/shaders/flatcolor.vert7
-rw-r--r--src/quick/scenegraph/shaders/flatcolor_core.frag10
-rw-r--r--src/quick/scenegraph/shaders/flatcolor_core.vert10
-rw-r--r--src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag58
-rw-r--r--src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert34
-rw-r--r--src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.frag32
-rw-r--r--src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.vert36
-rw-r--r--src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.frag17
-rw-r--r--src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.vert27
-rw-r--r--src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.frag21
-rw-r--r--src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.vert29
-rw-r--r--src/quick/scenegraph/shaders/opaquetexture.frag8
-rw-r--r--src/quick/scenegraph/shaders/opaquetexture.vert12
-rw-r--r--src/quick/scenegraph/shaders/opaquetexture_core.frag12
-rw-r--r--src/quick/scenegraph/shaders/opaquetexture_core.vert14
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext.frag21
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext.vert22
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext_core.frag25
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext_core.vert24
-rw-r--r--src/quick/scenegraph/shaders/rendernode.frag8
-rw-r--r--src/quick/scenegraph/shaders/rendernode.vert10
-rw-r--r--src/quick/scenegraph/shaders/rendernode_core.frag12
-rw-r--r--src/quick/scenegraph/shaders/rendernode_core.vert12
-rw-r--r--src/quick/scenegraph/shaders/smoothcolor.frag6
-rw-r--r--src/quick/scenegraph/shaders/smoothcolor.vert45
-rw-r--r--src/quick/scenegraph/shaders/smoothcolor_core.frag10
-rw-r--r--src/quick/scenegraph/shaders/smoothcolor_core.vert47
-rw-r--r--src/quick/scenegraph/shaders/smoothtexture.frag9
-rw-r--r--src/quick/scenegraph/shaders/smoothtexture.vert52
-rw-r--r--src/quick/scenegraph/shaders/smoothtexture_core.frag13
-rw-r--r--src/quick/scenegraph/shaders/smoothtexture_core.vert54
-rw-r--r--src/quick/scenegraph/shaders/stencilclip.frag4
-rw-r--r--src/quick/scenegraph/shaders/stencilclip.vert8
-rw-r--r--src/quick/scenegraph/shaders/stencilclip_core.frag8
-rw-r--r--src/quick/scenegraph/shaders/stencilclip_core.vert10
-rw-r--r--src/quick/scenegraph/shaders/styledtext.frag14
-rw-r--r--src/quick/scenegraph/shaders/styledtext.vert16
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.frag18
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.vert18
-rw-r--r--src/quick/scenegraph/shaders/textmask.frag10
-rw-r--r--src/quick/scenegraph/shaders/textmask.vert13
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.frag14
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.vert15
-rw-r--r--src/quick/scenegraph/shaders/texture.frag9
-rw-r--r--src/quick/scenegraph/shaders/texture_core.frag13
-rw-r--r--src/quick/scenegraph/shaders/vertexcolor.frag6
-rw-r--r--src/quick/scenegraph/shaders/vertexcolor.vert13
-rw-r--r--src/quick/scenegraph/shaders/vertexcolor_core.frag10
-rw-r--r--src/quick/scenegraph/shaders/vertexcolor_core.vert15
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp51
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture_p.h10
-rw-r--r--src/quick/scenegraph/util/qsgflatcolormaterial.cpp29
-rw-r--r--src/quick/scenegraph/util/qsgpainternode.cpp6
-rw-r--r--src/quick/scenegraph/util/qsgpainternode_p.h2
-rw-r--r--src/quick/scenegraph/util/qsgshadersourcebuilder.cpp403
-rw-r--r--src/quick/scenegraph/util/qsgshadersourcebuilder_p.h82
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp16
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp50
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial_p.h8
-rw-r--r--src/quick/scenegraph/util/qsgvertexcolormaterial.cpp33
-rw-r--r--src/quick/util/qquickanimation.cpp19
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp187
-rw-r--r--src/quick/util/qquickanimatorcontroller_p.h63
-rw-r--r--src/quick/util/qquickanimatorjob.cpp108
-rw-r--r--src/quick/util/qquickanimatorjob_p.h12
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp5
-rw-r--r--src/quick/util/qquickspringanimation.cpp5
-rw-r--r--src/src.pro2
-rw-r--r--tests/auto/auto.pro2
-rw-r--r--tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp51
-rw-r--r--tests/auto/qml/debugger/debugger.pro2
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp3
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp406
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp7
-rw-r--r--tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp1
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugclient.cpp1
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/idAsLValue.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/misctypetest.qml28
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug34792.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_33754.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_34493.qml19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/setPropertyOnNull.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/setPropertyOnUndefined.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/singletonTest.qml48
-rw-r--r--tests/auto/qml/qqmlecmascript/data/singletonTest2.qml74
-rw-r--r--tests/auto/qml/qqmlecmascript/data/thisObject.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/updateCall.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.cpp40
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h30
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp278
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/imports/Test.2/qmldir1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/module/intercepted/Intercepted.qml9
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/module/intercepted/comment1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/module/intercepted/qmldir1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/module/urlInterceptor.qml3
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp19
-rw-r--r--tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp22
-rw-r--r--tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml18
-rw-r--r--tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro1
-rw-r--r--tests/auto/qml/qqmlinstantiator/stringmodel.h126
-rw-r--r--tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp24
-rw-r--r--tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp7
-rw-r--r--tests/auto/qml/qqmllanguage/data/singleton/+basicSelector/SingletonType.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/singleton/RegisteredCompositeSingletonType.qml (renamed from examples/quick/demos/samegame/content/settings.js)28
-rw-r--r--tests/auto/qml/qqmllanguage/data/singletonTest17.qml (renamed from examples/quick/demos/samegame/content/+blackberry/settings.js)21
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp33
-rw-r--r--tests/auto/qml/qqmllocale/tst_qqmllocale.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/.gitignore2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.2.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.errors.txt2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.qml4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/importsNested.2.qml4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.errors.txt2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.qml4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/incorrectCase.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/pluginWithQmlFile.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.errors.txt2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.errors.txt2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/works.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/works2.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/works21.qml2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/ComponentA.qml (renamed from tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/ComponentA.qml)0
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/ComponentB.qml (renamed from tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/ComponentB.qml)0
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/qmldir (renamed from tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/qmldir)0
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/invalidFirstCommandModule.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/invalidNamespaceModule.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/nonstrictModule/nonstrictModule.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.2.1.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.2.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin/plugin.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginMixed/pluginMixed.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginVersion/pluginVersion.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/pluginWithQmlFile.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/pluginWrongCase.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/preemptedStrictModule.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp6
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/preemptiveModule/preemptiveModule.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/strictModule/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/strictModule/strictModule.pro2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp58
-rw-r--r--tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp3
-rw-r--r--tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp18
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp295
-rw-r--r--tests/auto/qml/qv4debugger/tst_qv4debugger.cpp271
-rw-r--r--tests/auto/qmltest/fontloader/tst_fontloader.qml6
-rw-r--r--tests/auto/quick/nodes/tst_nodestest.cpp20
-rw-r--r--tests/auto/quick/nokeywords/tst_nokeywords.cpp1
-rw-r--r--tests/auto/quick/qquickanimations/data/parallelAnimationNullChildBug.qml6
-rw-r--r--tests/auto/quick/qquickanimations/data/sequentialAnimationNullChildBug.qml6
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp26
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp25
-rw-r--r--tests/auto/quick/qquickitem2/data/keynavigationtest_focusscope.qml93
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp12
-rw-r--r--tests/auto/quick/qquicklistview/data/headerchangesviewport.qml19
-rw-r--r--tests/auto/quick/qquicklistview/data/typedModel.qml23
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp50
-rw-r--r--tests/auto/quick/qquickmousearea/data/qtbug34368.qml38
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp23
-rw-r--r--tests/auto/quick/qquickspringanimation/data/inTransition.qml22
-rw-r--r--tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp10
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp2
-rw-r--r--tests/auto/quick/qquicktext/data/hover.qml22
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp28
-rw-r--r--tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml13
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp45
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp14
-rw-r--r--tests/auto/quick/rendernode/data/RenderOrder.qml4
-rw-r--r--tests/auto/quick/rendernode/rendernode.pro1
-rw-r--r--tests/auto/quick/rendernode/tst_rendernode.cpp40
-rw-r--r--tests/auto/quick/scenegraph/data/RenderTestBase.qml84
-rw-r--r--tests/auto/quick/scenegraph/data/logo-big.jpgbin0 -> 14174 bytes
-rw-r--r--tests/auto/quick/scenegraph/data/logo-small.jpgbin0 -> 691 bytes
-rw-r--r--tests/auto/quick/scenegraph/data/manyWindows_dftext.qml (renamed from src/quick/scenegraph/qsgflashnode_p.h)29
-rw-r--r--tests/auto/quick/scenegraph/data/manyWindows_image.qml (renamed from src/quick/scenegraph/qsgflashnode.cpp)28
-rw-r--r--tests/auto/quick/scenegraph/data/manyWindows_ntext.qml (renamed from src/qml/jsruntime/qv4unwindhelper_p.h)37
-rw-r--r--tests/auto/quick/scenegraph/data/manyWindows_rects.qml70
-rw-r--r--tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml83
-rw-r--r--tests/auto/quick/scenegraph/data/render_DrawSets.qml113
-rw-r--r--tests/auto/quick/scenegraph/data/render_MovingOverlap.qml109
-rw-r--r--tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml108
-rw-r--r--tests/auto/quick/scenegraph/data/render_Overlap.qml88
-rw-r--r--tests/auto/quick/scenegraph/data/render_StackingOrder.qml65
-rw-r--r--tests/auto/quick/scenegraph/scenegraph.pro14
-rw-r--r--tests/auto/quick/scenegraph/tst_scenegraph.cpp407
-rw-r--r--tests/auto/shared/testhttpserver.cpp53
-rw-r--r--tests/auto/shared/testhttpserver.h9
-rw-r--r--tools/qml/main.cpp197
-rw-r--r--tools/qml/qml.pro5
-rw-r--r--tools/qmlimportscanner/main.cpp224
-rw-r--r--tools/qmlimportscanner/qmlimportscanner.pro9
-rw-r--r--tools/qmljs/main.cpp22
-rw-r--r--tools/qmljs/qmljs.pro2
-rw-r--r--tools/qmlmin/qmlmin.pro10
-rw-r--r--tools/tools.pro36
620 files changed, 19085 insertions, 8915 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 43c664e01f..88d13d1eef 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -3,21 +3,3 @@ CONFIG += qt_example_installs
CONFIG += warning_clean
MODULE_VERSION = 5.3.0
-
-# For the JS engine we need to be able to produce back traces,
-# and as we're using the C stack, we need the system to be able
-# to walk it properly. Unfortunately on Windows with i386 there
-# are no unwind tables, that can compensate for an omitted frame
-# pointer, so we have no choice but to disable the frame pointer
-# omission optimizations.
-# Only within the qtdeclarative module we support throwing V4
-# exceptions, hence the choice of applying this change here.
-win32:equals(QT_ARCH, "i386") {
- *msvc*: QMAKE_CXXFLAGS += -Oy-
- *g++*: QMAKE_CXXFLAGS += -fno-omit-frame-pointer
-}
-
-# Any code within this module has access to the private V4 API and
-# can therefore be subject to exception traversal. Support for exceptions
-# is therefore required, especially with older toolchains.
-CONFIG += exceptions
diff --git a/dist/changes-5.2.0 b/dist/changes-5.2.0
index 969d4e30e6..8b044d6932 100644
--- a/dist/changes-5.2.0
+++ b/dist/changes-5.2.0
@@ -42,6 +42,17 @@ Third party components
flag QSGNode::DirtySubtreeBlocked whenever the state of
QSGNode::isSubtreeBlocked() is changed.
+ - When assigning double precision floating point values to integer properties,
+ the engine now truncates instead of rounding. This is consistent with the
+ ECMAScript specification's way of converting doubles to ints.
+
+ - Comparing value based types with the JS strictly equal operator will
+ now behave similar to the corresponding C++ == operator. Ie. two
+ QPoints exposed on the JS side will be strictly equal if their values
+ are equal. This brings the behavior of value based types in JS closer
+ to what one would expect and more inline with primitive values in
+ Javascript.
+
****************************************************************************
* Library *
****************************************************************************
@@ -49,6 +60,10 @@ Third party components
QtQml
------
+- New class QQmlFileSelectors allows applying a QFileSelector to QML assets
+ and types. One is automatically set on QQmlApplicationEngines from now on,
+ plain QQmlEngines must set their own in order to be affected.
+
QtQuick
------
diff --git a/examples/quick/demos/samegame/content/+blackberry/Settings.qml b/examples/quick/demos/samegame/content/+blackberry/Settings.qml
new file mode 100644
index 0000000000..be747691ce
--- /dev/null
+++ b/examples/quick/demos/samegame/content/+blackberry/Settings.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** 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$
+**
+****************************************************************************/
+
+pragma Singleton
+import QtQml 2.0
+
+// Instantiating a BBSettings class that can be easily tweaked for future
+// BB devices (we may have more selectors added)
+BBSettings {
+}
diff --git a/examples/quick/demos/samegame/content/BBSettings.qml b/examples/quick/demos/samegame/content/BBSettings.qml
new file mode 100644
index 0000000000..ea1c70e50d
--- /dev/null
+++ b/examples/quick/demos/samegame/content/BBSettings.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** 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$
+**
+****************************************************************************/
+
+import QtQml 2.0
+
+QtObject {
+ // This height/width is here for desktop testing, otherwise
+ // we could just use Screen.width/Screen.height.
+ property int screenHeight: 1280
+ property int screenWidth: 768
+
+ property int menuDelay: 500
+
+ property int headerHeight: 70
+ property int footerHeight: 100
+
+ property int fontPixelSize: 55
+
+ property int blockSize: 64
+
+ property int toolButtonHeight: 64
+
+ property int menuButtonSpacing: 15
+}
diff --git a/examples/quick/demos/samegame/content/BlockEmitter.qml b/examples/quick/demos/samegame/content/BlockEmitter.qml
index 49ee38d376..a38deaf941 100644
--- a/examples/quick/demos/samegame/content/BlockEmitter.qml
+++ b/examples/quick/demos/samegame/content/BlockEmitter.qml
@@ -40,8 +40,8 @@
import QtQuick 2.0
import QtQuick.Particles 2.0
-
-import "settings.js" as Settings
+// Needed for singletons QTBUG-34418
+import "."
Emitter {
property Item block: parent
diff --git a/examples/quick/demos/samegame/content/GameArea.qml b/examples/quick/demos/samegame/content/GameArea.qml
index 6e72161320..cf66014fa3 100644
--- a/examples/quick/demos/samegame/content/GameArea.qml
+++ b/examples/quick/demos/samegame/content/GameArea.qml
@@ -41,6 +41,7 @@
import QtQuick 2.0
import QtQuick.Particles 2.0
import "samegame.js" as Logic
+import "."
Item {
id: gameCanvas
@@ -54,6 +55,7 @@ Item {
property alias backgroundVisible: bg.visible
property string background: "gfx/background.png"
property string blockFile: "Block.qml"
+ property int blockSize: Settings.blockSize
onBlockFileChanged: Logic.changeBlock(blockFile);
property alias particlePack: auxLoader.source
//For multiplayer
diff --git a/examples/quick/demos/samegame/content/PaintEmitter.qml b/examples/quick/demos/samegame/content/PaintEmitter.qml
index 85d148de92..dcf68f511d 100644
--- a/examples/quick/demos/samegame/content/PaintEmitter.qml
+++ b/examples/quick/demos/samegame/content/PaintEmitter.qml
@@ -40,7 +40,7 @@
import QtQuick 2.0
import QtQuick.Particles 2.0
-import "settings.js" as Settings
+import "."
Emitter {
property Item block: parent
diff --git a/examples/quick/demos/samegame/content/SamegameText.qml b/examples/quick/demos/samegame/content/SamegameText.qml
index e3bee989fb..2d36e6adab 100644
--- a/examples/quick/demos/samegame/content/SamegameText.qml
+++ b/examples/quick/demos/samegame/content/SamegameText.qml
@@ -39,7 +39,7 @@
****************************************************************************/
import QtQuick 2.0
-import "settings.js" as Settings
+import "."
Text {
font.pixelSize: Settings.fontPixelSize;
diff --git a/examples/quick/demos/samegame/content/Settings.qml b/examples/quick/demos/samegame/content/Settings.qml
new file mode 100644
index 0000000000..d21170df53
--- /dev/null
+++ b/examples/quick/demos/samegame/content/Settings.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** 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$
+**
+****************************************************************************/
+
+pragma Singleton
+import QtQml 2.0
+
+QtObject {
+ property int screenHeight: 480
+ property int screenWidth: 320
+
+ property int menuDelay: 500
+
+ property int headerHeight: 20 // 70 on BB10
+ property int footerHeight: 44 // 100 on BB10
+
+ property int fontPixelSize: 14 // 55 on BB10
+
+ property int blockSize: 32 // 64 on BB10
+
+ property int toolButtonHeight: 32 // 64 on BB10
+
+ property int menuButtonSpacing: 0 // 15 on BB10
+}
diff --git a/examples/quick/demos/samegame/content/qmldir b/examples/quick/demos/samegame/content/qmldir
new file mode 100644
index 0000000000..727989d006
--- /dev/null
+++ b/examples/quick/demos/samegame/content/qmldir
@@ -0,0 +1,14 @@
+singleton Settings 1.0 Settings.qml
+BBSettings 1.0 BBSettings.qml
+Block 1.0 Block.qml
+BlockEmitter 1.0 BlockEmitter.qml
+Button 1.0 Button.qml
+GameArea 1.0 GameArea.qml
+LogoAnimation 1.0 LogoAnimation.qml
+MenuEmitter 1.0 MenuEmitter.qml
+PaintEmitter 1.0 PaintEmitter.qml
+PrimaryPack 1.0 PrimaryPack.qml
+PuzzleBlock 1.0 PuzzleBlock.qml
+SamegameText 1.0 SamegameText.qml
+SimpleBlock 1.0 SimpleBlock.qml
+SmokeText 1.0 SmokeText.qml
diff --git a/examples/quick/demos/samegame/content/samegame.js b/examples/quick/demos/samegame/content/samegame.js
index 5bb24d70db..99154320ca 100755
--- a/examples/quick/demos/samegame/content/samegame.js
+++ b/examples/quick/demos/samegame/content/samegame.js
@@ -41,7 +41,6 @@
/* This script file handles the game logic */
.pragma library
.import QtQuick.LocalStorage 2.0 as Sql
-.import "settings.js" as Settings
var maxColumn = 10;
var maxRow = 13;
@@ -111,8 +110,8 @@ function startNewGame(gc, mode, map)
gc.gameOver = false;
gc.mode = gameMode;
// Calculate board size
- maxColumn = Math.floor(gameCanvas.width/Settings.blockSize);
- maxRow = Math.floor(gameCanvas.height/Settings.blockSize);
+ maxColumn = Math.floor(gameCanvas.width/gameCanvas.blockSize);
+ maxRow = Math.floor(gameCanvas.height/gameCanvas.blockSize);
maxIndex = maxRow * maxColumn;
if (gameMode == "arcade") //Needs to be after board sizing
getHighScore();
@@ -143,8 +142,8 @@ function handleClick(x,y)
{
if (betweenTurns || gameOver || gameCanvas == undefined)
return;
- var column = Math.floor(x/Settings.blockSize);
- var row = Math.floor(y/Settings.blockSize);
+ var column = Math.floor(x/gameCanvas.blockSize);
+ var row = Math.floor(y/gameCanvas.blockSize);
if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
return;
if (board[index(column, row)] == null)
@@ -212,7 +211,7 @@ function shuffleDown()
} else {
if (fallDist > 0) {
var obj = board[index(column, row)];
- obj.y = (row + fallDist) * Settings.blockSize;
+ obj.y = (row + fallDist) * gameCanvas.blockSize;
board[index(column, row + fallDist)] = obj;
board[index(column, row)] = null;
}
@@ -230,7 +229,7 @@ function shuffleDown()
obj = board[index(column, row)];
if (obj == null)
continue;
- obj.x = (column - fallDist) * Settings.blockSize;
+ obj.x = (column - fallDist) * gameCanvas.blockSize;
board[index(column - fallDist,row)] = obj;
board[index(column, row)] = null;
}
@@ -251,7 +250,7 @@ function shuffleUp()
} else {
if (fallDist > 0) {
var obj = board[index(column, row)];
- obj.y = (row - fallDist) * Settings.blockSize;
+ obj.y = (row - fallDist) * gameCanvas.blockSize;
board[index(column, row - fallDist)] = obj;
board[index(column, row)] = null;
}
@@ -269,7 +268,7 @@ function shuffleUp()
obj = board[index(column, row)];
if (obj == null)
continue;
- obj.x = (column - fallDist) * Settings.blockSize;
+ obj.x = (column - fallDist) * gameCanvas.blockSize;
board[index(column - fallDist,row)] = obj;
board[index(column, row)] = null;
}
@@ -372,17 +371,17 @@ function createBlock(column,row,type)
}
var dynamicObject = component.createObject(gameCanvas,
{"type": type,
- "x": column*Settings.blockSize,
- "y": -1*Settings.blockSize,
- "width": Settings.blockSize,
- "height": Settings.blockSize,
+ "x": column*gameCanvas.blockSize,
+ "y": -1*gameCanvas.blockSize,
+ "width": gameCanvas.blockSize,
+ "height": gameCanvas.blockSize,
"particleSystem": gameCanvas.ps});
if (dynamicObject == null){
console.log("error creating block");
console.log(component.errorString());
return false;
}
- dynamicObject.y = row*Settings.blockSize;
+ dynamicObject.y = row*gameCanvas.blockSize;
dynamicObject.spawned = true;
board[index(column,row)] = dynamicObject;
diff --git a/examples/quick/demos/samegame/samegame.qml b/examples/quick/demos/samegame/samegame.qml
index 23cdf94acc..b9c3876ded 100644
--- a/examples/quick/demos/samegame/samegame.qml
+++ b/examples/quick/demos/samegame/samegame.qml
@@ -41,12 +41,11 @@
import QtQuick 2.0
import QtQuick.Particles 2.0
import "content/samegame.js" as Logic
-import "content/settings.js" as Settings
import "content"
Rectangle {
id: root
- width: 320; height: 480
+ width: Settings.screenWidth; height: Settings.screenHeight
property int acc: 0
@@ -119,6 +118,8 @@ Rectangle {
Column {
y: 100 + 40
spacing: Settings.menuButtonSpacing
+ width: parent.width
+ height: parent.height - (140 + Settings.footerHeight)
Button {
width: root.width
diff --git a/examples/quick/demos/samegame/samegame.qrc b/examples/quick/demos/samegame/samegame.qrc
index 40b7cb6478..e51d3fae05 100644
--- a/examples/quick/demos/samegame/samegame.qrc
+++ b/examples/quick/demos/samegame/samegame.qrc
@@ -1,8 +1,10 @@
<RCC>
<qresource prefix="/demos/samegame">
<file>samegame.qml</file>
- <file>content/settings.js</file>
- <file>content/+blackberry/settings.js</file>
+ <file>content/qmldir</file>
+ <file>content/Settings.qml</file>
+ <file>content/BBSettings.qml</file>
+ <file>content/+blackberry/Settings.qml</file>
<file>content/gfx/text-p1-won.png</file>
<file>content/gfx/background-puzzle.png</file>
<file>content/gfx/background.png</file>
diff --git a/examples/quick/demos/stocqt/content/StockChart.qml b/examples/quick/demos/stocqt/content/StockChart.qml
index 8235b5a632..f7e0d0206b 100644
--- a/examples/quick/demos/stocqt/content/StockChart.qml
+++ b/examples/quick/demos/stocqt/content/StockChart.qml
@@ -48,8 +48,8 @@ Rectangle {
property var _months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]
property var stockModel: null
- property var startDate
- property var endDate
+ property var startDate: new Date()
+ property var endDate: new Date()
property var settings
function update() {
@@ -228,6 +228,7 @@ Rectangle {
last = stockModel.indexOf(chart.endDate)
first = last - (chart.endDate.getTime() - chart.startDate.getTime())/86400000;
+ first = Math.max(first, 0);
console.log("painting... first:" + first + ", last:" + last);
var highestPrice = stockModel.highestPrice;
diff --git a/examples/quick/demos/stocqt/content/StockModel.qml b/examples/quick/demos/stocqt/content/StockModel.qml
index d127afc5c5..f9ed9c87d4 100644
--- a/examples/quick/demos/stocqt/content/StockModel.qml
+++ b/examples/quick/demos/stocqt/content/StockModel.qml
@@ -122,11 +122,14 @@ ListModel {
}
function updateStock() {
- var xhr = new XMLHttpRequest;
-
var req = requestUrl();
- xhr.open("GET", req);
+ if (!req)
+ return;
+
+ var xhr = new XMLHttpRequest;
+
+ xhr.open("GET", req, true);
model.ready = false;
model.clear();
@@ -145,7 +148,7 @@ ListModel {
if (model.count > 0) {
model.ready = true;
model.stockPrice = model.get(0).adjusted;
- model.stockPriceChanged = Math.round((model.stockPrice - model.get(2).adjusted) * 100) / 100;
+ model.stockPriceChanged = model.count > 1 ? (Math.round((model.stockPrice - model.get(1).close) * 100) / 100) : 0;
model.dataReady(); //emit signal
}
}
diff --git a/examples/quick/demos/stocqt/content/StockView.qml b/examples/quick/demos/stocqt/content/StockView.qml
index eefcf0aeb4..ce55fdf3d3 100644
--- a/examples/quick/demos/stocqt/content/StockView.qml
+++ b/examples/quick/demos/stocqt/content/StockView.qml
@@ -53,6 +53,8 @@ Rectangle {
signal settingsClicked
function update() {
+ if (!settings)
+ return;
chart.endDate = settings.endDate
chart.update()
}
diff --git a/examples/quick/demos/stocqt/stocqt.qml b/examples/quick/demos/stocqt/stocqt.qml
index 9bcffd972f..3e231ab8bf 100644
--- a/examples/quick/demos/stocqt/stocqt.qml
+++ b/examples/quick/demos/stocqt/stocqt.qml
@@ -52,17 +52,23 @@ ListView {
boundsBehavior: Flickable.StopAtBounds
currentIndex: 1
+ Timer {
+ id: updateTimer
+ interval: 500
+ onTriggered: stock.updateStock()
+ }
+
StockModel {
id: stock
stockId: listView.currentStockId
stockName: listView.currentStockName
startDate: settings.startDate
endDate: settings.endDate
- onStockIdChanged: updateStock()
- onStartDateChanged: updateStock()
- onEndDateChanged: updateStock()
+ onStockIdChanged: updateTimer.restart()
+ onStartDateChanged: updateTimer.restart()
+ onEndDateChanged: updateTimer.restart()
onDataReady: {
- root.currentIndex = 1
+ root.positionViewAtIndex(1, ListView.SnapPosition)
stockView.update()
}
}
diff --git a/examples/quick/dialogs/systemdialogs/FileDialogs.qml b/examples/quick/dialogs/systemdialogs/FileDialogs.qml
index dca47ae1fd..bfc160fa45 100644
--- a/examples/quick/dialogs/systemdialogs/FileDialogs.qml
+++ b/examples/quick/dialogs/systemdialogs/FileDialogs.qml
@@ -175,16 +175,6 @@ Rectangle {
// TODO: QTBUG-29814 This isn't portable, but we don't expose QDir::tempPath to QML yet.
onClicked: fileDialog.folder = "/tmp" // file:///tmp would also be OK
}
- Button {
- text: "set geometry"
- anchors.verticalCenter: parent.verticalCenter
- onClicked: {
- fileDialog.width = Math.min(512, Screen.width * 0.9)
- fileDialog.height = Math.min(340, Screen.height * 0.9)
- fileDialog.x = (Screen.width - fileDialog.width) / 2
- fileDialog.y = (Screen.height - fileDialog.height) / 2
- }
- }
}
}
}
diff --git a/examples/quick/dialogs/systemdialogs/MessageDialogs.qml b/examples/quick/dialogs/systemdialogs/MessageDialogs.qml
index e6fdf57e0d..9c70228046 100644
--- a/examples/quick/dialogs/systemdialogs/MessageDialogs.qml
+++ b/examples/quick/dialogs/systemdialogs/MessageDialogs.qml
@@ -61,12 +61,12 @@ Rectangle {
detailedText: customizeDetailedText.checked ? detailedTextField.text : ""
onButtonClicked: console.log("clicked button " + clickedButton)
onAccepted: lastChosen.text = "Accepted " +
- (clickedButton == Message.Ok ? "(OK)" : (clickedButton == Message.Retry ? "(Retry)" : "(Ignore)"))
+ (clickedButton == StandardButton.Ok ? "(OK)" : (clickedButton == StandardButton.Retry ? "(Retry)" : "(Ignore)"))
onRejected: lastChosen.text = "Rejected " +
- (clickedButton == Message.Close ? "(Close)" : (clickedButton == Message.Abort ? "(Abort)" : "(Cancel)"))
+ (clickedButton == StandardButton.Close ? "(Close)" : (clickedButton == StandardButton.Abort ? "(Abort)" : "(Cancel)"))
onHelp: lastChosen.text = "Yelped for help!"
- onYes: lastChosen.text = (clickedButton == Message.Yes ? "Yeessss!!" : "Yes, now and always")
- onNo: lastChosen.text = (clickedButton == Message.No ? "Oh No." : "No, no, a thousand times no!")
+ onYes: lastChosen.text = (clickedButton == StandardButton.Yes ? "Yeessss!!" : "Yes, now and always")
+ onNo: lastChosen.text = (clickedButton == StandardButton.No ? "Oh No." : "No, no, a thousand times no!")
onApply: lastChosen.text = "Apply"
onReset: lastChosen.text = "Reset"
}
@@ -105,7 +105,7 @@ Rectangle {
function updateIcon(icon, checked) {
if (updating) return
updating = true
- messageDialog.icon = (checked ? icon : Message.NoIcon)
+ messageDialog.icon = (checked ? icon : StandardIcon.NoIcon)
for (var i = 0; i < children.length; ++i)
if (children[i].icon !== icon)
children[i].checked = false
@@ -115,7 +115,7 @@ Rectangle {
CheckBox {
id: iconInformation
text: "Information"
- property int icon: Message.Information
+ property int icon: StandardIcon.Information
onCheckedChanged: parent.updateIcon(icon, checked)
}
@@ -123,7 +123,7 @@ Rectangle {
id: iconWarning
text: "Warning"
checked: true
- property int icon: Message.Warning
+ property int icon: StandardIcon.Warning
onCheckedChanged: parent.updateIcon(icon, checked)
Component.onCompleted: parent.updateIcon(icon, true)
}
@@ -131,14 +131,14 @@ Rectangle {
CheckBox {
id: iconCritical
text: "Critical"
- property int icon: Message.Critical
+ property int icon: StandardIcon.Critical
onCheckedChanged: parent.updateIcon(icon, checked)
}
CheckBox {
id: iconQuestion
text: "Question"
- property int icon: Message.Question
+ property int icon: StandardIcon.Question
onCheckedChanged: parent.updateIcon(icon, checked)
}
}
@@ -182,75 +182,75 @@ Rectangle {
if (children[i].checked)
buttons |= children[i].button
if (!buttons)
- buttons = Message.Ok
+ buttons = StandardButton.Ok
messageDialog.standardButtons = buttons
updating = false
}
CheckBox {
text: "Help"
- property int button: Message.Help
+ property int button: StandardButton.Help
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "Abort"
- property int button: Message.Abort
+ property int button: StandardButton.Abort
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "Close"
- property int button: Message.Close
+ property int button: StandardButton.Close
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "Cancel"
- property int button: Message.Cancel
+ property int button: StandardButton.Cancel
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "NoToAll"
- property int button: Message.NoToAll
+ property int button: StandardButton.NoToAll
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "No"
- property int button: Message.No
+ property int button: StandardButton.No
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "YesToAll"
- property int button: Message.YesToAll
+ property int button: StandardButton.YesToAll
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "Yes"
- property int button: Message.Yes
+ property int button: StandardButton.Yes
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "Ignore"
- property int button: Message.Ignore
+ property int button: StandardButton.Ignore
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "Retry"
- property int button: Message.Retry
+ property int button: StandardButton.Retry
onCheckedChanged: parent.updateButtons(button, checked)
}
CheckBox {
text: "OK"
checked: true
- property int button: Message.Ok
+ property int button: StandardButton.Ok
onCheckedChanged: parent.updateButtons(button, checked)
}
}
diff --git a/examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc b/examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc
index 7869383ca2..a8ba96a10a 100644
--- a/examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc
+++ b/examples/quick/painteditem/textballoons/doc/src/textballoons.qdoc
@@ -49,7 +49,7 @@
We will focus on the \c TextBalloon class first and continue with the
\c textballoons.qml file. For an example on how to implement a \l {Qt Quick}
- plugin please look at \l{declarative/tutorials/extending/chapter6-plugins}
+ plugin please look at \l{Chapter 6: Writing an Extension Plugin}
{Writing an Extension Plugin}
\section1 TextBalloon Class Declaration
diff --git a/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc b/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc
index e3cef52bf7..56dcf6f396 100644
--- a/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc
+++ b/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc
@@ -171,7 +171,7 @@
The application is a straightforward QML application, with a
QGuiApplication and a QQuickView that we pass a .qml file. To make
use of the BezierCurve item, we need to register it in the QML
- engine, using the qmlRegisterType function. We give it the name
+ engine, using the qmlRegisterType() function. We give it the name
BezierCurve and make it part of the \c {CustomGeometry 1.0}
module.
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp
index 8ceb9c5f9e..91d69c90a4 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.cpp
+++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp
@@ -129,7 +129,10 @@ void Squircle::paint()
m_program->setAttributeArray(0, GL_FLOAT, values, 2);
m_program->setUniformValue("t", (float) m_thread_t);
- glViewport(0, 0, window()->width(), window()->height());
+ qreal ratio = window()->devicePixelRatio();
+ int w = int(ratio * window()->width());
+ int h = int(ratio * window()->height());
+ glViewport(0, 0, w, h);
glDisable(GL_DEPTH_TEST);
diff --git a/examples/quick/shared/Button.qml b/examples/quick/shared/Button.qml
index 468f945934..6f080e1b21 100644
--- a/examples/quick/shared/Button.qml
+++ b/examples/quick/shared/Button.qml
@@ -49,8 +49,8 @@ Item {
signal clicked
property alias containsMouse: mouseArea.containsMouse
property alias pressed: mouseArea.pressed
- implicitHeight: Math.max(Screen.logicalPixelDensity * 7, buttonLabel.implicitHeight * 1.2)
- implicitWidth: Math.max(Screen.logicalPixelDensity * 11, buttonLabel.implicitWidth * 1.3)
+ implicitHeight: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2)
+ implicitWidth: Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3)
height: implicitHeight
width: implicitWidth
diff --git a/examples/quick/shared/TabSet.qml b/examples/quick/shared/TabSet.qml
index 1fdf476424..b71e84c9d6 100644
--- a/examples/quick/shared/TabSet.qml
+++ b/examples/quick/shared/TabSet.qml
@@ -69,7 +69,7 @@ Item {
model: stack.children.length
delegate: Rectangle {
width: tabWidget.width / stack.children.length
- height: Math.max(Screen.logicalPixelDensity * 11, label.implicitHeight * 1.2)
+ height: Math.max(Screen.pixelDensity * 7, label.implicitHeight * 1.2)
Rectangle {
width: parent.width; height: 1
diff --git a/examples/quick/shared/shared.h b/examples/quick/shared/shared.h
index 5cf1333c02..d2f7c98311 100644
--- a/examples/quick/shared/shared.h
+++ b/examples/quick/shared/shared.h
@@ -49,8 +49,14 @@
app.setOrganizationDomain("qt-project.org");\
app.setApplicationName(QFileInfo(app.applicationFilePath()).baseName());\
QQuickView view;\
+ if (qgetenv("QT_QUICK_CORE_PROFILE").toInt()) {\
+ QSurfaceFormat f = view.format();\
+ f.setProfile(QSurfaceFormat::CoreProfile);\
+ f.setVersion(4, 4);\
+ view.setFormat(f);\
+ }\
view.connect(view.engine(), SIGNAL(quit()), &app, SLOT(quit()));\
- view.engine()->setUrlInterceptor(new QQmlFileSelector(&view));\
+ new QQmlFileSelector(view.engine(), &view);\
view.setSource(QUrl("qrc:///" #NAME ".qml")); \
view.setResizeMode(QQuickView::SizeRootObjectToView);\
if (QGuiApplication::platformName() == QLatin1String("qnx") || \
diff --git a/examples/quick/ui-components/slideswitch/doc/src/example-slideswitch.qdoc b/examples/quick/ui-components/slideswitch/doc/src/example-slideswitch.qdoc
index 3a14dd465a..8b0f103f0c 100644
--- a/examples/quick/ui-components/slideswitch/doc/src/example-slideswitch.qdoc
+++ b/examples/quick/ui-components/slideswitch/doc/src/example-slideswitch.qdoc
@@ -116,7 +116,7 @@ states (\e on and \e off).
This second function is called when the knob is released and we want to make sure that the knob does not end up between states
(neither \e on nor \e off). If it is the case call the \c toggle() function otherwise we do nothing.
-For more information on scripts see \l{Using JavaScript Expressions in QML}.
+For more information on scripts see \l{JavaScript Expressions in QML Documents}.
\section2 Transition
\snippet ui-components/slideswitch/content/Switch.qml 7
diff --git a/examples/quick/window/ScreenInfo.qml b/examples/quick/window/ScreenInfo.qml
index e4abc8d69d..e422a51a71 100644
--- a/examples/quick/window/ScreenInfo.qml
+++ b/examples/quick/window/ScreenInfo.qml
@@ -79,6 +79,9 @@ Item {
Text { text: "dimensions" }
Text { text: Screen.width + "x" + Screen.height }
+ Text { text: "pixel density" }
+ Text { text: Screen.pixelDensity.toFixed(2) + " dots/mm" }
+
Text { text: "logical pixel density" }
Text { text: Screen.logicalPixelDensity.toFixed(2) + " dots/mm" }
diff --git a/examples/quick/window/window.qml b/examples/quick/window/window.qml
index 67e2ba40ff..00daec7ff1 100644
--- a/examples/quick/window/window.qml
+++ b/examples/quick/window/window.qml
@@ -140,6 +140,7 @@ QtObject {
height: 240
color: "#215400"
title: "Test Window with color " + color
+ flags: Qt.Window | Qt.WindowFullscreenButtonHint
Rectangle {
anchors.fill: parent
anchors.margins: defaultSpacing
diff --git a/src/3rdparty/double-conversion/cached-powers.cc b/src/3rdparty/double-conversion/cached-powers.cc
index c676429194..7067fca4a9 100644
--- a/src/3rdparty/double-conversion/cached-powers.cc
+++ b/src/3rdparty/double-conversion/cached-powers.cc
@@ -144,6 +144,7 @@ void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
int max_exponent,
DiyFp* power,
int* decimal_exponent) {
+ (void)max_exponent; // Silence unused parameter warning in release builds
int kQ = DiyFp::kSignificandSize;
double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
int foo = kCachedPowersOffset;
diff --git a/src/3rdparty/double-conversion/fixed-dtoa.cc b/src/3rdparty/double-conversion/fixed-dtoa.cc
index d56b1449b2..6d63c71858 100644
--- a/src/3rdparty/double-conversion/fixed-dtoa.cc
+++ b/src/3rdparty/double-conversion/fixed-dtoa.cc
@@ -152,6 +152,8 @@ static void FillDigits32(uint32_t number, Vector<char> buffer, int* length) {
static void FillDigits64FixedLength(uint64_t number, int requested_length,
Vector<char> buffer, int* length) {
+ (void) requested_length;
+
const uint32_t kTen7 = 10000000;
// For efficiency cut the number into 3 uint32_t parts, and print those.
uint32_t part2 = static_cast<uint32_t>(number % kTen7);
diff --git a/src/3rdparty/double-conversion/strtod.cc b/src/3rdparty/double-conversion/strtod.cc
index 9758989f71..2620fbbf0f 100644
--- a/src/3rdparty/double-conversion/strtod.cc
+++ b/src/3rdparty/double-conversion/strtod.cc
@@ -137,6 +137,7 @@ static void TrimAndCut(Vector<const char> buffer, int exponent,
Vector<const char> right_trimmed = TrimTrailingZeros(left_trimmed);
exponent += left_trimmed.length() - right_trimmed.length();
if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
+ (void)space_size; // Silence unused parameter warning in release build
ASSERT(space_size >= kMaxSignificantDecimalDigits);
CutToMaxSignificantDigits(right_trimmed, exponent,
buffer_copy_space, updated_exponent);
@@ -515,6 +516,7 @@ float Strtof(Vector<const char> buffer, int exponent) {
double double_next2 = Double(double_next).NextDouble();
f4 = static_cast<float>(double_next2);
}
+ (void)f2; // Silence unused parameter warning in release builds
ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
// If the guess doesn't lie near a single-precision boundary we can simply
diff --git a/src/3rdparty/double-conversion/utils.h b/src/3rdparty/double-conversion/utils.h
index 044c0c25eb..1eca476913 100644
--- a/src/3rdparty/double-conversion/utils.h
+++ b/src/3rdparty/double-conversion/utils.h
@@ -57,7 +57,7 @@
// disabled.)
// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
#if defined(_M_X64) || defined(__x86_64__) || \
- defined(__ARMEL__) || defined(__avr32__) || \
+ defined(__ARMEL__) || defined(__avr32__) || _M_ARM_FP || \
defined(__hppa__) || defined(__ia64__) || \
defined(__mips__) || defined(__powerpc__) || \
defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
@@ -302,7 +302,8 @@ template <class Dest, class Source>
inline Dest BitCast(const Source& source) {
// Compile time assertion: sizeof(Dest) == sizeof(Source)
// A compile error here means your Dest and Source have different sizes.
- typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+ char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+ (void) VerifySizesAreEqual;
Dest dest;
memmove(&dest, &source, sizeof(dest));
diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri
index 34c2e9f8de..95f1f60031 100644
--- a/src/3rdparty/masm/masm-defs.pri
+++ b/src/3rdparty/masm/masm-defs.pri
@@ -2,6 +2,11 @@
DEFINES += WTF_EXPORT_PRIVATE="" JS_EXPORT_PRIVATE=""
+# Avoid symbol clashes with QtScript during static linking
+DEFINES += WTFReportAssertionFailure=qmlWTFReportAssertionFailure
+DEFINES += WTFReportBacktrace=qmlWTFReportBacktrace
+DEFINES += WTFInvokeCrashHook=qmlWTFInvokeCrashHook
+
win*: DEFINES += NOMINMAX
DEFINES += ENABLE_LLINT=0
diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri
index d7b315602e..3fd4aa6cec 100644
--- a/src/3rdparty/masm/masm.pri
+++ b/src/3rdparty/masm/masm.pri
@@ -11,7 +11,8 @@ HEADERS += $$PWD/wtf/FilePrintStream.h
HEADERS += $$PWD/wtf/RawPointer.h
-win32: SOURCES += $$PWD/wtf/OSAllocatorWin.cpp
+winrt: SOURCES += $$PWD/wtf/OSAllocatorWinRT.cpp
+else:win32: SOURCES += $$PWD/wtf/OSAllocatorWin.cpp
else: SOURCES += $$PWD/wtf/OSAllocatorPosix.cpp
HEADERS += $$PWD/wtf/OSAllocator.h
diff --git a/src/3rdparty/masm/stubs/ExecutableAllocator.h b/src/3rdparty/masm/stubs/ExecutableAllocator.h
index a8f54df39f..d8618b3b44 100644
--- a/src/3rdparty/masm/stubs/ExecutableAllocator.h
+++ b/src/3rdparty/masm/stubs/ExecutableAllocator.h
@@ -119,8 +119,10 @@ struct ExecutableAllocator {
size_t iaddr = reinterpret_cast<size_t>(addr);
size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
#if OS(WINDOWS)
+#if !OS(WINRT)
DWORD oldProtect;
VirtualProtect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), PAGE_EXECUTE_READWRITE, &oldProtect);
+#endif
#else
int mode = PROT_READ | PROT_EXEC;
#if !ENABLE(ASSEMBLER_WX_EXCLUSIVE)
diff --git a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
new file mode 100644
index 0000000000..f851087eb2
--- /dev/null
+++ b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#include "config.h"
+#include "OSAllocator.h"
+
+#if OS(WINRT)
+
+#include "windows.h"
+#include <wtf/Assertions.h>
+
+namespace WTF {
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool, bool, bool)
+{
+ void* result = _aligned_malloc(bytes, 16);
+ if (!result)
+ CRASH();
+ return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool)
+{
+ return reserveUncommitted(bytes, usage, writable, executable);
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
+{
+ CRASH(); // Unimplemented
+}
+
+void OSAllocator::decommit(void* address, size_t)
+{
+ _aligned_free(address);
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+ decommit(address, bytes);
+}
+
+} // namespace WTF
+
+#endif // OS(WINRT)
diff --git a/src/3rdparty/masm/wtf/PageBlock.cpp b/src/3rdparty/masm/wtf/PageBlock.cpp
index 8bbd7eb600..a6f5585925 100644
--- a/src/3rdparty/masm/wtf/PageBlock.cpp
+++ b/src/3rdparty/masm/wtf/PageBlock.cpp
@@ -53,7 +53,11 @@ inline size_t systemPageSize()
{
static size_t size = 0;
SYSTEM_INFO system_info;
+#if OS(WINRT)
+ GetNativeSystemInfo(&system_info);
+#else
GetSystemInfo(&system_info);
+#endif
size = system_info.dwPageSize;
return size;
}
diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h
index c81a9fe40f..c845f5e23c 100644
--- a/src/3rdparty/masm/wtf/Platform.h
+++ b/src/3rdparty/masm/wtf/Platform.h
@@ -404,6 +404,11 @@
#define WTF_OS_WINCE 1
#endif
+/* OS(WINCE) - Windows Runtime; note that for this platform OS(WINDOWS) is also defined */
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#define WTF_OS_WINRT 1
+#endif
+
/* OS(WINDOWS) - Any version of Windows */
#if defined(WIN32) || defined(_WIN32)
#define WTF_OS_WINDOWS 1
diff --git a/src/imports/dialogs/DefaultColorDialog.qml b/src/imports/dialogs/DefaultColorDialog.qml
index 1d4c4a704b..4913e332d7 100644
--- a/src/imports/dialogs/DefaultColorDialog.qml
+++ b/src/imports/dialogs/DefaultColorDialog.qml
@@ -45,31 +45,60 @@ import "qml"
AbstractColorDialog {
id: root
- property bool _valueSet: true // guard to prevent binding loops
- function _setControlsFromColor() {
- _valueSet = false
+ property bool __valueSet: true // guard to prevent binding loops
+ function __setControlsFromColor() {
+ __valueSet = false
hueSlider.value = root.currentHue
saturationSlider.value = root.currentSaturation
lightnessSlider.value = root.currentLightness
alphaSlider.value = root.currentAlpha
crosshairs.x = root.currentLightness * paletteMap.width
crosshairs.y = (1.0 - root.currentSaturation) * paletteMap.height
- _valueSet = true
+ __valueSet = true
}
- onCurrentColorChanged: _setControlsFromColor()
+ onCurrentColorChanged: __setControlsFromColor()
onSelectionAccepted: root.color = root.currentColor
Rectangle {
id: content
property int maxSize: 0.9 * Math.min(Screen.desktopAvailableWidth, Screen.desktopAvailableHeight)
- implicitHeight: Math.min(maxSize, Screen.logicalPixelDensity * (usePaletteMap ? 100 : 50))
+ implicitHeight: Math.min(maxSize, Screen.pixelDensity * (usePaletteMap ? 100 : 50))
implicitWidth: usePaletteMap ? implicitHeight - bottomMinHeight : implicitHeight * 1.5
color: palette.window
+ focus: root.visible
property real bottomMinHeight: sliders.height + buttonRow.height + outerSpacing * 3
property real spacing: 8
property real outerSpacing: 12
property bool usePaletteMap: true
+ Keys.onPressed: {
+ event.accepted = true
+ switch (event.key) {
+ case Qt.Key_Return:
+ case Qt.Key_Select:
+ accept()
+ break
+ case Qt.Key_Escape:
+ case Qt.Key_Back:
+ reject()
+ break
+ case Qt.Key_C:
+ if (event.modifiers & Qt.ControlModifier)
+ colorField.copyAll()
+ break
+ case Qt.Key_V:
+ if (event.modifiers & Qt.ControlModifier) {
+ colorField.paste()
+ root.currentColor = colorField.text
+ }
+ break
+ default:
+ // do nothing
+ event.accepted = false
+ break
+ }
+ }
+
// set the preferred width based on height, to avoid "letterboxing" the paletteMap
onHeightChanged: implicitHeight = Math.max((usePaletteMap ? 480 : bottomMinHeight), height)
@@ -90,7 +119,7 @@ AbstractColorDialog {
id: paletteMap
x: (parent.width - width) / 2
width: height
- onWidthChanged: root._setControlsFromColor()
+ onWidthChanged: root.__setControlsFromColor()
height: parent.height
source: "images/checkers.png"
fillMode: Image.Tile
@@ -205,7 +234,7 @@ AbstractColorDialog {
ColorSlider {
id: hueSlider
value: 0.5
- onValueChanged: if (_valueSet) root.currentColor = Qt.hsla(hueSlider.value, saturationSlider.value, lightnessSlider.value, alphaSlider.value)
+ onValueChanged: if (__valueSet) root.currentColor = Qt.hsla(hueSlider.value, saturationSlider.value, lightnessSlider.value, alphaSlider.value)
text: qsTr("Hue")
trackDelegate: Rectangle {
rotation: -90
@@ -226,7 +255,7 @@ AbstractColorDialog {
id: saturationSlider
visible: !content.usePaletteMap
value: 0.5
- onValueChanged: if (_valueSet) root.currentColor = Qt.hsla(hueSlider.value, saturationSlider.value, lightnessSlider.value, alphaSlider.value)
+ onValueChanged: if (__valueSet) root.currentColor = Qt.hsla(hueSlider.value, saturationSlider.value, lightnessSlider.value, alphaSlider.value)
text: qsTr("Saturation")
trackDelegate: Rectangle {
rotation: -90
@@ -242,7 +271,7 @@ AbstractColorDialog {
id: lightnessSlider
visible: !content.usePaletteMap
value: 0.5
- onValueChanged: if (_valueSet) root.currentColor = Qt.hsla(hueSlider.value, saturationSlider.value, lightnessSlider.value, alphaSlider.value)
+ onValueChanged: if (__valueSet) root.currentColor = Qt.hsla(hueSlider.value, saturationSlider.value, lightnessSlider.value, alphaSlider.value)
text: qsTr("Luminosity")
trackDelegate: Rectangle {
rotation: -90
@@ -260,7 +289,7 @@ AbstractColorDialog {
minimum: 0.0
maximum: 1.0
value: 1.0
- onValueChanged: if (_valueSet) root.currentColor = Qt.hsla(hueSlider.value, saturationSlider.value, lightnessSlider.value, alphaSlider.value)
+ onValueChanged: if (__valueSet) root.currentColor = Qt.hsla(hueSlider.value, saturationSlider.value, lightnessSlider.value, alphaSlider.value)
text: qsTr("Alpha")
visible: root.showAlphaChannel
trackDelegate: Item {
@@ -295,6 +324,7 @@ AbstractColorDialog {
}
Row {
spacing: content.spacing
+ height: parent.height
TextField {
id: colorField
text: root.currentColor.toString()
diff --git a/src/imports/dialogs/DefaultFileDialog.qml b/src/imports/dialogs/DefaultFileDialog.qml
index fb6996b80c..0a5eabddf2 100644
--- a/src/imports/dialogs/DefaultFileDialog.qml
+++ b/src/imports/dialogs/DefaultFileDialog.qml
@@ -48,63 +48,62 @@ AbstractFileDialog {
id: root
onVisibleChanged: {
if (visible) {
- selectedIndices = []
- lastClickedIdx = -1
+ __selectedIndices = []
+ __lastClickedIdx = -1
currentPathField.visible = false
}
}
onFolderChanged: view.model.folder = folder
- property bool showFocusHighlight: false
- property real textX: titleBar.height
- property SystemPalette palette
- property var selectedIndices: []
- property int lastClickedIdx: -1
+ property real __textX: titleBar.height
+ property SystemPalette __palette
+ property var __selectedIndices: []
+ property int __lastClickedIdx: -1
- function dirDown(path) {
+ function __dirDown(path) {
view.model.folder = path
- lastClickedIdx = -1
- selectedIndices = []
+ __lastClickedIdx = -1
+ __selectedIndices = []
}
- function dirUp() {
+ function __dirUp() {
view.model.folder = view.model.parentFolder
- lastClickedIdx = -1
- selectedIndices = []
+ __lastClickedIdx = -1
+ __selectedIndices = []
}
- function up(extend) {
+ function __up(extend) {
if (view.currentIndex > 0)
--view.currentIndex
else
view.currentIndex = 0
if (extend) {
- if (selectedIndices.indexOf(view.currentIndex) < 0) {
- var selCopy = selectedIndices
+ if (__selectedIndices.indexOf(view.currentIndex) < 0) {
+ var selCopy = __selectedIndices
selCopy.push(view.currentIndex)
- selectedIndices = selCopy
+ __selectedIndices = selCopy
}
} else
- selectedIndices = [view.currentIndex]
+ __selectedIndices = [view.currentIndex]
}
- function down(extend) {
+ function __down(extend) {
if (view.currentIndex < view.model.count - 1)
++view.currentIndex
else
view.currentIndex = view.model.count - 1
if (extend) {
- if (selectedIndices.indexOf(view.currentIndex) < 0) {
- var selCopy = selectedIndices
+ if (__selectedIndices.indexOf(view.currentIndex) < 0) {
+ var selCopy = __selectedIndices
selCopy.push(view.currentIndex)
- selectedIndices = selCopy
+ __selectedIndices = selCopy
}
} else
- selectedIndices = [view.currentIndex]
+ __selectedIndices = [view.currentIndex]
}
- function acceptSelection() {
+ function __acceptSelection() {
clearSelection()
- if (selectFolder && selectedIndices.length == 0)
+ if (selectFolder && __selectedIndices.length == 0)
addSelection(folder)
- else {
- selectedIndices.map(function(idx) {
+ else if (__selectedIndices.length > 0) {
+ __selectedIndices.map(function(idx) {
if (view.model.isFolder(idx)) {
if (selectFolder)
addSelection(view.model.get(idx, "fileURL"))
@@ -113,19 +112,23 @@ AbstractFileDialog {
addSelection(view.model.get(idx, "fileURL"))
}
})
+ } else {
+ addSelection(pathToUrl(currentPathField.text))
}
accept()
}
Rectangle {
+ id: content
property int maxSize: Math.min(Screen.desktopAvailableWidth, Screen.desktopAvailableHeight)
// TODO: QTBUG-29817 geometry from AbstractFileDialog
- implicitWidth: Math.min(maxSize, Screen.logicalPixelDensity * 100)
- implicitHeight: Math.min(maxSize, Screen.logicalPixelDensity * 80)
- id: window
- color: palette.window
-
- SystemPalette { id: palette }
+ implicitWidth: Math.min(maxSize, Screen.pixelDensity * 100)
+ implicitHeight: Math.min(maxSize, Screen.pixelDensity * 80)
+ color: __palette.window
+ focus: root.visible && !currentPathField.visible
+ property real spacing: 6
+ property real outerSpacing: 12
+ SystemPalette { id: __palette }
Component {
id: folderDelegate
@@ -133,25 +136,25 @@ AbstractFileDialog {
id: wrapper
function launch() {
if (view.model.isFolder(index)) {
- dirDown(filePath)
+ __dirDown(filePath)
} else {
- root.acceptSelection()
+ root.__acceptSelection()
}
}
- width: window.width
+ width: content.width
height: nameText.implicitHeight * 1.5
color: "transparent"
Rectangle {
id: itemHighlight
- visible: root.selectedIndices.indexOf(index) >= 0
+ visible: root.__selectedIndices.indexOf(index) >= 0
anchors.fill: parent
- color: palette.highlight
+ color: __palette.highlight
}
Image {
id: icon
source: "images/folder.png"
height: wrapper.height - y * 2; width: height
- x: (root.textX - width) / 2
+ x: (root.__textX - width) / 2
y: 2
visible: view.model.isFolder(index)
}
@@ -159,51 +162,92 @@ AbstractFileDialog {
id: nameText
anchors.fill: parent; verticalAlignment: Text.AlignVCenter
text: fileName
- anchors.leftMargin: root.textX
- color: itemHighlight.visible ? palette.highlightedText : palette.windowText
+ anchors.leftMargin: root.__textX
+ color: itemHighlight.visible ? __palette.highlightedText : __palette.windowText
elide: Text.ElideRight
}
MouseArea {
id: mouseRegion
anchors.fill: parent
onDoubleClicked: {
- selectedIndices = [index]
- root.lastClickedIdx = index
+ __selectedIndices = [index]
+ root.__lastClickedIdx = index
launch()
}
onClicked: {
view.currentIndex = index
if (mouse.modifiers & Qt.ControlModifier && root.selectMultiple) {
- // modifying the contents of selectedIndices doesn't notify,
+ // modifying the contents of __selectedIndices doesn't notify,
// so we have to re-assign the variable
- var selCopy = selectedIndices
+ var selCopy = __selectedIndices
var existingIdx = selCopy.indexOf(index)
if (existingIdx >= 0)
selCopy.splice(existingIdx, 1)
else
selCopy.push(index)
- selectedIndices = selCopy
+ __selectedIndices = selCopy
} else if (mouse.modifiers & Qt.ShiftModifier && root.selectMultiple) {
- if (root.lastClickedIdx >= 0) {
+ if (root.__lastClickedIdx >= 0) {
var sel = []
- if (index > lastClickedIdx) {
- for (var i = root.lastClickedIdx; i <= index; i++)
+ if (index > __lastClickedIdx) {
+ for (var i = root.__lastClickedIdx; i <= index; i++)
sel.push(i)
} else {
- for (var i = root.lastClickedIdx; i >= index; i--)
+ for (var i = root.__lastClickedIdx; i >= index; i--)
sel.push(i)
}
- selectedIndices = sel
+ __selectedIndices = sel
}
} else {
- selectedIndices = [index]
- root.lastClickedIdx = index
+ __selectedIndices = [index]
+ root.__lastClickedIdx = index
}
}
}
}
}
+ Keys.onPressed: {
+ event.accepted = true
+ switch (event.key) {
+ case Qt.Key_Up:
+ root.__up(event.modifiers & Qt.ShiftModifier && root.selectMultiple)
+ break
+ case Qt.Key_Down:
+ root.__down(event.modifiers & Qt.ShiftModifier && root.selectMultiple)
+ break
+ case Qt.Key_Left:
+ root.__dirUp()
+ break
+ case Qt.Key_Return:
+ case Qt.Key_Select:
+ case Qt.Key_Right:
+ if (view.currentItem)
+ view.currentItem.launch()
+ else
+ root.__acceptSelection()
+ break
+ case Qt.Key_Back:
+ case Qt.Key_Escape:
+ reject()
+ break
+ case Qt.Key_C:
+ if (event.modifiers & Qt.ControlModifier)
+ currentPathField.copyAll()
+ break
+ case Qt.Key_V:
+ if (event.modifiers & Qt.ControlModifier) {
+ currentPathField.visible = true
+ currentPathField.paste()
+ }
+ break
+ default:
+ // do nothing
+ event.accepted = false
+ break
+ }
+ }
+
ListView {
id: view
anchors.top: titleBar.bottom
@@ -220,37 +264,10 @@ AbstractFileDialog {
delegate: folderDelegate
highlight: Rectangle {
color: "transparent"
- border.color: Qt.darker(palette.window, 1.3)
+ border.color: Qt.darker(__palette.window, 1.3)
}
highlightMoveDuration: 0
highlightMoveVelocity: -1
- focus: !currentPathField.visible
- Keys.onPressed: {
- event.accepted = true
- switch (event.key) {
- case Qt.Key_Up:
- root.up(event.modifiers & Qt.ShiftModifier && root.selectMultiple)
- break
- case Qt.Key_Down:
- root.down(event.modifiers & Qt.ShiftModifier && root.selectMultiple)
- break
- case Qt.Key_Left:
- root.dirUp()
- break
- case Qt.Key_Return:
- case Qt.Key_Select:
- case Qt.Key_Right:
- if (view.currentItem)
- view.currentItem.launch()
- else
- root.acceptSelection()
- break
- default:
- // do nothing
- event.accepted = false
- break
- }
- }
}
MouseArea {
@@ -266,12 +283,12 @@ AbstractFileDialog {
height: currentPathField.height * 1.5
Rectangle {
anchors.fill: parent
- color: Qt.darker(palette.window, 1.1)
- border.color: Qt.darker(palette.window, 1.3)
+ color: Qt.darker(__palette.window, 1.1)
+ border.color: Qt.darker(__palette.window, 1.3)
}
Rectangle {
id: upButton
- width: root.textX
+ width: root.__textX
height: titleBar.height
color: "transparent"
@@ -282,22 +299,22 @@ AbstractFileDialog {
MouseArea { id: upRegion; anchors.centerIn: parent
width: 56
height: parent.height
- onClicked: if (view.model.parentFolder != "") dirUp()
+ onClicked: if (view.model.parentFolder !== "") __dirUp()
}
states: [
State {
name: "pressed"
when: upRegion.pressed
- PropertyChanges { target: upButton; color: palette.highlight }
+ PropertyChanges { target: upButton; color: __palette.highlight }
}
]
}
Text {
id: currentPathText
anchors.left: parent.left; anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: textX; anchors.rightMargin: 4
+ anchors.leftMargin: __textX; anchors.rightMargin: content.spacing
text: root.urlToPath(view.model.folder)
- color: palette.text
+ color: __palette.text
elide: Text.ElideLeft; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignVCenter
MouseArea {
anchors.fill: parent
@@ -307,7 +324,7 @@ AbstractFileDialog {
TextField {
id: currentPathField
anchors.left: parent.left; anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: textX; anchors.rightMargin: 4
+ anchors.leftMargin: __textX; anchors.rightMargin: content.spacing
visible: false
focus: visible
onAccepted: {
@@ -318,6 +335,8 @@ AbstractFileDialog {
view.model.folder = root.pathFolder(text)
}
onDownPressed: currentPathField.visible = false
+ onBackPressed: reject()
+ onEscapePressed: reject()
}
}
Rectangle {
@@ -325,15 +344,15 @@ AbstractFileDialog {
width: parent.width
height: buttonRow.height + buttonRow.spacing * 2
anchors.bottom: parent.bottom
- color: Qt.darker(palette.window, 1.1)
- border.color: Qt.darker(palette.window, 1.3)
+ color: Qt.darker(__palette.window, 1.1)
+ border.color: Qt.darker(__palette.window, 1.3)
Row {
id: buttonRow
anchors.right: parent.right
anchors.rightMargin: spacing
anchors.verticalCenter: parent.verticalCenter
- spacing: 4
+ spacing: content.spacing
TextField {
id: filterField
text: root.selectedNameFilter
@@ -355,9 +374,9 @@ AbstractFileDialog {
text: "OK"
onClicked: {
if (view.model.isFolder(view.currentIndex) && !selectFolder)
- dirDown(view.model.get(view.currentIndex, "filePath"))
+ __dirDown(view.model.get(view.currentIndex, "filePath"))
else
- root.acceptSelection()
+ root.__acceptSelection()
}
}
}
diff --git a/src/imports/dialogs/DefaultFontDialog.qml b/src/imports/dialogs/DefaultFontDialog.qml
index 87bb812c42..29feed342f 100644
--- a/src/imports/dialogs/DefaultFontDialog.qml
+++ b/src/imports/dialogs/DefaultFontDialog.qml
@@ -51,13 +51,19 @@ AbstractFontDialog {
Rectangle {
id: content
- property int maxSize: Math.min(Screen.desktopAvailableWidth, Screen.desktopAvailableHeight)
- implicitWidth: settings.implicitWidth + changeableWidth + outerSpacing * 2
- implicitHeight: writingSystemLabel.implicitHeight + changeableHeight + buttonRow.height + outerSpacing * 2
+ implicitWidth: Math.min(Screen.desktopAvailableWidth, implicitHeight * 1.2)
+ implicitHeight: Math.min(Screen.desktopAvailableHeight, settingsBottom.implicitHeight * 3)
color: palette.window
- property real spacing: 8
+ focus: root.visible
+ property real spacing: 6
property real outerSpacing: 12
property real listMargins: 4
+ property real delegateHeightMultiplier: 1.5
+ property real extraWidth: width > 400 ? width - 400 : 0
+ property real extraHeight: height > initialHeight ? height - initialHeight : 0
+ property real initialHeight: -1
+ onHeightChanged: if (visible && initialHeight < 0) initialHeight = height
+
property color borderColor: Qt.darker(palette.button, 1.5)
property font font: Qt.font({ family: "Helvetica", pointSize: 24, weight: Font.Normal })
@@ -66,9 +72,6 @@ AbstractFontDialog {
property string writingSystemSample
property var pointSizes
- property real changeableWidth: 160
- property real changeableHeight: 120
-
onFontChanged: externalFont = font
onExternalFontChanged: {
@@ -80,374 +83,397 @@ AbstractFontDialog {
}
}
+ Keys.onPressed: {
+ event.accepted = true
+ switch (event.key) {
+ case Qt.Key_Return:
+ case Qt.Key_Select:
+ root.font = content.font
+ root.accept()
+ break
+ case Qt.Key_Escape:
+ case Qt.Key_Back:
+ reject()
+ break
+ default:
+ // do nothing
+ event.accepted = false
+ break
+ }
+ }
+
SystemPalette { id: palette }
- Grid {
- id: settings
- anchors {
- top: parent.top
- bottom: buttonRow.top
- left: parent.left
- margins: content.outerSpacing
- }
- columns: 5
- spacing: content.spacing
+ Column {
+ id: contentColumn
+ anchors.fill: parent
+ anchors.margins: content.outerSpacing
+ spacing: content.outerSpacing
- Text { id: writingSystemLabel; text: qsTr("Writing System") }
- Text { id: fontNameLabel; text: qsTr("Font") }
- Text { id: weightLabel; text: qsTr("Weight") }
- Text { id: sizeLabel; text: qsTr("Size") }
- Text { id: optionsLabel; text: qsTr("Others") }
- Rectangle {
- radius: 3
- color: palette.window
- border.color: content.borderColor
- implicitWidth: Math.max(writingSystemLabel.implicitWidth + content.listMargins * 2, 80)
- implicitHeight: Math.max(content.changeableHeight, sampleRectangle.height)
- clip: true
- ListView {
- id: wsListView
- anchors.fill: parent
- anchors.margins: content.listMargins
- anchors.topMargin: 2
- highlightMoveDuration: 0
- function reset() {
- if (wsModel.count > 0) {
- content.writingSystem = wsModel.get(0).name;
- fontModel.writingSystem = content.writingSystem;
- content.writingSystemSample = wsModel.get(0).sample;
+ Grid {
+ id: settingsTop
+ columns: 3
+ spacing: content.spacing
+ width: parent.width
+ height: parent.height - buttonRow.height - settingsBottom.height - parent.spacing * 2
+ property real columnHeight: height - writingSystemLabel.height - spacing
+
+ Text { id: writingSystemLabel; text: qsTr("Writing System"); font.bold: true }
+ Text { id: fontNameLabel; text: qsTr("Font"); font.bold: true }
+ Text { id: sizeLabel; text: qsTr("Size"); font.bold: true }
+ Rectangle {
+ id: wsColumn
+ radius: 3
+ color: palette.window
+ border.color: content.borderColor
+ implicitWidth: Math.max(writingSystemLabel.implicitWidth, 100) + content.extraWidth / 5
+ height: parent.columnHeight
+ clip: true
+ ListView {
+ id: wsListView
+ anchors.fill: parent
+ anchors.margins: content.listMargins
+ anchors.topMargin: 2
+ highlightMoveDuration: 0
+ onHeightChanged: positionViewAtIndex(currentIndex, ListView.Contain)
+ function reset() {
+ if (wsModel.count > 0) {
+ content.writingSystem = wsModel.get(0).name;
+ fontModel.writingSystem = content.writingSystem;
+ content.writingSystemSample = wsModel.get(0).sample;
+ }
}
- }
- model: WritingSystemListModel {
- id: wsModel
- Component.onCompleted: wsListView.reset()
- }
- highlight: Rectangle {
- color: palette.highlight
- x: 2 - wsListView.anchors.margins
- width: wsListView.parent.width - 4
- }
- delegate: Item {
- width: parent.width
- height: wsText.height
- Text {
- id: wsText
- text: name
- width: parent.width
- elide: Text.ElideRight
+ model: WritingSystemListModel {
+ id: wsModel
+ Component.onCompleted: wsListView.reset()
}
- MouseArea {
- anchors.fill: parent
- onClicked: {
- wsListView.currentIndex = index;
- content.writingSystem = wsModel.get(wsListView.currentIndex).name;
- fontModel.writingSystem = content.writingSystem;
- content.writingSystemSample = wsModel.get(wsListView.currentIndex).sample;
+ highlight: Rectangle {
+ color: palette.highlight
+ x: 2 - wsListView.anchors.margins
+ width: wsListView.parent.width - 4
+ }
+ delegate: Item {
+ width: parent.width
+ height: wsText.height * content.delegateHeightMultiplier
+ Text {
+ id: wsText
+ text: name
+ width: parent.width
+ elide: Text.ElideRight
+ color: index === wsListView.currentIndex ? palette.highlightedText : palette.windowText
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ wsListView.currentIndex = index;
+ content.writingSystem = wsModel.get(wsListView.currentIndex).name;
+ fontModel.writingSystem = content.writingSystem;
+ content.writingSystemSample = wsModel.get(wsListView.currentIndex).sample;
+ }
}
}
}
}
- }
- Rectangle {
- radius: 3
- color: palette.window
- border.color: content.borderColor
- implicitWidth: Math.max(fontNameLabel.implicitWidth + content.listMargins * 2, 100, (root.width - 400) / 3)
- implicitHeight: Math.max(content.changeableHeight, sampleRectangle.height)
- clip: true
- ListView {
- id: fontListView
- anchors.fill: parent
- anchors.margins: content.listMargins
- anchors.topMargin: 2
- highlightMoveDuration: 0
- function reset() {
- fontModel.findIndex()
- content.pointSizes = fontModel.pointSizes()
- fontModel.findPointSizesIndex()
- }
+ Rectangle {
+ radius: 3
+ color: palette.window
+ border.color: content.borderColor
+ implicitWidth: Math.max(fontNameLabel.implicitWidth, parent.width - wsColumn.implicitWidth - pointSizesColumn.implicitWidth - parent.spacing * 2)
+ height: parent.columnHeight
+ clip: true
+ ListView {
+ id: fontListView
+ anchors.fill: parent
+ anchors.margins: content.listMargins
+ anchors.topMargin: 2
+ highlightMoveDuration: 0
+ onHeightChanged: positionViewAtIndex(currentIndex, ListView.Contain)
+ function reset() {
+ fontModel.findIndex()
+ content.pointSizes = fontModel.pointSizes()
+ fontModel.findPointSizesIndex()
+ }
+
+ model: FontListModel {
+ id: fontModel
+ scalableFonts: root.scalableFonts
+ nonScalableFonts: root.nonScalableFonts
+ monospacedFonts: root.monospacedFonts
+ proportionalFonts: root.proportionalFonts
+ Component.onCompleted: fontListView.reset()
+ onModelReset: { findIndex(); }
+ function findIndex() {
+ if (fontModel.count <= 0)
+ return
- model: FontListModel {
- id: fontModel
- scalableFonts: root.scalableFonts
- nonScalableFonts: root.nonScalableFonts
- monospacedFonts: root.monospacedFonts
- proportionalFonts: root.proportionalFonts
- Component.onCompleted: fontListView.reset()
- onModelReset: { findIndex(); }
- function findIndex() {
- if (fontModel.count <= 0)
- return
+ if (content.font.family == "") {
+ content.font.family = fontModel.get(0).family
+ fontListView.currentIndex = 0
+ } else {
+ var find = false
+ for (var i = 0; i < fontModel.count; ++i) {
+ if (content.font.family == fontModel.get(i).family) {
+ find = true
+ fontListView.currentIndex = i
+ break
+ }
+ }
+ if (find == false) {
+ content.font.family = fontModel.get(0).family
+ fontListView.currentIndex = 0
+ }
+ }
+ }
+ function findPointSizesIndex() {
+ if (content.pointSizes.length <= 0)
+ return
- if (content.font.family == "") {
- content.font.family = fontModel.get(0).family
- fontListView.currentIndex = 0
- } else {
var find = false
- for (var i = 0; i < fontModel.count; ++i) {
- if (content.font.family == fontModel.get(i).family) {
+ for (var i = 0; i < content.pointSizes.length; ++i) {
+ if (content.font.pointSize == content.pointSizes[i]) {
find = true
- fontListView.currentIndex = i
+ pointSizesListView.currentIndex = i
break
}
}
if (find == false) {
- content.font.family = fontModel.get(0).family
- fontListView.currentIndex = 0
+ content.font.pointSize = content.pointSizes[0]
+ pointSizesListView.currentIndex = 0
}
}
}
- function findPointSizesIndex() {
- if (content.pointSizes.length <= 0)
- return
-
- var find = false
- for (var i = 0; i < content.pointSizes.length; ++i) {
- if (content.font.pointSize == content.pointSizes[i]) {
- find = true
- pointSizesListView.currentIndex = i
- break
- }
+ highlight: Rectangle {
+ color: palette.highlight
+ x: 2 - fontListView.anchors.margins
+ width: fontListView.parent.width - 4
+ }
+ delegate: Item {
+ width: parent.width
+ height: fontText.height * content.delegateHeightMultiplier
+ Text {
+ id: fontText
+ text: family
+ width: parent.width
+ elide: Text.ElideRight
+ color: index === fontListView.currentIndex ? palette.highlightedText : palette.windowText
+ anchors.verticalCenter: parent.verticalCenter
}
- if (find == false) {
- content.font.pointSize = content.pointSizes[0]
- pointSizesListView.currentIndex = 0
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ fontListView.currentIndex = index
+ content.font.family = fontModel.get(fontListView.currentIndex).family
+ }
}
}
}
- highlight: Rectangle {
- color: palette.highlight
- x: 2 - fontListView.anchors.margins
- width: fontListView.parent.width - 4
- }
- delegate: Item {
- width: parent.width
- height: fontText.height
- Text {
- id: fontText
- text: family
- width: parent.width
- elide: Text.ElideRight
+ }
+ Rectangle {
+ id: pointSizesColumn
+ radius: 3
+ color: palette.window
+ border.color: content.borderColor
+ implicitWidth:sizeLabel.implicitWidth * 2
+ height: parent.columnHeight
+ clip: true
+ ListView {
+ id: pointSizesListView
+ anchors.fill: parent
+ anchors.margins: content.listMargins
+ anchors.topMargin: 2
+ highlightMoveDuration: 0
+ onHeightChanged: positionViewAtIndex(currentIndex, ListView.Contain)
+ model: content.pointSizes
+ highlight: Rectangle {
+ color: palette.highlight
+ x: 2 - pointSizesListView.anchors.margins
+ width: pointSizesListView.parent.width - 4
}
- MouseArea {
- anchors.fill: parent
- onClicked: {
- fontListView.currentIndex = index
- content.font.family = fontModel.get(fontListView.currentIndex).family
+ delegate: Item {
+ width: parent.width
+ height: pointSizesText.height * content.delegateHeightMultiplier
+ Text {
+ id: pointSizesText
+ text: content.pointSizes[index]
+ width: parent.width
+ elide: Text.ElideRight
+ color: index === pointSizesListView.currentIndex ? palette.highlightedText : palette.windowText
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ pointSizesListView.currentIndex = index
+ content.font.pointSize = content.pointSizes[pointSizesListView.currentIndex]
+ }
}
}
}
}
}
- Rectangle {
- radius: 3
- color: palette.window
- border.color: content.borderColor
- implicitWidth: Math.max(weightLabel.implicitWidth + content.listMargins * 2, 80)
- implicitHeight: Math.max(content.changeableHeight, sampleRectangle.height)
- clip: true
- ListView {
- anchors.fill: parent
- anchors.margins: content.listMargins
- anchors.topMargin: 2
- highlightMoveDuration: 0
- id: weightListView
- function reset() {
- weightModel.findIndex()
- }
- model: ListModel {
- id: weightModel
- ListElement {
- name: "Light"
- weight: Font.Light
- }
- ListElement {
- name: "Normal"
- weight: Font.Normal
- }
- ListElement {
- name: "DemiBold"
- weight: Font.DemiBold
- }
- ListElement {
- name: "Bold"
- weight: Font.Bold
- }
- ListElement {
- name: "Black"
- weight: Font.Black
+ Grid {
+ id: settingsBottom
+ columns: 3
+ spacing: content.spacing
+ width: parent.width
+ height: initialHeight + content.extraHeight / 4
+ property real initialHeight
+ property real secondRowHeight: height - weightLabel.height - spacing
+ Component.onCompleted: initialHeight = implicitHeight
+
+ Text { id: weightLabel; text: qsTr("Weight"); font.bold: true }
+ Text { id: optionsLabel; text: qsTr("Style"); font.bold: true }
+ Text { id: sampleLabel; text: qsTr("Sample"); font.bold: true }
+ Rectangle {
+ id: weightColumn
+ radius: 3
+ color: palette.window
+ border.color: content.borderColor
+ implicitWidth: optionsColumn.implicitWidth
+ implicitHeight: optionsColumn.implicitHeight
+ height: parent.secondRowHeight
+ clip: true
+ ListView {
+ id: weightListView
+ anchors.fill: parent
+ anchors.margins: content.listMargins
+ anchors.topMargin: 2
+ highlightMoveDuration: 0
+ onHeightChanged: positionViewAtIndex(currentIndex, ListView.Contain)
+ function reset() {
+ weightModel.findIndex()
}
- Component.onCompleted: weightListView.reset()
- function findIndex() {
- var find = false
- for (var i = 0; i < weightModel.count; ++i) {
- if (content.font.weight == weightModel.get(i).weight) {
- find = true
- weightListView.currentIndex = i
- break
- }
+
+ model: ListModel {
+ id: weightModel
+ ListElement {
+ name: "Light"
+ weight: Font.Light
+ }
+ ListElement {
+ name: "Normal"
+ weight: Font.Normal
}
- if (find == false) {
- content.font.weight = weightModel.get(1).family
- fontListView.currentIndex = 1
+ ListElement {
+ name: "DemiBold"
+ weight: Font.DemiBold
+ }
+ ListElement {
+ name: "Bold"
+ weight: Font.Bold
+ }
+ ListElement {
+ name: "Black"
+ weight: Font.Black
+ }
+ Component.onCompleted: weightListView.reset()
+ function findIndex() {
+ var find = false
+ for (var i = 0; i < weightModel.count; ++i) {
+ if (content.font.weight == weightModel.get(i).weight) {
+ find = true
+ weightListView.currentIndex = i
+ break
+ }
+ }
+ if (find == false) {
+ content.font.weight = weightModel.get(1).family
+ fontListView.currentIndex = 1
+ }
}
}
- }
- highlight: Rectangle {
- color: palette.highlight
- x: 2 - weightListView.anchors.margins
- width: weightListView.parent.width - 4
- }
- delegate: Item {
- width: parent.width
- height: weightText.height
- Text {
- id: weightText
- text: name
- width: parent.width
- elide: Text.ElideRight
+ highlight: Rectangle {
+ color: palette.highlight
+ x: 2 - weightListView.anchors.margins
+ width: weightListView.parent.width - 4
}
- MouseArea {
- anchors.fill: parent
- onClicked: {
- weightListView.currentIndex = index
- content.font.weight = weightModel.get(weightListView.currentIndex).weight
+ delegate: Item {
+ width: parent.width
+ height: weightText.height * content.delegateHeightMultiplier
+ Text {
+ id: weightText
+ text: name
+ width: parent.width
+ elide: Text.ElideRight
+ color: index === weightListView.currentIndex ? palette.highlightedText : palette.windowText
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ weightListView.currentIndex = index
+ content.font.weight = weightModel.get(weightListView.currentIndex).weight
+ }
}
}
}
}
- }
- Rectangle {
- radius: 3
- color: palette.window
- border.color: content.borderColor
- implicitWidth: Math.max(sizeLabel.implicitWidth + content.listMargins * 2, 60)
- implicitHeight: Math.max(content.changeableHeight, sampleRectangle.height)
- clip: true
- ListView {
- anchors.fill: parent
- anchors.margins: content.listMargins
- anchors.topMargin: 2
- highlightMoveDuration: 0
- id: pointSizesListView
- model: content.pointSizes
- highlight: Rectangle {
- color: palette.highlight
- x: 2 - weightListView.anchors.margins
- width: weightListView.parent.width - 4
+ Column {
+ id: optionsColumn
+ spacing: 4
+ CheckBox {
+ id: italicCheckBox
+ text: qsTr("Italic")
+ checked: content.font.italic
+ onClicked: { content.font.italic = italicCheckBox.checked }
}
- delegate: Item {
- width: parent.width
- height: pointSizesText.height
- Text {
- id: pointSizesText
- text: content.pointSizes[index]
- width: parent.width
- elide: Text.ElideRight
- }
- MouseArea {
- anchors.fill: parent
- onClicked: {
- pointSizesListView.currentIndex = index
- content.font.pointSize = content.pointSizes[pointSizesListView.currentIndex]
- }
- }
+ CheckBox {
+ id: underlineCheckBox
+ text: qsTr("Underline")
+ checked: content.font.underline
+ onClicked: { content.font.underline = underlineCheckBox.checked }
+ }
+ CheckBox {
+ id: overlineCheckBox
+ text: qsTr("Overline")
+ checked: content.font.overline
+ onClicked: { content.font.overline = overlineCheckBox.checked }
+ }
+ CheckBox {
+ id: strikeoutCheckBox
+ text: qsTr("Strikeout")
+ checked: content.font.strikeout
+ onClicked: { content.font.strikeout = strikeoutCheckBox.checked }
}
}
- }
- Column {
- id: optionsColumn
- anchors.margins: 2
- spacing: 2
- CheckBox {
- id: italicCheckBox
- text: qsTr("Italic")
- checked: content.font.italic
- onClicked: { content.font.italic = italicCheckBox.checked }
- }
- CheckBox {
- id: underlineCheckBox
- text: qsTr("Underline")
- checked: content.font.underline
- onClicked: { content.font.underline = underlineCheckBox.checked }
- }
- CheckBox {
- id: overlineCheckBox
- text: qsTr("Overline")
- checked: content.font.overline
- onClicked: { content.font.overline = overlineCheckBox.checked }
- }
- CheckBox {
- id: strikeoutCheckBox
- text: qsTr("Strikeout")
- checked: content.font.strikeout
- onClicked: { content.font.strikeout = strikeoutCheckBox.checked }
+ Rectangle {
+ clip: true
+ implicitWidth: sample.implicitWidth + parent.spacing
+ implicitHeight: optionsColumn.implicitHeight
+ width: parent.width - weightColumn.width - optionsColumn.width - parent.spacing * 2
+ height: parent.secondRowHeight
+ color: palette.window
+ border.color: content.borderColor
+ Text {
+ id: sample
+ anchors.centerIn: parent
+ font: content.font
+ text: content.writingSystemSample
+ }
}
}
- }
- Rectangle {
- id: fixsampleRectangle
- color: palette.window
- anchors {
- top: parent.top
- left: settings.right
- right: parent.right
- margins: content.outerSpacing
- }
- implicitWidth: fixsampleText.implicitWidth
- implicitHeight: fixsampleText.implicitHeight
- Text { id: fixsampleText; anchors.left: parent.left; text: qsTr("Sample") }
- }
- Rectangle {
- id: sampleRectangle
- clip: true
- anchors {
- top: fixsampleRectangle.bottom
- bottom: buttonRow.top
- left: fixsampleRectangle.left
- right: parent.right
- margins: content.outerSpacing
- }
- implicitWidth: content.changeableWidth
- implicitHeight: content.changeableHeight
- color: palette.window
- border.color: content.borderColor
- Text {
- id: sample
- anchors.centerIn: parent
- font: content.font
- text: content.writingSystemSample
- }
- }
-
- Item {
- id: buttonRow
- height: buttonsOnly.height
- width: parent.width
- anchors {
- left: parent.left
- right: parent.right
- bottom: content.bottom
- margins: content.outerSpacing
- }
- Row {
- id: buttonsOnly
- spacing: content.spacing
- anchors.right: parent.right
- Button {
- id: cancelButton
- text: qsTr("Cancel")
- onClicked: root.reject()
- }
- Button {
- id: okButton
- text: qsTr("OK")
- onClicked: {
- root.font = content.font
- root.accept()
+ Item {
+ id: buttonRow
+ height: buttonsOnly.height
+ width: parent.width
+ Row {
+ id: buttonsOnly
+ spacing: content.spacing
+ anchors.right: parent.right
+ Button {
+ text: qsTr("Cancel")
+ onClicked: root.reject()
+ }
+ Button {
+ text: qsTr("OK")
+ onClicked: {
+ root.font = content.font
+ root.accept()
+ }
}
}
}
diff --git a/src/imports/dialogs/DefaultMessageDialog.qml b/src/imports/dialogs/DefaultMessageDialog.qml
index 5dbe727f68..ba29469b5e 100644
--- a/src/imports/dialogs/DefaultMessageDialog.qml
+++ b/src/imports/dialogs/DefaultMessageDialog.qml
@@ -48,28 +48,37 @@ AbstractMessageDialog {
Rectangle {
id: content
- property real spacing: 8
+ property real spacing: 6
property real outerSpacing: 12
- property int maxSize: 0.9 * Math.min(Screen.desktopAvailableWidth, Screen.desktopAvailableHeight)
+ property real buttonsRowImplicitWidth: Screen.pixelDensity * 50
implicitHeight: contentColumn.implicitHeight + outerSpacing * 2
onImplicitHeightChanged: root.height = implicitHeight
- implicitWidth: Math.min(maxSize, Math.max(
- mainText.implicitWidth, buttons.implicitWidth) + outerSpacing * 2);
- onImplicitWidthChanged: if (implicitWidth > root.width) root.width = implicitWidth
+ implicitWidth: Math.min(Screen.desktopAvailableWidth * 0.9, Math.max(
+ mainText.implicitWidth, buttonsRowImplicitWidth) + outerSpacing * 2);
+ onImplicitWidthChanged: root.width = implicitWidth
color: palette.window
- focus: true
- Keys.onEscapePressed: root.reject()
- Keys.onEnterPressed: root.accept()
- Keys.onReturnPressed: root.accept()
- Keys.onPressed: if (event.modifiers === Qt.ControlModifier)
- switch (event.key) {
- case Qt.Key_A:
- detailedText.selectAll();
- break;
- case Qt.Key_C:
- detailedText.copy();
- break;
+ focus: root.visible
+ Keys.onPressed: {
+ event.accepted = true
+ if (event.modifiers === Qt.ControlModifier)
+ switch (event.key) {
+ case Qt.Key_A:
+ detailedText.selectAll()
+ break
+ case Qt.Key_C:
+ detailedText.copy()
+ break
+ } else switch (event.key) {
+ case Qt.Key_Escape:
+ case Qt.Key_Back:
+ reject()
+ break
+ case Qt.Key_Enter:
+ case Qt.Key_Return:
+ accept()
+ break
}
+ }
Column {
id: contentColumn
@@ -118,112 +127,113 @@ AbstractMessageDialog {
}
- Row {
+ Flow {
id: buttons
spacing: content.spacing
layoutDirection: Qt.RightToLeft
- width: parent.width
+ width: parent.width + content.outerSpacing
+ x: -content.outerSpacing
Button {
id: okButton
text: "OK"
- onClicked: root.click(Message.Ok)
- visible: root.standardButtons & Message.Ok
+ onClicked: root.click(StandardButton.Ok)
+ visible: root.standardButtons & StandardButton.Ok
}
Button {
id: openButton
text: "Open"
- onClicked: root.click(Message.Open)
- visible: root.standardButtons & Message.Open
+ onClicked: root.click(StandardButton.Open)
+ visible: root.standardButtons & StandardButton.Open
}
Button {
id: saveButton
text: "Save"
- onClicked: root.click(Message.Save)
- visible: root.standardButtons & Message.Save
+ onClicked: root.click(StandardButton.Save)
+ visible: root.standardButtons & StandardButton.Save
}
Button {
id: saveAllButton
text: "Save All"
- onClicked: root.click(Message.SaveAll)
- visible: root.standardButtons & Message.SaveAll
+ onClicked: root.click(StandardButton.SaveAll)
+ visible: root.standardButtons & StandardButton.SaveAll
}
Button {
id: retryButton
text: "Retry"
- onClicked: root.click(Message.Retry)
- visible: root.standardButtons & Message.Retry
+ onClicked: root.click(StandardButton.Retry)
+ visible: root.standardButtons & StandardButton.Retry
}
Button {
id: ignoreButton
text: "Ignore"
- onClicked: root.click(Message.Ignore)
- visible: root.standardButtons & Message.Ignore
+ onClicked: root.click(StandardButton.Ignore)
+ visible: root.standardButtons & StandardButton.Ignore
}
Button {
id: applyButton
text: "Apply"
- onClicked: root.click(Message.Apply)
- visible: root.standardButtons & Message.Apply
+ onClicked: root.click(StandardButton.Apply)
+ visible: root.standardButtons & StandardButton.Apply
}
Button {
id: yesButton
text: "Yes"
- onClicked: root.click(Message.Yes)
- visible: root.standardButtons & Message.Yes
+ onClicked: root.click(StandardButton.Yes)
+ visible: root.standardButtons & StandardButton.Yes
}
Button {
id: yesAllButton
text: "Yes to All"
- onClicked: root.click(Message.YesToAll)
- visible: root.standardButtons & Message.YesToAll
+ onClicked: root.click(StandardButton.YesToAll)
+ visible: root.standardButtons & StandardButton.YesToAll
}
Button {
id: noButton
text: "No"
- onClicked: root.click(Message.No)
- visible: root.standardButtons & Message.No
+ onClicked: root.click(StandardButton.No)
+ visible: root.standardButtons & StandardButton.No
}
Button {
id: noAllButton
text: "No to All"
- onClicked: root.click(Message.NoToAll)
- visible: root.standardButtons & Message.NoToAll
+ onClicked: root.click(StandardButton.NoToAll)
+ visible: root.standardButtons & StandardButton.NoToAll
}
Button {
id: discardButton
text: "Discard"
- onClicked: root.click(Message.Discard)
- visible: root.standardButtons & Message.Discard
+ onClicked: root.click(StandardButton.Discard)
+ visible: root.standardButtons & StandardButton.Discard
}
Button {
id: resetButton
text: "Reset"
- onClicked: root.click(Message.Reset)
- visible: root.standardButtons & Message.Reset
+ onClicked: root.click(StandardButton.Reset)
+ visible: root.standardButtons & StandardButton.Reset
}
Button {
id: restoreDefaultsButton
text: "Restore Defaults"
- onClicked: root.click(Message.RestoreDefaults)
- visible: root.standardButtons & Message.RestoreDefaults
+ onClicked: root.click(StandardButton.RestoreDefaults)
+ visible: root.standardButtons & StandardButton.RestoreDefaults
}
Button {
id: cancelButton
text: "Cancel"
- onClicked: root.click(Message.Cancel)
- visible: root.standardButtons & Message.Cancel
+ onClicked: root.click(StandardButton.Cancel)
+ visible: root.standardButtons & StandardButton.Cancel
}
Button {
id: abortButton
text: "Abort"
- onClicked: root.click(Message.Abort)
- visible: root.standardButtons & Message.Abort
+ onClicked: root.click(StandardButton.Abort)
+ visible: root.standardButtons & StandardButton.Abort
}
Button {
id: closeButton
text: "Close"
- onClicked: root.click(Message.Close)
- visible: root.standardButtons & Message.Close
+ onClicked: root.click(StandardButton.Close)
+ visible: root.standardButtons & StandardButton.Close
}
Button {
id: moreButton
@@ -234,9 +244,10 @@ AbstractMessageDialog {
Button {
id: helpButton
text: "Help"
- onClicked: root.click(Message.Help)
- visible: root.standardButtons & Message.Help
+ onClicked: root.click(StandardButton.Help)
+ visible: root.standardButtons & StandardButton.Help
}
+ onVisibleChildrenChanged: calculateImplicitWidth()
}
}
@@ -307,4 +318,13 @@ AbstractMessageDialog {
}
]
}
+ function calculateImplicitWidth() {
+ if (buttons.visibleChildren.length < 2)
+ return;
+ var calcWidth = 0;
+ for (var i = 0; i < buttons.visibleChildren.length; ++i)
+ calcWidth += Math.max(100, buttons.visibleChildren[i].implicitWidth) + content.spacing
+ content.buttonsRowImplicitWidth = content.outerSpacing + calcWidth
+ }
+ Component.onCompleted: calculateImplicitWidth()
}
diff --git a/src/imports/dialogs/dialogs.pro b/src/imports/dialogs/dialogs.pro
index e6ca7a2147..1abad55883 100644
--- a/src/imports/dialogs/dialogs.pro
+++ b/src/imports/dialogs/dialogs.pro
@@ -25,7 +25,7 @@ HEADERS += \
qquickabstractmessagedialog_p.h \
qquickplatformmessagedialog_p.h \
qquickmessagedialog_p.h \
- qquickmessageattached_p.h \
+ qquickdialogassets_p.h \
qquickabstractfiledialog_p.h \
qquickplatformfiledialog_p.h \
qquickfiledialog_p.h \
diff --git a/src/imports/dialogs/doc/images/critical.png b/src/imports/dialogs/doc/images/critical.png
new file mode 100644
index 0000000000..dc9c5aebf4
--- /dev/null
+++ b/src/imports/dialogs/doc/images/critical.png
Binary files differ
diff --git a/src/imports/dialogs/doc/images/information.png b/src/imports/dialogs/doc/images/information.png
new file mode 100644
index 0000000000..0a2eb87d10
--- /dev/null
+++ b/src/imports/dialogs/doc/images/information.png
Binary files differ
diff --git a/src/imports/dialogs/doc/images/question.png b/src/imports/dialogs/doc/images/question.png
new file mode 100644
index 0000000000..2dd92fd791
--- /dev/null
+++ b/src/imports/dialogs/doc/images/question.png
Binary files differ
diff --git a/src/imports/dialogs/doc/images/replacefile.png b/src/imports/dialogs/doc/images/replacefile.png
new file mode 100644
index 0000000000..d1479fa944
--- /dev/null
+++ b/src/imports/dialogs/doc/images/replacefile.png
Binary files differ
diff --git a/src/imports/dialogs/doc/images/warning.png b/src/imports/dialogs/doc/images/warning.png
new file mode 100644
index 0000000000..cba78f6bea
--- /dev/null
+++ b/src/imports/dialogs/doc/images/warning.png
Binary files differ
diff --git a/src/imports/dialogs/doc/qtquickdialogs.qdocconf b/src/imports/dialogs/doc/qtquickdialogs.qdocconf
index c6cd32c73a..1bad67790f 100644
--- a/src/imports/dialogs/doc/qtquickdialogs.qdocconf
+++ b/src/imports/dialogs/doc/qtquickdialogs.qdocconf
@@ -2,7 +2,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtQuickDialogs
description = Qt Quick Dialogs Reference Documentation
-url = http://qt-project.org/doc/qt-$QT_VER/qtquickdialogs/
+url = http://qt-project.org/doc/qt-$QT_VER
version = $QT_VERSION
qhp.projects = QtQuickDialogs
diff --git a/src/imports/dialogs/plugin.cpp b/src/imports/dialogs/plugin.cpp
index 1c852abae9..44df1447d1 100644
--- a/src/imports/dialogs/plugin.cpp
+++ b/src/imports/dialogs/plugin.cpp
@@ -43,7 +43,7 @@
#include <QtQml/qqmlextensionplugin.h>
#include "qquickmessagedialog_p.h"
#include "qquickabstractmessagedialog_p.h"
-#include "qquickmessageattached_p.h"
+#include "qquickdialogassets_p.h"
#include "qquickplatformmessagedialog_p.h"
#include "qquickfiledialog_p.h"
#include "qquickabstractfiledialog_p.h"
@@ -60,6 +60,11 @@
//#define PURE_QML_ONLY
//#define DEBUG_REGISTRATION
+static void initResources()
+{
+ Q_INIT_RESOURCE(dialogs);
+}
+
QT_BEGIN_NAMESPACE
/*!
@@ -96,6 +101,8 @@ public:
}
virtual void registerTypes(const char *uri) {
+ initResources();
+
#ifdef DEBUG_REGISTRATION
qDebug() << Q_FUNC_INFO << uri;
#endif
@@ -122,7 +129,10 @@ public:
// Otherwise fall back to a pure-QML implementation.
// MessageDialog
- qmlRegisterUncreatableType<QQuickMessageAttached>(uri, 1, 1, "Message", QQuickMessageAttached::tr("Message can only be used via the attached property."));
+ qmlRegisterUncreatableType<QQuickStandardButton>(uri, 1, 1, "StandardButton",
+ QLatin1String("Do not create objects of type StandardButton"));
+ qmlRegisterUncreatableType<QQuickStandardIcon>(uri, 1, 1, "StandardIcon",
+ QLatin1String("Do not create objects of type StandardIcon"));
#ifndef PURE_QML_ONLY
if (QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(QPlatformTheme::MessageDialog))
qmlRegisterType<QQuickPlatformMessageDialog>(uri, 1, 0, "MessageDialog");
diff --git a/src/imports/dialogs/plugins.qmltypes b/src/imports/dialogs/plugins.qmltypes
index c52d355cad..d5db4b93bd 100644
--- a/src/imports/dialogs/plugins.qmltypes
+++ b/src/imports/dialogs/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable QtQuick.Dialogs 1.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -omit-prefix=__ QtQuick.Dialogs 1.1'
Module {
Component {
@@ -124,15 +125,530 @@ Module {
}
}
Component {
- name: "QQuickPlatformColorDialog"
+ name: "QQuickAbstractFontDialog"
+ prototype: "QQuickAbstractDialog"
+ Property { name: "scalableFonts"; type: "bool" }
+ Property { name: "nonScalableFonts"; type: "bool" }
+ Property { name: "monospacedFonts"; type: "bool" }
+ Property { name: "proportionalFonts"; type: "bool" }
+ Property { name: "font"; type: "QFont" }
+ Signal { name: "selectionAccepted" }
+ Method {
+ name: "setVisible"
+ Parameter { name: "v"; type: "bool" }
+ }
+ Method {
+ name: "setModality"
+ Parameter { name: "m"; type: "Qt::WindowModality" }
+ }
+ Method {
+ name: "setTitle"
+ Parameter { name: "t"; type: "string" }
+ }
+ Method {
+ name: "setFont"
+ Parameter { name: "arg"; type: "QFont" }
+ }
+ Method {
+ name: "setScalableFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setNonScalableFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setMonospacedFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setProportionalFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ }
+ Component {
+ name: "QQuickAbstractMessageDialog"
+ prototype: "QQuickAbstractDialog"
+ Enum {
+ name: "Icon"
+ values: {
+ "NoIcon": 0,
+ "Information": 1,
+ "Warning": 2,
+ "Critical": 3,
+ "Question": 4
+ }
+ }
+ Enum {
+ name: "StandardButton"
+ values: {
+ "NoButton": 0,
+ "Ok": 1024,
+ "Save": 2048,
+ "SaveAll": 4096,
+ "Open": 8192,
+ "Yes": 16384,
+ "YesToAll": 32768,
+ "No": 65536,
+ "NoToAll": 131072,
+ "Abort": 262144,
+ "Retry": 524288,
+ "Ignore": 1048576,
+ "Close": 2097152,
+ "Cancel": 4194304,
+ "Discard": 8388608,
+ "Help": 16777216,
+ "Apply": 33554432,
+ "Reset": 67108864,
+ "RestoreDefaults": 134217728
+ }
+ }
+ Enum {
+ name: "StandardButtons"
+ values: {
+ "NoButton": 0,
+ "Ok": 1024,
+ "Save": 2048,
+ "SaveAll": 4096,
+ "Open": 8192,
+ "Yes": 16384,
+ "YesToAll": 32768,
+ "No": 65536,
+ "NoToAll": 131072,
+ "Abort": 262144,
+ "Retry": 524288,
+ "Ignore": 1048576,
+ "Close": 2097152,
+ "Cancel": 4194304,
+ "Discard": 8388608,
+ "Help": 16777216,
+ "Apply": 33554432,
+ "Reset": 67108864,
+ "RestoreDefaults": 134217728
+ }
+ }
+ Property { name: "text"; type: "string" }
+ Property { name: "informativeText"; type: "string" }
+ Property { name: "detailedText"; type: "string" }
+ Property { name: "icon"; type: "Icon" }
+ Property { name: "standardIconSource"; type: "QUrl"; isReadonly: true }
+ Property { name: "standardButtons"; type: "StandardButtons" }
+ Property { name: "clickedButton"; type: "StandardButton"; isReadonly: true }
+ Signal { name: "buttonClicked" }
+ Signal { name: "discard" }
+ Signal { name: "help" }
+ Signal { name: "yes" }
+ Signal { name: "no" }
+ Signal { name: "apply" }
+ Signal { name: "reset" }
+ Method {
+ name: "setVisible"
+ Parameter { name: "v"; type: "bool" }
+ }
+ Method {
+ name: "setTitle"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setInformativeText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setDetailedText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setIcon"
+ Parameter { name: "icon"; type: "Icon" }
+ }
+ Method {
+ name: "setStandardButtons"
+ Parameter { name: "buttons"; type: "StandardButtons" }
+ }
+ Method {
+ name: "click"
+ Parameter { name: "button"; type: "QMessageDialogOptions::StandardButton" }
+ Parameter { type: "QMessageDialogOptions::ButtonRole" }
+ }
+ Method {
+ name: "click"
+ Parameter { name: "button"; type: "QQuickAbstractMessageDialog::StandardButton" }
+ }
+ }
+ Component {
+ name: "QQuickColorDialog"
+ defaultProperty: "implementation"
prototype: "QQuickAbstractColorDialog"
- exports: ["QtQuick.Dialogs/ColorDialog 1.0"]
+ exports: ["QtQuick.Dialogs/AbstractColorDialog 1.0"]
exportMetaObjectRevisions: [0]
+ Property { name: "implementation"; type: "QObject"; isPointer: true }
}
Component {
- name: "QQuickPlatformFileDialog"
+ name: "QQuickFileDialog"
+ defaultProperty: "implementation"
prototype: "QQuickAbstractFileDialog"
+ exports: ["QtQuick.Dialogs/AbstractFileDialog 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "implementation"; type: "QObject"; isPointer: true }
+ Method { name: "clearSelection" }
+ Method {
+ name: "addSelection"
+ type: "bool"
+ Parameter { name: "path"; type: "QUrl" }
+ }
+ }
+ Component {
+ name: "QQuickFontDialog"
+ defaultProperty: "implementation"
+ prototype: "QQuickAbstractFontDialog"
+ exports: ["QtQuick.Dialogs/AbstractFontDialog 1.1"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "implementation"; type: "QObject"; isPointer: true }
+ }
+ Component {
+ name: "QQuickMessageDialog"
+ defaultProperty: "implementation"
+ prototype: "QQuickAbstractMessageDialog"
+ exports: ["QtQuick.Dialogs/AbstractMessageDialog 1.1"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "implementation"; type: "QObject"; isPointer: true }
+ }
+ Component {
+ name: "QQuickStandardButton"
+ exports: ["QtQuick.Dialogs/StandardButton 1.1"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QQuickStandardIcon"
+ exports: ["QtQuick.Dialogs/StandardIcon 1.1"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ prototype: "QObject"
+ name: "QtQuick.Dialogs/ColorDialog"
+ exports: ["QtQuick.Dialogs/ColorDialog 1.0"]
+ exportMetaObjectRevisions: [0]
+ defaultProperty: "implementation"
+ Property { name: "showAlphaChannel"; type: "bool" }
+ Property { name: "color"; type: "QColor" }
+ Property { name: "currentColor"; type: "QColor" }
+ Property { name: "currentHue"; type: "double"; isReadonly: true }
+ Property { name: "currentSaturation"; type: "double"; isReadonly: true }
+ Property { name: "currentLightness"; type: "double"; isReadonly: true }
+ Property { name: "currentAlpha"; type: "double"; isReadonly: true }
+ Signal { name: "selectionAccepted" }
+ Method {
+ name: "setVisible"
+ Parameter { name: "v"; type: "bool" }
+ }
+ Method {
+ name: "setModality"
+ Parameter { name: "m"; type: "Qt::WindowModality" }
+ }
+ Method {
+ name: "setTitle"
+ Parameter { name: "t"; type: "string" }
+ }
+ Method {
+ name: "setColor"
+ Parameter { name: "arg"; type: "QColor" }
+ }
+ Method {
+ name: "setCurrentColor"
+ Parameter { name: "currentColor"; type: "QColor" }
+ }
+ Method {
+ name: "setShowAlphaChannel"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Property { name: "visible"; type: "bool" }
+ Property { name: "modality"; type: "Qt::WindowModality" }
+ Property { name: "title"; type: "string" }
+ Property { name: "isWindow"; type: "bool"; isReadonly: true }
+ Property { name: "x"; type: "int" }
+ Property { name: "y"; type: "int" }
+ Property { name: "width"; type: "int" }
+ Property { name: "height"; type: "int" }
+ Signal { name: "visibilityChanged" }
+ Signal { name: "geometryChanged" }
+ Signal { name: "accepted" }
+ Signal { name: "rejected" }
+ Method { name: "open" }
+ Method { name: "close" }
+ Method {
+ name: "setX"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setY"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setWidth"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setHeight"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Property { name: "implementation"; type: "QObject"; isPointer: true }
+ }
+ Component {
+ prototype: "QObject"
+ name: "QtQuick.Dialogs/FileDialog"
exports: ["QtQuick.Dialogs/FileDialog 1.0"]
exportMetaObjectRevisions: [0]
+ defaultProperty: "implementation"
+ Property { name: "visible"; type: "bool" }
+ Property { name: "modality"; type: "Qt::WindowModality" }
+ Property { name: "title"; type: "string" }
+ Property { name: "isWindow"; type: "bool"; isReadonly: true }
+ Property { name: "x"; type: "int" }
+ Property { name: "y"; type: "int" }
+ Property { name: "width"; type: "int" }
+ Property { name: "height"; type: "int" }
+ Signal { name: "visibilityChanged" }
+ Signal { name: "geometryChanged" }
+ Signal { name: "accepted" }
+ Signal { name: "rejected" }
+ Method { name: "open" }
+ Method { name: "close" }
+ Method {
+ name: "setX"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setY"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setWidth"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setHeight"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Property { name: "selectExisting"; type: "bool" }
+ Property { name: "selectMultiple"; type: "bool" }
+ Property { name: "selectFolder"; type: "bool" }
+ Property { name: "folder"; type: "QUrl" }
+ Property { name: "nameFilters"; type: "QStringList" }
+ Property { name: "selectedNameFilter"; type: "string" }
+ Property { name: "fileUrl"; type: "QUrl"; isReadonly: true }
+ Property { name: "fileUrls"; type: "QList<QUrl>"; isReadonly: true }
+ Signal { name: "filterSelected" }
+ Signal { name: "fileModeChanged" }
+ Signal { name: "selectionAccepted" }
+ Method {
+ name: "setVisible"
+ Parameter { name: "v"; type: "bool" }
+ }
+ Method {
+ name: "setTitle"
+ Parameter { name: "t"; type: "string" }
+ }
+ Method {
+ name: "setSelectExisting"
+ Parameter { name: "s"; type: "bool" }
+ }
+ Method {
+ name: "setSelectMultiple"
+ Parameter { name: "s"; type: "bool" }
+ }
+ Method {
+ name: "setSelectFolder"
+ Parameter { name: "s"; type: "bool" }
+ }
+ Method {
+ name: "setFolder"
+ Parameter { name: "f"; type: "QUrl" }
+ }
+ Method {
+ name: "setNameFilters"
+ Parameter { name: "f"; type: "QStringList" }
+ }
+ Method {
+ name: "selectNameFilter"
+ Parameter { name: "f"; type: "string" }
+ }
+ Property { name: "implementation"; type: "QObject"; isPointer: true }
+ Method { name: "clearSelection" }
+ Method {
+ name: "addSelection"
+ type: "bool"
+ Parameter { name: "path"; type: "QUrl" }
+ }
+ }
+ Component {
+ prototype: "QObject"
+ name: "QtQuick.Dialogs/FontDialog"
+ exports: ["QtQuick.Dialogs/FontDialog 1.1"]
+ exportMetaObjectRevisions: [1]
+ defaultProperty: "implementation"
+ Property { name: "font"; type: "QFont" }
+ Property { name: "visible"; type: "bool" }
+ Property { name: "modality"; type: "Qt::WindowModality" }
+ Property { name: "title"; type: "string" }
+ Property { name: "isWindow"; type: "bool"; isReadonly: true }
+ Property { name: "x"; type: "int" }
+ Property { name: "y"; type: "int" }
+ Property { name: "width"; type: "int" }
+ Property { name: "height"; type: "int" }
+ Signal { name: "visibilityChanged" }
+ Signal { name: "geometryChanged" }
+ Signal { name: "accepted" }
+ Signal { name: "rejected" }
+ Method { name: "open" }
+ Method { name: "close" }
+ Method {
+ name: "setX"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setY"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setWidth"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setHeight"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Property { name: "scalableFonts"; type: "bool" }
+ Property { name: "nonScalableFonts"; type: "bool" }
+ Property { name: "monospacedFonts"; type: "bool" }
+ Property { name: "proportionalFonts"; type: "bool" }
+ Property { name: "font"; type: "QFont" }
+ Signal { name: "selectionAccepted" }
+ Method {
+ name: "setVisible"
+ Parameter { name: "v"; type: "bool" }
+ }
+ Method {
+ name: "setModality"
+ Parameter { name: "m"; type: "Qt::WindowModality" }
+ }
+ Method {
+ name: "setTitle"
+ Parameter { name: "t"; type: "string" }
+ }
+ Method {
+ name: "setFont"
+ Parameter { name: "arg"; type: "QFont" }
+ }
+ Method {
+ name: "setScalableFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setNonScalableFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setMonospacedFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setProportionalFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Property { name: "implementation"; type: "QObject"; isPointer: true }
+ }
+ Component {
+ prototype: "QObject"
+ name: "QtQuick.Dialogs/MessageDialog"
+ exports: ["QtQuick.Dialogs/MessageDialog 1.1"]
+ exportMetaObjectRevisions: [1]
+ defaultProperty: "implementation"
+ Method { name: "calculateImplicitWidth"; type: "QVariant" }
+ Property { name: "visible"; type: "bool" }
+ Property { name: "modality"; type: "Qt::WindowModality" }
+ Property { name: "title"; type: "string" }
+ Property { name: "isWindow"; type: "bool"; isReadonly: true }
+ Property { name: "x"; type: "int" }
+ Property { name: "y"; type: "int" }
+ Property { name: "width"; type: "int" }
+ Property { name: "height"; type: "int" }
+ Signal { name: "visibilityChanged" }
+ Signal { name: "geometryChanged" }
+ Signal { name: "accepted" }
+ Signal { name: "rejected" }
+ Method { name: "open" }
+ Method { name: "close" }
+ Method {
+ name: "setX"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setY"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setWidth"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setHeight"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Property { name: "text"; type: "string" }
+ Property { name: "informativeText"; type: "string" }
+ Property { name: "detailedText"; type: "string" }
+ Property { name: "icon"; type: "Icon" }
+ Property { name: "standardIconSource"; type: "QUrl"; isReadonly: true }
+ Property { name: "standardButtons"; type: "StandardButtons" }
+ Property { name: "clickedButton"; type: "StandardButton"; isReadonly: true }
+ Signal { name: "buttonClicked" }
+ Signal { name: "discard" }
+ Signal { name: "help" }
+ Signal { name: "yes" }
+ Signal { name: "no" }
+ Signal { name: "apply" }
+ Signal { name: "reset" }
+ Method {
+ name: "setVisible"
+ Parameter { name: "v"; type: "bool" }
+ }
+ Method {
+ name: "setTitle"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setInformativeText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setDetailedText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setIcon"
+ Parameter { name: "icon"; type: "Icon" }
+ }
+ Method {
+ name: "setStandardButtons"
+ Parameter { name: "buttons"; type: "StandardButtons" }
+ }
+ Method {
+ name: "click"
+ Parameter { name: "button"; type: "QMessageDialogOptions::StandardButton" }
+ Parameter { type: "QMessageDialogOptions::ButtonRole" }
+ }
+ Method {
+ name: "click"
+ Parameter { name: "button"; type: "QQuickAbstractMessageDialog::StandardButton" }
+ }
+ Property { name: "implementation"; type: "QObject"; isPointer: true }
}
}
diff --git a/src/imports/dialogs/qml/Button.qml b/src/imports/dialogs/qml/Button.qml
index 19ed073484..f48264d5ff 100644
--- a/src/imports/dialogs/qml/Button.qml
+++ b/src/imports/dialogs/qml/Button.qml
@@ -49,8 +49,8 @@ Item {
signal clicked
property alias containsMouse: mouseArea.containsMouse
property alias pressed: mouseArea.pressed
- implicitHeight: Math.max(Screen.logicalPixelDensity * 7, buttonLabel.implicitHeight * 1.2)
- implicitWidth: visible ? Math.max(Screen.logicalPixelDensity * 11, buttonLabel.implicitWidth * 1.3) : 0
+ implicitHeight: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2)
+ implicitWidth: visible ? Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3) : 0
height: implicitHeight
width: implicitWidth
diff --git a/src/imports/dialogs/qml/DefaultWindowDecoration.qml b/src/imports/dialogs/qml/DefaultWindowDecoration.qml
index 69a8658aba..ec930101d2 100644
--- a/src/imports/dialogs/qml/DefaultWindowDecoration.qml
+++ b/src/imports/dialogs/qml/DefaultWindowDecoration.qml
@@ -55,11 +55,14 @@ Rectangle {
id: borderImage
property Item content
+ MouseArea { anchors.fill: parent }
+
width: content ? content.width + 15 : 0
height: content ? content.height + 15 : 0
onWidthChanged: content.x = 5
onHeightChanged: content.y = 5
border { left: 10; top: 10; right: 10; bottom: 10 }
+ clip: true
source: "../images/window_border.png"
anchors.centerIn: parent
onContentChanged: if (content) content.parent = borderImage
diff --git a/src/imports/dialogs/qml/TextField.qml b/src/imports/dialogs/qml/TextField.qml
index 9a6427a105..e67155086c 100644
--- a/src/imports/dialogs/qml/TextField.qml
+++ b/src/imports/dialogs/qml/TextField.qml
@@ -47,6 +47,8 @@ Item {
property alias text: textInput.text
signal accepted
signal downPressed
+ signal backPressed
+ signal escapePressed
implicitWidth: textInput.implicitWidth + rect.radius * 2
implicitHeight: textInput.implicitHeight
@@ -55,6 +57,11 @@ Item {
textInput.copy()
}
+ function paste() {
+ textInput.selectAll()
+ textInput.paste()
+ }
+
SystemPalette { id: palette }
height: textInput.implicitHeight + 8
clip: true
@@ -76,5 +83,7 @@ Item {
verticalAlignment: Text.AlignVCenter
onAccepted: root.accepted()
Keys.onDownPressed: root.downPressed()
+ Keys.onBackPressed: root.backPressed()
+ Keys.onEscapePressed: root.escapePressed()
}
}
diff --git a/src/imports/dialogs/qquickabstractmessagedialog.cpp b/src/imports/dialogs/qquickabstractmessagedialog.cpp
index cfcf056e6c..a44464962a 100644
--- a/src/imports/dialogs/qquickabstractmessagedialog.cpp
+++ b/src/imports/dialogs/qquickabstractmessagedialog.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qquickabstractmessagedialog_p.h"
+#include <QtGui/qpa/qplatformdialoghelper.h>
QT_BEGIN_NAMESPACE
@@ -133,10 +134,46 @@ void QQuickAbstractMessageDialog::setStandardButtons(StandardButtons buttons)
}
}
-void QQuickAbstractMessageDialog::click(QQuickAbstractMessageDialog::StandardButton button)
+void QQuickAbstractMessageDialog::click(QMessageDialogOptions::StandardButton button, QMessageDialogOptions::ButtonRole role)
{
- m_clickedButton = button;
+ setVisible(false);
+ m_clickedButton = static_cast<StandardButton>(button);
emit buttonClicked();
+ switch (role) {
+ case QMessageDialogOptions::AcceptRole:
+ emit accept();
+ break;
+ case QMessageDialogOptions::RejectRole:
+ emit reject();
+ break;
+ case QMessageDialogOptions::DestructiveRole:
+ emit discard();
+ break;
+ case QMessageDialogOptions::HelpRole:
+ emit help();
+ break;
+ case QMessageDialogOptions::YesRole:
+ emit yes();
+ break;
+ case QMessageDialogOptions::NoRole:
+ emit no();
+ break;
+ case QMessageDialogOptions::ApplyRole:
+ emit apply();
+ break;
+ case QMessageDialogOptions::ResetRole:
+ emit reset();
+ break;
+ default:
+ qWarning("unhandled MessageDialog button %d with role %d", button, role);
+ }
+}
+
+void QQuickAbstractMessageDialog::click(QQuickAbstractMessageDialog::StandardButton button)
+{
+ click(static_cast<QMessageDialogOptions::StandardButton>(button),
+ static_cast<QMessageDialogOptions::ButtonRole>(
+ QMessageDialogOptions::buttonRole(static_cast<QMessageDialogOptions::StandardButton>(button))));
}
QT_END_NAMESPACE
diff --git a/src/imports/dialogs/qquickabstractmessagedialog_p.h b/src/imports/dialogs/qquickabstractmessagedialog_p.h
index 3f1b842a96..f2427bb2e0 100644
--- a/src/imports/dialogs/qquickabstractmessagedialog_p.h
+++ b/src/imports/dialogs/qquickabstractmessagedialog_p.h
@@ -133,7 +133,8 @@ public Q_SLOTS:
void setDetailedText(const QString &arg);
void setIcon(Icon icon);
void setStandardButtons(StandardButtons buttons);
- void click(StandardButton button);
+ void click(QMessageDialogOptions::StandardButton button, QMessageDialogOptions::ButtonRole);
+ void click(QQuickAbstractMessageDialog::StandardButton button);
Q_SIGNALS:
void textChanged();
diff --git a/src/imports/dialogs/qquickmessageattached_p.h b/src/imports/dialogs/qquickdialogassets_p.h
index c1cb94ae36..406b68a66d 100644
--- a/src/imports/dialogs/qquickmessageattached_p.h
+++ b/src/imports/dialogs/qquickdialogassets_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QQUICKMESSAGEATTACHED_H
-#define QQUICKMESSAGEATTACHED_H
+#ifndef QQUICKDIALOGASSETS_P_H
+#define QQUICKDIALOGASSETS_P_H
#include <private/qtquickglobal_p.h>
#include <QtGui/qpa/qplatformdialoghelper.h>
@@ -48,22 +48,18 @@
QT_BEGIN_NAMESPACE
-class Q_DECL_EXPORT QQuickMessageAttached : public QObject
+class QQuickStandardButton
{
- Q_OBJECT
- Q_ENUMS(QQuickAbstractMessageDialog::Icon)
+ Q_GADGET
Q_ENUMS(QQuickAbstractMessageDialog::StandardButton)
+};
-public:
- static QQuickMessageAttached *qmlAttachedProperties(QObject *obj) {
- return new QQuickMessageAttached(obj); }
-
- QQuickMessageAttached(QObject *parent = 0) : QObject(parent) { }
+class QQuickStandardIcon
+{
+ Q_GADGET
+ Q_ENUMS(QQuickAbstractMessageDialog::Icon)
};
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickMessageAttached)
-QML_DECLARE_TYPEINFO(QQuickMessageAttached, QML_HAS_ATTACHED_PROPERTIES)
-
-#endif // QQUICKMESSAGEATTACHED_H
+#endif // QQUICKDIALOGASSETS_P_H
diff --git a/src/imports/dialogs/qquickplatformfontdialog.cpp b/src/imports/dialogs/qquickplatformfontdialog.cpp
index 8b2e0e0501..46ad5eb8df 100644
--- a/src/imports/dialogs/qquickplatformfontdialog.cpp
+++ b/src/imports/dialogs/qquickplatformfontdialog.cpp
@@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE
\instantiates QQuickPlatformFontDialog
\inqmlmodule QtQuick.Dialogs 1
\ingroup qtquick-visual
+ \ingroup dialogs
\brief Dialog component for choosing a font.
\since 5.2
diff --git a/src/imports/dialogs/qquickplatformmessagedialog.cpp b/src/imports/dialogs/qquickplatformmessagedialog.cpp
index 6ee8f10bd9..65114100d2 100644
--- a/src/imports/dialogs/qquickplatformmessagedialog.cpp
+++ b/src/imports/dialogs/qquickplatformmessagedialog.cpp
@@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
The most basic use case for a MessageDialog is a popup alert. It also
allows the user to respond in various ways depending on which buttons are
enabled. The dialog is initially invisible. You need to set the properties
- as desired first, then set \l visible to true or call \l open().
+ as desired first, then set \l visible to \c true or call \l open().
Here is a minimal example to show an alert and exit after the user
responds:
@@ -81,6 +81,11 @@ QT_BEGIN_NAMESPACE
}
\endqml
+ There are several possible handlers depending on which \l standardButtons
+ the dialog has and the \l {QMessageBox::ButtonRole} {ButtonRole} of each.
+ For example, the \l {rejected} {onRejected} handler will be called if the
+ user presses a \gui Cancel, \gui Close or \gui Abort button.
+
A MessageDialog window is automatically transient for its parent window. So
whether you declare the dialog inside an \l Item or inside a \l Window, the
dialog will appear centered over the window containing the item, or over
@@ -89,25 +94,73 @@ QT_BEGIN_NAMESPACE
The implementation of MessageDialog will be a platform message dialog if
possible. If that isn't possible, then it will try to instantiate a
\l QMessageBox. If that also isn't possible, then it will fall back to a QML
- implementation, DefaultMessageDialog.qml. In that case you can customize the
- appearance by editing this file. DefaultMessageDialog.qml contains a Rectangle
- to hold the dialog's contents, because certain embedded systems do not
- support multiple top-level windows. When the dialog becomes visible, it
- will automatically be wrapped in a Window if possible, or simply reparented
- on top of the main window if there can only be one window.
+ implementation, \c DefaultMessageDialog.qml. In that case you can customize
+ the appearance by editing this file. \c DefaultMessageDialog.qml contains a
+ \l Rectangle to hold the dialog's contents, because certain embedded systems
+ do not support multiple top-level windows. When the dialog becomes visible,
+ it will automatically be wrapped in a \l Window if possible, or simply
+ reparented on top of the main window if there can only be one window.
+*/
+
+/*!
+ \qmlsignal MessageDialog::accepted()
+
+ This handler is called when the user has pressed any button which has the
+ \l {QMessageBox::AcceptRole} {AcceptRole}: \gui OK, \gui Open, \gui Save,
+ \gui {Save All}, \gui Retry or \gui Ignore.
*/
/*!
- \qmlsignal QtQuick::Dialogs::MessageDialog::accepted
+ \qmlsignal MessageDialog::rejected()
- This handler is called when the user has pressed OK.
+ This handler is called when the user has dismissed the dialog, by closing
+ the dialog window, by pressing a \gui Cancel, \gui Close or \gui Abort
+ button on the dialog, or by pressing the back button or the escape key.
*/
/*!
- \qmlsignal QtQuick::Dialogs::MessageDialog::rejected
+ \qmlsignal MessageDialog::discard()
- This handler is called when the user has dismissed the dialog,
- either by closing the dialog window or by pressing the Cancel button.
+ This handler is called when the user has pressed the \gui Discard button.
+*/
+
+/*!
+ \qmlsignal MessageDialog::help()
+
+ This handler is called when the user has pressed the \gui Help button.
+ Depending on platform, the dialog may not be automatically dismissed
+ because the help that your application provides may need to be relevant to
+ the text shown in this dialog in order to assist the user in making a
+ decision. However on other platforms it's not possible to show a dialog and
+ a help window at the same time. If you want to be sure that the dialog will
+ close, you can set \l visible to \c false in your handler.
+*/
+
+/*!
+ \qmlsignal MessageDialog::yes()
+
+ This handler is called when the user has pressed any button which has
+ the \l {QMessageBox::YesRole} {YesRole}: \gui Yes or \gui {Yes to All}.
+*/
+
+/*!
+ \qmlsignal MessageDialog::no()
+
+ This handler is called when the user has pressed any button which has
+ the \l {QMessageBox::NoRole} {NoRole}: \gui No or \gui {No to All}.
+*/
+
+/*!
+ \qmlsignal MessageDialog::apply()
+
+ This handler is called when the user has pressed the \gui Apply button.
+*/
+
+/*!
+ \qmlsignal MessageDialog::reset()
+
+ This handler is called when the user has pressed any button which has
+ the \l {QMessageBox::ResetRole} {ResetRole}: \gui Reset or \gui {Restore Defaults}.
*/
/*!
@@ -153,8 +206,12 @@ QPlatformMessageDialogHelper *QQuickPlatformMessageDialog::helper()
->createPlatformDialogHelper(QPlatformTheme::MessageDialog));
if (!m_dlgHelper)
return m_dlgHelper;
+ // accept() shouldn't be emitted. reject() happens only if the dialog is
+ // dismissed by closing the window rather than by one of its button widgets.
connect(m_dlgHelper, SIGNAL(accept()), this, SLOT(accept()));
connect(m_dlgHelper, SIGNAL(reject()), this, SLOT(reject()));
+ connect(m_dlgHelper, SIGNAL(clicked(QMessageDialogOptions::StandardButton, QMessageDialogOptions::ButtonRole)),
+ this, SLOT(click(QMessageDialogOptions::StandardButton, QMessageDialogOptions::ButtonRole)));
}
return m_dlgHelper;
@@ -164,7 +221,7 @@ QPlatformMessageDialogHelper *QQuickPlatformMessageDialog::helper()
\qmlproperty bool MessageDialog::visible
This property holds whether the dialog is visible. By default this is
- false.
+ \c false.
\sa modality
*/
@@ -181,14 +238,14 @@ QPlatformMessageDialogHelper *QQuickPlatformMessageDialog::helper()
Modality does not mean that there are any blocking calls to wait for the
dialog to be accepted or rejected; it's only that the user will be
prevented from interacting with the parent window and/or the application
- windows at the same time.
+ windows until the dialog is dismissed.
*/
/*!
\qmlmethod void MessageDialog::open()
Shows the dialog to the user. It is equivalent to setting \l visible to
- true.
+ \c true.
*/
/*!
@@ -203,4 +260,139 @@ QPlatformMessageDialogHelper *QQuickPlatformMessageDialog::helper()
The title of the dialog window.
*/
+/*!
+ \qmlproperty string MessageDialog::text
+
+ The primary text to be displayed.
+*/
+
+/*!
+ \qmlproperty string MessageDialog::informativeText
+
+ The informative text that provides a fuller description for the message.
+
+ Informative text can be used to supplement the \c text to give more
+ information to the user. Depending on the platform, it may appear in a
+ smaller font below the text, or simply appended to the text.
+
+ \sa {MessageDialog::text}{text}
+*/
+
+/*!
+ \qmlproperty string MessageDialog::detailedText
+
+ The text to be displayed in the details area, which is hidden by default.
+ The user will then be able to press the \gui {Show Details...} button to
+ make it visible.
+
+ \sa {MessageDialog::text}{text}
+*/
+
+/*!
+ \enum QQuickStandardIcon::Icon
+
+ This enum specifies a standard icon to be used on a dialog.
+*/
+
+/*!
+ \qmlproperty QQuickStandardIcon::Icon MessageDialog::icon
+
+ The icon of the message box can be specified with one of these values:
+
+ \table
+ \row
+ \li no icon
+ \li \l StandardIcon.NoIcon
+ \li For an unadorned text alert.
+ \row
+ \li \inlineimage ../images/question.png "Question icon"
+ \li \l StandardIcon.Question
+ \li For asking a question during normal operations.
+ \row
+ \li \image information.png
+ \li \l StandardIcon.Information
+ \li For reporting information about normal operations.
+ \row
+ \li \image warning.png
+ \li \l StandardIcon.Warning
+ \li For reporting non-critical errors.
+ \row
+ \li \image critical.png
+ \li \l StandardIcon.Critical
+ \li For reporting critical errors.
+ \endtable
+
+ The default is \c StandardIcon.NoIcon.
+
+ The enum values are the same as in \l QMessageBox::Icon.
+*/
+
+// TODO after QTBUG-35019 is fixed: fix links to this module's enums
+// rather than linking to those in QMessageBox
+/*!
+ \enum QQuickStandardButton::StandardButton
+
+ This enum specifies a button with a standard label to be used on a dialog.
+*/
+
+/*!
+ \qmlproperty StandardButtons MessageDialog::standardButtons
+
+ The MessageDialog has a row of buttons along the bottom, each of which has
+ a \l {QMessageBox::ButtonRole} {ButtonRole} that determines which signal
+ will be emitted when the button is pressed. You can also find out which
+ specific button was pressed after the fact via the \l clickedButton
+ property. You can control which buttons are available by setting
+ standardButtons to a bitwise-or combination of the following flags:
+
+ \table
+ \row \li StandardButton.Ok \li An \gui OK button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}.
+ \row \li StandardButton.Open \li An \gui Open button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}.
+ \row \li StandardButton.Save \li A \gui Save button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}.
+ \row \li StandardButton.Cancel \li A \gui Cancel button defined with the \l {QMessageBox::RejectRole} {RejectRole}.
+ \row \li StandardButton.Close \li A \gui Close button defined with the \l {QMessageBox::RejectRole} {RejectRole}.
+ \row \li StandardButton.Discard \li A \gui Discard or \gui {Don't Save} button, depending on the platform,
+ defined with the \l {QMessageBox::DestructiveRole} {DestructiveRole}.
+ \row \li StandardButton.Apply \li An \gui Apply button defined with the \l {QMessageBox::ApplyRole} {ApplyRole}.
+ \row \li StandardButton.Reset \li A \gui Reset button defined with the \l {QMessageBox::ResetRole} {ResetRole}.
+ \row \li StandardButton.RestoreDefaults \li A \gui {Restore Defaults} button defined with the \l {QMessageBox::ResetRole} {ResetRole}.
+ \row \li StandardButton.Help \li A \gui Help button defined with the \l {QMessageBox::HelpRole} {HelpRole}.
+ \row \li StandardButton.SaveAll \li A \gui {Save All} button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}.
+ \row \li StandardButton.Yes \li A \gui Yes button defined with the \l {QMessageBox::YesRole} {YesRole}.
+ \row \li StandardButton.YesToAll \li A \gui {Yes to All} button defined with the \l {QMessageBox::YesRole} {YesRole}.
+ \row \li StandardButton.No \li A \gui No button defined with the \l {QMessageBox::NoRole} {NoRole}.
+ \row \li StandardButton.NoToAll \li A \gui {No to All} button defined with the \l {QMessageBox::NoRole} {NoRole}.
+ \row \li StandardButton.Abort \li An \gui Abort button defined with the \l {QMessageBox::RejectRole} {RejectRole}.
+ \row \li StandardButton.Retry \li A \gui Retry button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}.
+ \row \li StandardButton.Ignore \li An \gui Ignore button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}.
+ \endtable
+
+ For example the following dialog will ask a question with 5 possible answers:
+
+ \qml
+ import QtQuick 2.2
+ import QtQuick.Dialogs 1.1
+
+ MessageDialog {
+ title: "Overwrite?"
+ icon: StandardIcon.Question
+ text: "file.txt already exists. Replace?"
+ detailedText: "To replace a file means that its existing contents will be lost. " +
+ "The file that you are copying now will be copied over it instead."
+ standardButtons: StandardButton.Yes | StandardButton.YesToAll |
+ StandardButton.No | StandardButton.NoToAll | StandardButton.Abort
+ Component.onCompleted: visible = true
+ onYes: console.log("copied")
+ onNo: console.log("didn't copy")
+ onRejected: console.log("aborted")
+ }
+ \endqml
+
+ \image replacefile.png
+
+ The default is \c StandardButton.Ok.
+
+ The enum values are the same as in \l QMessageBox::StandardButtons.
+*/
+
QT_END_NAMESPACE
diff --git a/src/imports/folderlistmodel/fileinfothread.cpp b/src/imports/folderlistmodel/fileinfothread.cpp
index 4aa43b2d3f..f7587c25f5 100644
--- a/src/imports/folderlistmodel/fileinfothread.cpp
+++ b/src/imports/folderlistmodel/fileinfothread.cpp
@@ -59,6 +59,7 @@ FileInfoThread::FileInfoThread(QObject *parent)
showDirs(true),
showDirsFirst(false),
showDotAndDotDot(false),
+ showHidden(false),
showOnlyReadable(false)
{
#ifndef QT_NO_FILESYSTEMWATCHER
@@ -176,6 +177,15 @@ void FileInfoThread::setShowDotAndDotDot(bool on)
condition.wakeAll();
}
+void FileInfoThread::setShowHidden(bool on)
+{
+ QMutexLocker locker(&mutex);
+ showHidden = on;
+ folderUpdate = true;
+ needUpdate = true;
+ condition.wakeAll();
+}
+
void FileInfoThread::setShowOnlyReadable(bool on)
{
QMutexLocker locker(&mutex);
@@ -231,6 +241,8 @@ void FileInfoThread::getFileInfos(const QString &path)
filter = filter | QDir::NoDot | QDir::NoDotDot;
else if (path == rootPath)
filter = filter | QDir::NoDotDot;
+ if (showHidden)
+ filter = filter | QDir::Hidden;
if (showOnlyReadable)
filter = filter | QDir::Readable;
if (showDirsFirst)
diff --git a/src/imports/folderlistmodel/fileinfothread_p.h b/src/imports/folderlistmodel/fileinfothread_p.h
index d50361de3a..d54b2dfcae 100644
--- a/src/imports/folderlistmodel/fileinfothread_p.h
+++ b/src/imports/folderlistmodel/fileinfothread_p.h
@@ -74,6 +74,7 @@ public:
void setShowDirs(bool showFolders);
void setShowDirsFirst(bool show);
void setShowDotAndDotDot(bool on);
+ void setShowHidden(bool on);
void setShowOnlyReadable(bool on);
public Q_SLOTS:
@@ -107,6 +108,7 @@ private:
bool showDirs;
bool showDirsFirst;
bool showDotAndDotDot;
+ bool showHidden;
bool showOnlyReadable;
};
diff --git a/src/imports/folderlistmodel/folderlistmodel.pro b/src/imports/folderlistmodel/folderlistmodel.pro
index c8c805adb6..99c54113e4 100644
--- a/src/imports/folderlistmodel/folderlistmodel.pro
+++ b/src/imports/folderlistmodel/folderlistmodel.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qmlfolderlistmodelplugin
TARGETPATH = Qt/labs/folderlistmodel
-IMPORT_VERSION = 2.0
+IMPORT_VERSION = 2.1
QT = core-private qml-private
diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp
index ef0947af76..9e8b65863c 100644
--- a/src/imports/folderlistmodel/plugin.cpp
+++ b/src/imports/folderlistmodel/plugin.cpp
@@ -59,6 +59,7 @@ public:
#ifndef QT_NO_DIRMODEL
qmlRegisterType<QQuickFolderListModel>(uri,1,0,"FolderListModel");
qmlRegisterType<QQuickFolderListModel>(uri,2,0,"FolderListModel");
+ qmlRegisterType<QQuickFolderListModel,1>(uri,2,1,"FolderListModel");
#endif
}
};
diff --git a/src/imports/folderlistmodel/plugins.qmltypes b/src/imports/folderlistmodel/plugins.qmltypes
index 20914f4108..a55d3a3499 100644
--- a/src/imports/folderlistmodel/plugins.qmltypes
+++ b/src/imports/folderlistmodel/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable Qt.labs.folderlistmodel 2.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable Qt.labs.folderlistmodel 2.1'
Module {
Component {
@@ -11,9 +12,10 @@ Module {
prototype: "QAbstractListModel"
exports: [
"Qt.labs.folderlistmodel/FolderListModel 1.0",
- "Qt.labs.folderlistmodel/FolderListModel 2.0"
+ "Qt.labs.folderlistmodel/FolderListModel 2.0",
+ "Qt.labs.folderlistmodel/FolderListModel 2.1"
]
- exportMetaObjectRevisions: [0, 0]
+ exportMetaObjectRevisions: [0, 0, 1]
Enum {
name: "SortField"
values: {
@@ -30,12 +32,15 @@ Module {
Property { name: "nameFilters"; type: "QStringList" }
Property { name: "sortField"; type: "SortField" }
Property { name: "sortReversed"; type: "bool" }
+ Property { name: "showFiles"; revision: 1; type: "bool" }
Property { name: "showDirs"; type: "bool" }
Property { name: "showDirsFirst"; type: "bool" }
Property { name: "showDotAndDotDot"; type: "bool" }
+ Property { name: "showHidden"; revision: 1; type: "bool" }
Property { name: "showOnlyReadable"; type: "bool" }
Property { name: "count"; type: "int"; isReadonly: true }
Signal { name: "rowCountChanged" }
+ Signal { name: "countChanged"; revision: 1 }
Method {
name: "isFolder"
type: "bool"
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index 7cab257d32..f425eaa220 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -56,7 +56,8 @@ public:
QQuickFolderListModelPrivate(QQuickFolderListModel *q)
: q_ptr(q),
sortField(QQuickFolderListModel::Name), sortReversed(false), showFiles(true),
- showDirs(true), showDirsFirst(false), showDotAndDotDot(false), showOnlyReadable(false)
+ showDirs(true), showDirsFirst(false), showDotAndDotDot(false), showOnlyReadable(false),
+ showHidden(false)
{
nameFilters << QLatin1String("*");
}
@@ -76,6 +77,7 @@ public:
bool showDirsFirst;
bool showDotAndDotDot;
bool showOnlyReadable;
+ bool showHidden;
~QQuickFolderListModelPrivate() {}
void init();
@@ -215,7 +217,7 @@ QString QQuickFolderListModelPrivate::resolvePath(const QUrl &path)
}
/*!
- \qmlmodule Qt.labs.folderlistmodel 1.0
+ \qmlmodule Qt.labs.folderlistmodel 2.1
\title Qt Labs FolderListModel QML Types
\ingroup qmlmodules
\brief The FolderListModel provides a model of the contents of a file system folder.
@@ -223,14 +225,14 @@ QString QQuickFolderListModelPrivate::resolvePath(const QUrl &path)
To use this module, import the module with the following line:
\code
- import Qt.labs.folderlistmodel 1.0
+ import Qt.labs.folderlistmodel 2.1
\endcode
*/
/*!
\qmltype FolderListModel
- \inqmlmodule Qt.labs.folderlistmodel 1.0
+ \inqmlmodule Qt.labs.folderlistmodel
\instantiates QQuickFolderListModel
\ingroup qtquick-models
\brief The FolderListModel provides a model of the contents of a file system folder.
@@ -242,7 +244,7 @@ QString QQuickFolderListModelPrivate::resolvePath(const QUrl &path)
\e{Elements in the Qt.labs module are not guaranteed to remain compatible
in future versions.}
- \b{import Qt.labs.folderlistmodel 1.0}
+ \b{import Qt.labs.folderlistmodel 2.1}
The \l folder property specifies the folder to access. Information about the
files and directories in the folder is supplied via the model's interface.
@@ -251,6 +253,7 @@ QString QQuickFolderListModelPrivate::resolvePath(const QUrl &path)
\list
\li \c fileName
\li \c filePath
+ \li \c fileURL (since Qt 5.2)
\li \c fileBaseName
\li \c fileSuffix
\li \c fileSize
@@ -271,9 +274,10 @@ QString QQuickFolderListModelPrivate::resolvePath(const QUrl &path)
that are applied to names of files and directories, causing only those that
match the filters to be exposed.
- Directories can be included or excluded using the \l showDirs property, and
+ Directories can be included or excluded using the \l showDirs property,
navigation directories can also be excluded by setting the \l showDotAndDotDot
- property to false.
+ property to false, hidden files can be included or excluded using the
+ \l showHidden property.
It is sometimes useful to limit the files and directories exposed to those
that the user can access. The \l showOnlyReadable property can be set to
@@ -286,7 +290,7 @@ QString QQuickFolderListModelPrivate::resolvePath(const QUrl &path)
\qml
import QtQuick 2.0
- import Qt.labs.folderlistmodel 1.0
+ import Qt.labs.folderlistmodel 2.1
ListView {
width: 200; height: 400
@@ -624,6 +628,7 @@ bool QQuickFolderListModel::isFolder(int index) const
/*!
\qmlproperty bool FolderListModel::showFiles
+ \since 5.2
If true, files are included in the model; otherwise only directories
are included.
@@ -721,6 +726,31 @@ void QQuickFolderListModel::setShowDotAndDotDot(bool on)
}
}
+
+/*!
+ \qmlproperty bool FolderListModel::showHidden
+ \since 5.2
+
+ If true, hidden files and directories are included in the model; otherwise
+ they are excluded.
+
+ By default, this property is false.
+*/
+bool QQuickFolderListModel::showHidden() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->showHidden;
+}
+
+void QQuickFolderListModel::setShowHidden(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ if (on != d->showHidden) {
+ d->fileInfoThread.setShowHidden(on);
+ }
+}
+
/*!
\qmlproperty bool FolderListModel::showOnlyReadable
@@ -747,7 +777,7 @@ void QQuickFolderListModel::setShowOnlyReadable(bool on)
}
/*!
- \qmlmethod QVariant QQuickFolderListModel::get(int idx, const QString &property) const
+ \qmlmethod var FolderListModel::get(int index, string property)
Get the folder property for the given index. The following properties
are available.
@@ -755,7 +785,7 @@ void QQuickFolderListModel::setShowOnlyReadable(bool on)
\list
\li \c fileName
\li \c filePath
- \li \c fileURL
+ \li \c fileURL (since Qt 5.2)
\li \c fileBaseName
\li \c fileSuffix
\li \c fileSize
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.h b/src/imports/folderlistmodel/qquickfolderlistmodel.h
index 3bf9a21d49..fe60c8d4c1 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.h
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.h
@@ -69,10 +69,11 @@ class QQuickFolderListModel : public QAbstractListModel, public QQmlParserStatus
Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters)
Q_PROPERTY(SortField sortField READ sortField WRITE setSortField)
Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed)
- Q_PROPERTY(bool showFiles READ showFiles WRITE setShowFiles)
+ Q_PROPERTY(bool showFiles READ showFiles WRITE setShowFiles REVISION 1)
Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs)
Q_PROPERTY(bool showDirsFirst READ showDirsFirst WRITE setShowDirsFirst)
Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot)
+ Q_PROPERTY(bool showHidden READ showHidden WRITE setShowHidden REVISION 1)
Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable)
Q_PROPERTY(int count READ count NOTIFY countChanged)
//![class props]
@@ -131,6 +132,8 @@ public:
void setShowDirsFirst(bool showDirsFirst);
bool showDotAndDotDot() const;
void setShowDotAndDotDot(bool on);
+ bool showHidden() const;
+ void setShowHidden(bool on);
bool showOnlyReadable() const;
void setShowOnlyReadable(bool on);
//![prop funcs]
@@ -149,7 +152,7 @@ public:
Q_SIGNALS:
void folderChanged();
void rowCountChanged() const;
- void countChanged() const;
+ Q_REVISION(1) void countChanged() const;
//![notifier]
//![class end]
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 2b3ef34d4c..145487cf3e 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -68,11 +68,21 @@ using namespace QV4;
QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \
ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \
ctx->throwError(ex); \
+ return Encode::undefined(); \
+}
+
+#define V4THROW_SQL2(error, desc) { \
+ QV4::Scoped<String> v(scope, ctx->engine->newString(desc)); \
+ QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \
+ ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \
+ args->setReturnValue(ctx->throwError(ex)); \
+ return; \
}
#define V4THROW_REFERENCE(string) { \
QV4::Scoped<String> v(scope, ctx->engine->newString(string)); \
ctx->throwReferenceError(v); \
+ return Encode::undefined(); \
}
@@ -123,7 +133,7 @@ public:
DEFINE_MANAGED_VTABLE(QQmlSqlDatabaseWrapper);
-static ReturnedValue qmlsqldatabase_version(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_version(CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
@@ -133,7 +143,7 @@ static ReturnedValue qmlsqldatabase_version(SimpleCallContext *ctx)
return Encode(ctx->engine->newString(r->version));
}
-static ReturnedValue qmlsqldatabase_rows_length(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_rows_length(CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
@@ -152,7 +162,7 @@ static ReturnedValue qmlsqldatabase_rows_length(SimpleCallContext *ctx)
return Encode(s);
}
-static ReturnedValue qmlsqldatabase_rows_forwardOnly(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_rows_forwardOnly(CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
@@ -161,14 +171,14 @@ static ReturnedValue qmlsqldatabase_rows_forwardOnly(SimpleCallContext *ctx)
return Encode(r->sqlQuery.isForwardOnly());
}
-static ReturnedValue qmlsqldatabase_rows_setForwardOnly(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_rows_setForwardOnly(CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
if (ctx->callData->argc < 1)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
r->sqlQuery.setForwardOnly(ctx->callData->args[0].toBoolean());
return Encode::undefined();
@@ -231,7 +241,7 @@ ReturnedValue QQmlSqlDatabaseWrapper::getIndexed(Managed *m, uint index, bool *h
return qmlsqldatabase_rows_index(r, m->engine(), index, hasProperty);
}
-static ReturnedValue qmlsqldatabase_rows_item(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_rows_item(CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
@@ -241,7 +251,7 @@ static ReturnedValue qmlsqldatabase_rows_item(SimpleCallContext *ctx)
return qmlsqldatabase_rows_index(r, ctx->engine, ctx->callData->argc ? ctx->callData->args[0].toUInt32() : 0);
}
-static ReturnedValue qmlsqldatabase_executeSql(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
@@ -353,7 +363,7 @@ struct TransactionRollback {
};
-static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
{
if (ctx->callData->argc < 2)
return Encode::undefined();
@@ -412,7 +422,7 @@ static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx)
return Encode::undefined();
}
-static ReturnedValue qmlsqldatabase_transaction_shared(SimpleCallContext *ctx, bool readOnly)
+static ReturnedValue qmlsqldatabase_transaction_shared(CallContext *ctx, bool readOnly)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
@@ -451,12 +461,12 @@ static ReturnedValue qmlsqldatabase_transaction_shared(SimpleCallContext *ctx, b
return Encode::undefined();
}
-static ReturnedValue qmlsqldatabase_transaction(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_transaction(CallContext *ctx)
{
return qmlsqldatabase_transaction_shared(ctx, false);
}
-static ReturnedValue qmlsqldatabase_read_transaction(SimpleCallContext *ctx)
+static ReturnedValue qmlsqldatabase_read_transaction(CallContext *ctx)
{
return qmlsqldatabase_transaction_shared(ctx, true);
}
@@ -652,7 +662,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
QV4::ExecutionContext *ctx = args->v4engine()->current;
QV4::Scope scope(ctx);
if (engine->engine()->offlineStoragePath().isEmpty())
- V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
+ V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
qmlsqldatabase_initDatabasesPath(engine);
@@ -680,7 +690,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
database = QSqlDatabase::database(dbid);
version = ini.value(QLatin1String("Version")).toString();
if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
- V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch"));
+ V4THROW_SQL2(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch"));
} else {
created = !QFile::exists(basename+QLatin1String(".sqlite"));
database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
@@ -695,7 +705,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
} else {
if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
// Incompatible
- V4THROW_SQL(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch"));
+ V4THROW_SQL2(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch"));
}
version = ini.value(QLatin1String("Version")).toString();
}
diff --git a/src/imports/localstorage/plugins.qmltypes b/src/imports/localstorage/plugins.qmltypes
index bcd516c25e..05bcc875f7 100644
--- a/src/imports/localstorage/plugins.qmltypes
+++ b/src/imports/localstorage/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable QtQuick.LocalStorage 2.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtQuick.LocalStorage 2.0'
Module {
Component {
diff --git a/src/imports/particles/plugins.qmltypes b/src/imports/particles/plugins.qmltypes
index 495c072a41..712d4fd844 100644
--- a/src/imports/particles/plugins.qmltypes
+++ b/src/imports/particles/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable QtQuick.Particles 2.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtQuick.Particles 2.0'
Module {
Component {
diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes
index 02c7d61536..cadef10370 100644
--- a/src/imports/qtquick2/plugins.qmltypes
+++ b/src/imports/qtquick2/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable -builtins'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -builtins'
Module {
Component {
@@ -222,6 +223,85 @@ Module {
}
}
Component {
+ name: "QKeySequence"
+ exports: ["QtQuick/StandardKey 2.2"]
+ exportMetaObjectRevisions: [2]
+ Enum {
+ name: "StandardKey"
+ values: {
+ "UnknownKey": 0,
+ "HelpContents": 1,
+ "WhatsThis": 2,
+ "Open": 3,
+ "Close": 4,
+ "Save": 5,
+ "New": 6,
+ "Delete": 7,
+ "Cut": 8,
+ "Copy": 9,
+ "Paste": 10,
+ "Undo": 11,
+ "Redo": 12,
+ "Back": 13,
+ "Forward": 14,
+ "Refresh": 15,
+ "ZoomIn": 16,
+ "ZoomOut": 17,
+ "Print": 18,
+ "AddTab": 19,
+ "NextChild": 20,
+ "PreviousChild": 21,
+ "Find": 22,
+ "FindNext": 23,
+ "FindPrevious": 24,
+ "Replace": 25,
+ "SelectAll": 26,
+ "Bold": 27,
+ "Italic": 28,
+ "Underline": 29,
+ "MoveToNextChar": 30,
+ "MoveToPreviousChar": 31,
+ "MoveToNextWord": 32,
+ "MoveToPreviousWord": 33,
+ "MoveToNextLine": 34,
+ "MoveToPreviousLine": 35,
+ "MoveToNextPage": 36,
+ "MoveToPreviousPage": 37,
+ "MoveToStartOfLine": 38,
+ "MoveToEndOfLine": 39,
+ "MoveToStartOfBlock": 40,
+ "MoveToEndOfBlock": 41,
+ "MoveToStartOfDocument": 42,
+ "MoveToEndOfDocument": 43,
+ "SelectNextChar": 44,
+ "SelectPreviousChar": 45,
+ "SelectNextWord": 46,
+ "SelectPreviousWord": 47,
+ "SelectNextLine": 48,
+ "SelectPreviousLine": 49,
+ "SelectNextPage": 50,
+ "SelectPreviousPage": 51,
+ "SelectStartOfLine": 52,
+ "SelectEndOfLine": 53,
+ "SelectStartOfBlock": 54,
+ "SelectEndOfBlock": 55,
+ "SelectStartOfDocument": 56,
+ "SelectEndOfDocument": 57,
+ "DeleteStartOfWord": 58,
+ "DeleteEndOfWord": 59,
+ "DeleteEndOfLine": 60,
+ "InsertParagraphSeparator": 61,
+ "InsertLineSeparator": 62,
+ "SaveAs": 63,
+ "Preferences": 64,
+ "Quit": 65,
+ "FullScreen": 66,
+ "Deselect": 67,
+ "DeleteCompleteLine": 68
+ }
+ }
+ }
+ Component {
name: "QObject"
exports: ["QtQml/QtObject 2.0", "QtQuick/QtObject 2.0"]
exportMetaObjectRevisions: [0, 0]
@@ -243,6 +323,8 @@ Module {
Property { name: "arguments"; type: "QStringList"; isReadonly: true }
Property { name: "name"; type: "string" }
Property { name: "version"; type: "string" }
+ Property { name: "organization"; type: "string" }
+ Property { name: "domain"; type: "string" }
Signal { name: "aboutToQuit" }
Method {
name: "setName"
@@ -252,6 +334,14 @@ Module {
name: "setVersion"
Parameter { name: "arg"; type: "string" }
}
+ Method {
+ name: "setOrganization"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setDomain"
+ Parameter { name: "arg"; type: "string" }
+ }
}
Component {
name: "QQmlBind"
@@ -378,44 +468,44 @@ Module {
Signal { name: "defaultIncludeChanged" }
Signal {
name: "changed"
- Parameter { name: "removed"; type: "QQmlV8Handle" }
- Parameter { name: "inserted"; type: "QQmlV8Handle" }
+ Parameter { name: "removed"; type: "QQmlV4Handle" }
+ Parameter { name: "inserted"; type: "QQmlV4Handle" }
}
Method {
name: "insert"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "create"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "resolve"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "remove"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "addGroups"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "removeGroups"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "setGroups"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "move"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "get"
- type: "QQmlV8Handle"
+ type: "QQmlV4Handle"
Parameter { name: "index"; type: "int" }
}
}
@@ -550,25 +640,25 @@ Module {
Method { name: "clear" }
Method {
name: "remove"
- Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true }
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "append"
- Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true }
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "insert"
- Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true }
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "get"
- type: "QQmlV8Handle"
+ type: "QQmlV4Handle"
Parameter { name: "index"; type: "int" }
}
Method {
name: "set"
Parameter { name: "index"; type: "int" }
- Parameter { type: "QQmlV8Handle" }
+ Parameter { type: "QQmlV4Handle" }
}
Method {
name: "setProperty"
@@ -586,8 +676,8 @@ Module {
}
Component {
name: "QQmlLocale"
- exports: ["QtQuick/Locale 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQml/Locale 2.2", "QtQuick/Locale 2.0"]
+ exportMetaObjectRevisions: [0, 0]
Enum {
name: "MeasurementSystem"
values: {
@@ -958,6 +1048,37 @@ Module {
Property { name: "animations"; type: "QQuickAbstractAnimation"; isList: true; isReadonly: true }
}
Component {
+ name: "QQuickAnimator"
+ prototype: "QQuickAbstractAnimation"
+ exports: ["QtQuick/Animator 2.2"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "target"; type: "QQuickItem"; isPointer: true }
+ Property { name: "easing"; type: "QEasingCurve" }
+ Property { name: "duration"; type: "int" }
+ Property { name: "to"; type: "double" }
+ Property { name: "from"; type: "double" }
+ Signal {
+ name: "targetItemChanged"
+ Parameter { type: "QQuickItem"; isPointer: true }
+ }
+ Signal {
+ name: "durationChanged"
+ Parameter { name: "duration"; type: "int" }
+ }
+ Signal {
+ name: "easingChanged"
+ Parameter { name: "curve"; type: "QEasingCurve" }
+ }
+ Signal {
+ name: "toChanged"
+ Parameter { name: "to"; type: "double" }
+ }
+ Signal {
+ name: "fromChanged"
+ Parameter { name: "from"; type: "double" }
+ }
+ }
+ Component {
name: "QQuickApplication"
prototype: "QQmlApplication"
exports: ["QtQuick/Application 2.0"]
@@ -965,6 +1086,11 @@ Module {
Property { name: "active"; type: "bool"; isReadonly: true }
Property { name: "layoutDirection"; type: "Qt::LayoutDirection"; isReadonly: true }
Property { name: "supportsMultipleWindows"; type: "bool"; isReadonly: true }
+ Property { name: "state"; type: "Qt::ApplicationState"; isReadonly: true }
+ Signal {
+ name: "stateChanged"
+ Parameter { name: "state"; type: "Qt::ApplicationState" }
+ }
}
Component {
name: "QQuickBasePositioner"
@@ -1066,15 +1192,15 @@ Module {
}
Method {
name: "getContext"
- Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true }
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "requestAnimationFrame"
- Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true }
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "cancelRequestAnimationFrame"
- Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true }
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
}
Method { name: "requestPaint" }
Method {
@@ -1132,6 +1258,14 @@ Module {
exportMetaObjectRevisions: [0]
attachedType: "QQuickDragAttached"
Enum {
+ name: "DragType"
+ values: {
+ "None": 0,
+ "Automatic": 1,
+ "Internal": 2
+ }
+ }
+ Enum {
name: "Axis"
values: {
"XAxis": 1,
@@ -1148,6 +1282,7 @@ Module {
Property { name: "maximumY"; type: "double" }
Property { name: "active"; type: "bool"; isReadonly: true }
Property { name: "filterChildren"; type: "bool" }
+ Property { name: "threshold"; type: "double" }
}
Component {
name: "QQuickDragAttached"
@@ -1157,11 +1292,22 @@ Module {
Property { name: "target"; type: "QObject"; isReadonly: true; isPointer: true }
Property { name: "hotSpot"; type: "QPointF" }
Property { name: "keys"; type: "QStringList" }
+ Property { name: "mimeData"; type: "QVariantMap" }
Property { name: "supportedActions"; type: "Qt::DropActions" }
Property { name: "proposedAction"; type: "Qt::DropAction" }
+ Property { name: "dragType"; type: "QQuickDrag::DragType" }
+ Signal { name: "dragStarted" }
+ Signal {
+ name: "dragFinished"
+ Parameter { name: "dropAction"; type: "Qt::DropAction" }
+ }
Method {
name: "start"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "startDrag"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method { name: "cancel" }
Method { name: "drop"; type: "int" }
@@ -1743,11 +1889,11 @@ Module {
}
Method {
name: "mapFromItem"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "mapToItem"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method { name: "forceActiveFocus" }
Method {
@@ -1756,10 +1902,11 @@ Module {
}
Method {
name: "nextItemInFocusChain"
+ revision: 1
type: "QQuickItem*"
Parameter { name: "forward"; type: "bool" }
}
- Method { name: "nextItemInFocusChain"; type: "QQuickItem*" }
+ Method { name: "nextItemInFocusChain"; revision: 1; type: "QQuickItem*" }
Method {
name: "childAt"
type: "QQuickItem*"
@@ -2195,7 +2342,7 @@ Module {
Signal { name: "loaded" }
Method {
name: "setSource"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
}
Component {
@@ -2312,6 +2459,12 @@ Module {
Property { name: "to"; type: "double" }
}
Component {
+ name: "QQuickOpacityAnimator"
+ prototype: "QQuickAnimator"
+ exports: ["QtQuick/OpacityAnimator 2.2"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
name: "QQuickPackage"
defaultProperty: "data"
prototype: "QObject"
@@ -2825,6 +2978,26 @@ Module {
Property { name: "direction"; type: "RotationDirection" }
}
Component {
+ name: "QQuickRotationAnimator"
+ prototype: "QQuickAnimator"
+ exports: ["QtQuick/RotationAnimator 2.2"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "RotationDirection"
+ values: {
+ "Numerical": 0,
+ "Shortest": 1,
+ "Clockwise": 2,
+ "Counterclockwise": 3
+ }
+ }
+ Property { name: "direction"; type: "RotationDirection" }
+ Signal {
+ name: "directionChanged"
+ Parameter { name: "dir"; type: "RotationDirection" }
+ }
+ }
+ Component {
name: "QQuickRow"
defaultProperty: "data"
prototype: "QQuickBasePositioner"
@@ -2845,6 +3018,12 @@ Module {
Signal { name: "scaleChanged" }
}
Component {
+ name: "QQuickScaleAnimator"
+ prototype: "QQuickAnimator"
+ exports: ["QtQuick/ScaleAnimator 2.2"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
name: "QQuickScaleGrid"
prototype: "QObject"
Property { name: "left"; type: "int" }
@@ -3251,8 +3430,8 @@ Module {
name: "QQuickText"
defaultProperty: "data"
prototype: "QQuickImplicitSizeItem"
- exports: ["QtQuick/Text 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/Text 2.0", "QtQuick/Text 2.2"]
+ exportMetaObjectRevisions: [0, 2]
Enum {
name: "HAlignment"
values: {
@@ -3356,6 +3535,7 @@ Module {
Property { name: "minimumPointSize"; type: "int" }
Property { name: "fontSizeMode"; type: "FontSizeMode" }
Property { name: "renderType"; type: "RenderType" }
+ Property { name: "hoveredLink"; revision: 2; type: "string"; isReadonly: true }
Signal {
name: "textChanged"
Parameter { name: "text"; type: "string" }
@@ -3365,6 +3545,11 @@ Module {
Parameter { name: "link"; type: "string" }
}
Signal {
+ name: "linkHovered"
+ revision: 2
+ Parameter { name: "link"; type: "string" }
+ }
+ Signal {
name: "fontChanged"
Parameter { name: "font"; type: "QFont" }
}
@@ -3408,8 +3593,12 @@ Module {
name: "QQuickTextEdit"
defaultProperty: "data"
prototype: "QQuickImplicitSizeItem"
- exports: ["QtQuick/TextEdit 2.0", "QtQuick/TextEdit 2.1"]
- exportMetaObjectRevisions: [0, 1]
+ exports: [
+ "QtQuick/TextEdit 2.0",
+ "QtQuick/TextEdit 2.1",
+ "QtQuick/TextEdit 2.2"
+ ]
+ exportMetaObjectRevisions: [0, 1, 2]
Enum {
name: "HAlignment"
values: {
@@ -3503,6 +3692,7 @@ Module {
isReadonly: true
isPointer: true
}
+ Property { name: "hoveredLink"; revision: 2; type: "string"; isReadonly: true }
Signal { name: "contentSizeChanged" }
Signal {
name: "colorChanged"
@@ -3569,6 +3759,11 @@ Module {
name: "linkActivated"
Parameter { name: "link"; type: "string" }
}
+ Signal {
+ name: "linkHovered"
+ revision: 2
+ Parameter { name: "link"; type: "string" }
+ }
Method { name: "selectAll" }
Method { name: "selectWord" }
Method {
@@ -3599,6 +3794,11 @@ Module {
Parameter { name: "end"; type: "int" }
}
Method {
+ name: "append"
+ revision: 2
+ Parameter { name: "text"; type: "string" }
+ }
+ Method {
name: "positionToRectangle"
type: "QRectF"
Parameter { type: "int" }
@@ -3812,7 +4012,7 @@ Module {
}
Method {
name: "positionAt"
- Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true }
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "positionToRectangle"
@@ -3877,6 +4077,17 @@ Module {
Property { name: "y"; type: "double" }
}
Component {
+ name: "QQuickUniformAnimator"
+ prototype: "QQuickAnimator"
+ exports: ["QtQuick/UniformAnimator 2.2"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "uniform"; type: "string" }
+ Signal {
+ name: "uniformChanged"
+ Parameter { type: "string" }
+ }
+ }
+ Component {
name: "QQuickVector3dAnimation"
prototype: "QQuickPropertyAnimation"
exports: ["QtQuick/Vector3dAnimation 2.0"]
@@ -3933,10 +4144,22 @@ Module {
}
Method {
name: "sendMessage"
- Parameter { type: "QQmlV8Function"; isPointer: true }
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
}
Component {
+ name: "QQuickXAnimator"
+ prototype: "QQuickAnimator"
+ exports: ["QtQuick/XAnimator 2.2"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QQuickYAnimator"
+ prototype: "QQuickAnimator"
+ exports: ["QtQuick/YAnimator 2.2"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
name: "QRegExpValidator"
prototype: "QValidator"
exports: ["QtQuick/RegExpValidator 2.0"]
@@ -4079,7 +4302,8 @@ Module {
"AlignTop": 32,
"AlignBottom": 64,
"AlignVCenter": 128,
- "AlignVertical_Mask": 224,
+ "AlignBaseline": 256,
+ "AlignVertical_Mask": 480,
"AlignCenter": 132
}
}
@@ -4107,6 +4331,7 @@ Module {
"Desktop": 17,
"SubWindow": 18,
"ForeignWindow": 33,
+ "CoverWindow": 65,
"WindowType_Mask": 255,
"MSWindowsFixedSizeDialogHint": 256,
"MSWindowsOwnDC": 512,
@@ -4150,6 +4375,7 @@ Module {
"Desktop": 17,
"SubWindow": 18,
"ForeignWindow": 33,
+ "CoverWindow": 65,
"WindowType_Mask": 255,
"MSWindowsFixedSizeDialogHint": 256,
"MSWindowsOwnDC": 512,
@@ -4199,6 +4425,15 @@ Module {
}
}
Enum {
+ name: "ApplicationState"
+ values: {
+ "ApplicationSuspended": 0,
+ "ApplicationHidden": 1,
+ "ApplicationInactive": 2,
+ "ApplicationActive": 4
+ }
+ }
+ Enum {
name: "ScreenOrientation"
values: {
"PrimaryOrientation": 0,
@@ -4785,6 +5020,13 @@ Module {
"Key_TouchpadToggle": 16777488,
"Key_TouchpadOn": 16777489,
"Key_TouchpadOff": 16777490,
+ "Key_MicMute": 16777491,
+ "Key_Red": 16777492,
+ "Key_Green": 16777493,
+ "Key_Yellow": 16777494,
+ "Key_Blue": 16777495,
+ "Key_ChannelUp": 16777496,
+ "Key_ChannelDown": 16777497,
"Key_MediaLast": 16842751,
"Key_Select": 16842752,
"Key_Yes": 16842753,
@@ -4987,7 +5229,8 @@ Module {
"SystemLocaleShortDate": 4,
"SystemLocaleLongDate": 5,
"DefaultLocaleShortDate": 6,
- "DefaultLocaleLongDate": 7
+ "DefaultLocaleLongDate": 7,
+ "RFC2822Date": 8
}
}
Enum {
@@ -4995,7 +5238,8 @@ Module {
values: {
"LocalTime": 0,
"UTC": 1,
- "OffsetFromUTC": 2
+ "OffsetFromUTC": 2,
+ "TimeZone": 3
}
}
Enum {
@@ -5366,6 +5610,14 @@ Module {
"VeryCoarseTimer": 2
}
}
+ Enum {
+ name: "ScrollPhase"
+ values: {
+ "ScrollBegin": 1,
+ "ScrollUpdate": 2,
+ "ScrollEnd": 3
+ }
+ }
}
Component { name: "QEasingCurve"; prototype: "QQmlEasingValueType" }
}
diff --git a/src/imports/settings/plugins.qmltypes b/src/imports/settings/plugins.qmltypes
index 290c4c5570..87503fbda5 100644
--- a/src/imports/settings/plugins.qmltypes
+++ b/src/imports/settings/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable Qt.labs.settings 1.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable Qt.labs.settings 1.0'
Module {
Component {
diff --git a/src/imports/settings/qqmlsettings.cpp b/src/imports/settings/qqmlsettings.cpp
index f73ab08cf3..011a39f20c 100644
--- a/src/imports/settings/qqmlsettings.cpp
+++ b/src/imports/settings/qqmlsettings.cpp
@@ -297,9 +297,8 @@ void QQmlSettingsPrivate::load()
const QVariant previousValue = property.read(q);
const QVariant currentValue = instance()->value(property.name(), previousValue);
- if (!currentValue.isNull()
- && currentValue.canConvert(previousValue.type())
- && previousValue != currentValue) {
+ if (!currentValue.isNull() && (!previousValue.isValid()
+ || (currentValue.canConvert(previousValue.type()) && previousValue != currentValue))) {
property.write(q, currentValue);
#ifdef SETTINGS_DEBUG
qDebug() << "QQmlSettings: load" << property.name() << "setting:" << currentValue << "default:" << previousValue;
@@ -340,9 +339,9 @@ void QQmlSettingsPrivate::_q_propertyChanged()
for (int i = offset; i < count; ++i) {
const QMetaProperty &property = mo->property(i);
changedProperties.insert(property.name(), property.read(q));
- #ifdef SETTINGS_DEBUG
+#ifdef SETTINGS_DEBUG
qDebug() << "QQmlSettings: cache" << property.name() << ":" << property.read(q);
- #endif
+#endif
}
if (timerId != 0)
q->killTimer(timerId);
diff --git a/src/imports/testlib/plugins.qmltypes b/src/imports/testlib/plugins.qmltypes
index 2865812eb2..94203df4dc 100644
--- a/src/imports/testlib/plugins.qmltypes
+++ b/src/imports/testlib/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable QtTest 1.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtTest 1.0'
Module {
Component {
@@ -147,7 +148,7 @@ Module {
Method { name: "finishTestFunction" }
Method {
name: "stringify"
- Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true }
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
}
Method {
name: "fail"
diff --git a/src/imports/widgets/plugins.qmltypes b/src/imports/widgets/plugins.qmltypes
index 9e73330c12..a67443c5b7 100644
--- a/src/imports/widgets/plugins.qmltypes
+++ b/src/imports/widgets/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable QtQuick.PrivateWidgets 1.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtQuick.PrivateWidgets 1.1'
Module {
Component {
@@ -11,6 +12,11 @@ Module {
prototype: "QQuickAbstractDialog"
Property { name: "showAlphaChannel"; type: "bool" }
Property { name: "color"; type: "QColor" }
+ Property { name: "currentColor"; type: "QColor" }
+ Property { name: "currentHue"; type: "double"; isReadonly: true }
+ Property { name: "currentSaturation"; type: "double"; isReadonly: true }
+ Property { name: "currentLightness"; type: "double"; isReadonly: true }
+ Property { name: "currentAlpha"; type: "double"; isReadonly: true }
Signal { name: "selectionAccepted" }
Method {
name: "setVisible"
@@ -29,6 +35,10 @@ Module {
Parameter { name: "arg"; type: "QColor" }
}
Method {
+ name: "setCurrentColor"
+ Parameter { name: "currentColor"; type: "QColor" }
+ }
+ Method {
name: "setShowAlphaChannel"
Parameter { name: "arg"; type: "bool" }
}
@@ -50,6 +60,22 @@ Module {
Signal { name: "rejected" }
Method { name: "open" }
Method { name: "close" }
+ Method {
+ name: "setX"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setY"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setWidth"
+ Parameter { name: "arg"; type: "int" }
+ }
+ Method {
+ name: "setHeight"
+ Parameter { name: "arg"; type: "int" }
+ }
}
Component {
name: "QQuickAbstractFileDialog"
@@ -99,6 +125,163 @@ Module {
}
}
Component {
+ name: "QQuickAbstractFontDialog"
+ prototype: "QQuickAbstractDialog"
+ Property { name: "scalableFonts"; type: "bool" }
+ Property { name: "nonScalableFonts"; type: "bool" }
+ Property { name: "monospacedFonts"; type: "bool" }
+ Property { name: "proportionalFonts"; type: "bool" }
+ Property { name: "font"; type: "QFont" }
+ Signal { name: "selectionAccepted" }
+ Method {
+ name: "setVisible"
+ Parameter { name: "v"; type: "bool" }
+ }
+ Method {
+ name: "setModality"
+ Parameter { name: "m"; type: "Qt::WindowModality" }
+ }
+ Method {
+ name: "setTitle"
+ Parameter { name: "t"; type: "string" }
+ }
+ Method {
+ name: "setFont"
+ Parameter { name: "arg"; type: "QFont" }
+ }
+ Method {
+ name: "setScalableFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setNonScalableFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setMonospacedFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ Method {
+ name: "setProportionalFonts"
+ Parameter { name: "arg"; type: "bool" }
+ }
+ }
+ Component {
+ name: "QQuickAbstractMessageDialog"
+ prototype: "QQuickAbstractDialog"
+ exports: ["QtQuick.PrivateWidgets/QtMessageDialog 1.1"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "Icon"
+ values: {
+ "NoIcon": 0,
+ "Information": 1,
+ "Warning": 2,
+ "Critical": 3,
+ "Question": 4
+ }
+ }
+ Enum {
+ name: "StandardButton"
+ values: {
+ "NoButton": 0,
+ "Ok": 1024,
+ "Save": 2048,
+ "SaveAll": 4096,
+ "Open": 8192,
+ "Yes": 16384,
+ "YesToAll": 32768,
+ "No": 65536,
+ "NoToAll": 131072,
+ "Abort": 262144,
+ "Retry": 524288,
+ "Ignore": 1048576,
+ "Close": 2097152,
+ "Cancel": 4194304,
+ "Discard": 8388608,
+ "Help": 16777216,
+ "Apply": 33554432,
+ "Reset": 67108864,
+ "RestoreDefaults": 134217728
+ }
+ }
+ Enum {
+ name: "StandardButtons"
+ values: {
+ "NoButton": 0,
+ "Ok": 1024,
+ "Save": 2048,
+ "SaveAll": 4096,
+ "Open": 8192,
+ "Yes": 16384,
+ "YesToAll": 32768,
+ "No": 65536,
+ "NoToAll": 131072,
+ "Abort": 262144,
+ "Retry": 524288,
+ "Ignore": 1048576,
+ "Close": 2097152,
+ "Cancel": 4194304,
+ "Discard": 8388608,
+ "Help": 16777216,
+ "Apply": 33554432,
+ "Reset": 67108864,
+ "RestoreDefaults": 134217728
+ }
+ }
+ Property { name: "text"; type: "string" }
+ Property { name: "informativeText"; type: "string" }
+ Property { name: "detailedText"; type: "string" }
+ Property { name: "icon"; type: "Icon" }
+ Property { name: "standardIconSource"; type: "QUrl"; isReadonly: true }
+ Property { name: "standardButtons"; type: "StandardButtons" }
+ Property { name: "clickedButton"; type: "StandardButton"; isReadonly: true }
+ Signal { name: "buttonClicked" }
+ Signal { name: "discard" }
+ Signal { name: "help" }
+ Signal { name: "yes" }
+ Signal { name: "no" }
+ Signal { name: "apply" }
+ Signal { name: "reset" }
+ Method {
+ name: "setVisible"
+ Parameter { name: "v"; type: "bool" }
+ }
+ Method {
+ name: "setTitle"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setInformativeText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setDetailedText"
+ Parameter { name: "arg"; type: "string" }
+ }
+ Method {
+ name: "setIcon"
+ Parameter { name: "icon"; type: "Icon" }
+ }
+ Method {
+ name: "setStandardButtons"
+ Parameter { name: "buttons"; type: "StandardButtons" }
+ }
+ Method {
+ name: "click"
+ Parameter { name: "button"; type: "QMessageDialogOptions::StandardButton" }
+ Parameter { type: "QMessageDialogOptions::ButtonRole" }
+ }
+ Method {
+ name: "click"
+ Parameter { name: "button"; type: "QQuickAbstractMessageDialog::StandardButton" }
+ }
+ }
+ Component {
name: "QQuickQColorDialog"
prototype: "QQuickAbstractColorDialog"
exports: ["QtQuick.PrivateWidgets/QtColorDialog 1.0"]
@@ -110,4 +293,10 @@ Module {
exports: ["QtQuick.PrivateWidgets/QtFileDialog 1.0"]
exportMetaObjectRevisions: [0]
}
+ Component {
+ name: "QQuickQFontDialog"
+ prototype: "QQuickAbstractFontDialog"
+ exports: ["QtQuick.PrivateWidgets/QtFontDialog 1.1"]
+ exportMetaObjectRevisions: [0]
+ }
}
diff --git a/src/imports/widgets/qmessageboxhelper_p.h b/src/imports/widgets/qmessageboxhelper_p.h
new file mode 100644
index 0000000000..4f1070f97d
--- /dev/null
+++ b/src/imports/widgets/qmessageboxhelper_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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 QMESSAGEBOXHELPER_P_H
+#define QMESSAGEBOXHELPER_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 <QMessageBox>
+#include "../dialogs/qquickabstractmessagedialog_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QMessageBoxHelper : public QPlatformMessageDialogHelper
+{
+ Q_OBJECT
+public:
+ QMessageBoxHelper() {
+ connect(&m_dialog, SIGNAL(accepted()), this, SIGNAL(accept()));
+ connect(&m_dialog, SIGNAL(rejected()), this, SIGNAL(reject()));
+ connect(&m_dialog, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
+ }
+
+ virtual void exec() { m_dialog.exec(); }
+
+ virtual bool show(Qt::WindowFlags f, Qt::WindowModality m, QWindow *parent) {
+ m_dialog.winId();
+ QWindow *window = m_dialog.windowHandle();
+ Q_ASSERT(window);
+ window->setTransientParent(parent);
+ window->setFlags(f);
+ m_dialog.setWindowModality(m);
+ m_dialog.setWindowTitle(QPlatformMessageDialogHelper::options()->windowTitle());
+ m_dialog.setIcon(static_cast<QMessageBox::Icon>(QPlatformMessageDialogHelper::options()->icon()));
+ if (!QPlatformMessageDialogHelper::options()->text().isNull())
+ m_dialog.setText(QPlatformMessageDialogHelper::options()->text());
+ if (!QPlatformMessageDialogHelper::options()->informativeText().isNull())
+ m_dialog.setInformativeText(QPlatformMessageDialogHelper::options()->informativeText());
+ if (!QPlatformMessageDialogHelper::options()->detailedText().isNull())
+ m_dialog.setDetailedText(QPlatformMessageDialogHelper::options()->detailedText());
+ m_dialog.setStandardButtons(static_cast<QMessageBox::StandardButtons>(static_cast<int>(
+ QPlatformMessageDialogHelper::options()->standardButtons())));
+ m_dialog.show();
+ return m_dialog.isVisible();
+ }
+
+ virtual void hide() { m_dialog.hide(); }
+
+ QMessageBox m_dialog;
+
+public Q_SLOTS:
+ void buttonClicked(QAbstractButton* button) {
+ emit clicked(static_cast<QMessageDialogOptions::StandardButton>(m_dialog.standardButton(button)),
+ static_cast<QMessageDialogOptions::ButtonRole>(m_dialog.buttonRole(button)));
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QMESSAGEBOXHELPER_P_H
diff --git a/src/imports/widgets/qquickqmessagebox.cpp b/src/imports/widgets/qquickqmessagebox.cpp
index 2f7c748c7b..1b92efc5ef 100644
--- a/src/imports/widgets/qquickqmessagebox.cpp
+++ b/src/imports/widgets/qquickqmessagebox.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qquickqmessagebox_p.h"
+#include "qmessageboxhelper_p.h"
#include "qquickitem.h"
#include <private/qguiapplication_p.h>
@@ -51,42 +52,6 @@
QT_BEGIN_NAMESPACE
-class QMessageBoxHelper : public QPlatformMessageDialogHelper
-{
-public:
- QMessageBoxHelper() {
- connect(&m_dialog, SIGNAL(accepted()), this, SIGNAL(accept()));
- connect(&m_dialog, SIGNAL(rejected()), this, SIGNAL(reject()));
- }
-
- virtual void exec() { m_dialog.exec(); }
-
- virtual bool show(Qt::WindowFlags f, Qt::WindowModality m, QWindow *parent) {
- m_dialog.winId();
- QWindow *window = m_dialog.windowHandle();
- Q_ASSERT(window);
- window->setTransientParent(parent);
- window->setFlags(f);
- m_dialog.setWindowModality(m);
- m_dialog.setWindowTitle(QPlatformMessageDialogHelper::options()->windowTitle());
- m_dialog.setIcon(static_cast<QMessageBox::Icon>(QPlatformMessageDialogHelper::options()->icon()));
- if (!QPlatformMessageDialogHelper::options()->text().isNull())
- m_dialog.setText(QPlatformMessageDialogHelper::options()->text());
- if (!QPlatformMessageDialogHelper::options()->informativeText().isNull())
- m_dialog.setInformativeText(QPlatformMessageDialogHelper::options()->informativeText());
- if (!QPlatformMessageDialogHelper::options()->detailedText().isNull())
- m_dialog.setDetailedText(QPlatformMessageDialogHelper::options()->detailedText());
- m_dialog.setStandardButtons(static_cast<QMessageBox::StandardButtons>(static_cast<int>(
- QPlatformMessageDialogHelper::options()->standardButtons())));
- m_dialog.show();
- return m_dialog.isVisible();
- }
-
- virtual void hide() { m_dialog.hide(); }
-
- QMessageBox m_dialog;
-};
-
/*!
\qmltype QtMessageDialog
\instantiates QQuickQMessageBox
@@ -156,44 +121,6 @@ QQuickQMessageBox::~QQuickQMessageBox()
delete m_dlgHelper;
}
-void QQuickQMessageBox::finished(int button) {
- click(static_cast<StandardButton>(button));
-}
-
-void QQuickQMessageBox::clicked(QAbstractButton* button) {
- QMessageBox &mb = static_cast<QMessageBoxHelper*>(QQuickAbstractMessageDialog::m_dlgHelper)->m_dialog;
- switch (mb.buttonRole(button)) {
- case QMessageBox::AcceptRole:
- emit accepted();
- break;
- case QMessageBox::RejectRole:
- emit rejected();
- break;
- case QMessageBox::DestructiveRole:
- emit discard();
- break;
- case QMessageBox::HelpRole:
- emit help();
- break;
- case QMessageBox::YesRole:
- emit yes();
- break;
- case QMessageBox::NoRole:
- emit no();
- break;
- case QMessageBox::ApplyRole:
- emit apply();
- break;
- case QMessageBox::ResetRole:
- emit reset();
- break;
- default:
- qWarning("unhandled QMessageBox button role %d", mb.buttonRole(button));
- }
- if (!mb.isVisible())
- setVisible(false);
-}
-
QPlatformDialogHelper *QQuickQMessageBox::helper()
{
QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
@@ -203,10 +130,12 @@ QPlatformDialogHelper *QQuickQMessageBox::helper()
if (!QQuickAbstractMessageDialog::m_dlgHelper) {
QMessageBoxHelper* helper = new QMessageBoxHelper();
QQuickAbstractMessageDialog::m_dlgHelper = helper;
+ // accept() shouldn't be emitted. reject() happens only if the dialog is
+ // dismissed by closing the window rather than by one of its button widgets.
connect(helper, SIGNAL(accept()), this, SLOT(accept()));
connect(helper, SIGNAL(reject()), this, SLOT(reject()));
- connect(&helper->m_dialog, SIGNAL(finished(int)), this, SLOT(finished(int)));
- connect(&helper->m_dialog, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(clicked(QAbstractButton*)));
+ connect(helper, SIGNAL(clicked(QMessageDialogOptions::StandardButton, QMessageDialogOptions::ButtonRole)),
+ this, SLOT(click(QMessageDialogOptions::StandardButton, QMessageDialogOptions::ButtonRole)));
}
return QQuickAbstractMessageDialog::m_dlgHelper;
diff --git a/src/imports/widgets/qquickqmessagebox_p.h b/src/imports/widgets/qquickqmessagebox_p.h
index 9c3c1f2dd6..be91f1d02b 100644
--- a/src/imports/widgets/qquickqmessagebox_p.h
+++ b/src/imports/widgets/qquickqmessagebox_p.h
@@ -53,25 +53,16 @@
// We mean it.
//
-#include <QMessageBox>
#include "../dialogs/qquickabstractmessagedialog_p.h"
QT_BEGIN_NAMESPACE
-class QAbstractButton;
-
class QQuickQMessageBox : public QQuickAbstractMessageDialog
{
- Q_OBJECT
-
public:
QQuickQMessageBox(QObject *parent = 0);
virtual ~QQuickQMessageBox();
-protected slots:
- void clicked(QAbstractButton* button);
- void finished(int button);
-
protected:
virtual QPlatformDialogHelper *helper();
diff --git a/src/imports/widgets/widgets.pro b/src/imports/widgets/widgets.pro
index 8c075945fd..5320838082 100644
--- a/src/imports/widgets/widgets.pro
+++ b/src/imports/widgets/widgets.pro
@@ -17,6 +17,7 @@ SOURCES += \
HEADERS += \
qquickqmessagebox_p.h \
+ qmessageboxhelper_p.h \
../dialogs/qquickabstractmessagedialog_p.h \
qquickqfiledialog_p.h \
../dialogs/qquickabstractfiledialog_p.h \
diff --git a/src/imports/window/plugin.cpp b/src/imports/window/plugin.cpp
index 059044e9ad..31c7899027 100644
--- a/src/imports/window/plugin.cpp
+++ b/src/imports/window/plugin.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
/*!
- \qmlmodule QtQuick.Window 2
+ \qmlmodule QtQuick.Window 2.1
\title Qt Quick Window QML Types
\ingroup qmlmodules
\brief Provides QML types for window management
diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes
index 59e69114e1..1e3577acda 100644
--- a/src/imports/window/plugins.qmltypes
+++ b/src/imports/window/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump QtQuick.Window 2.1 -notrelocatable'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtQuick.Window 2.0'
Module {
Component {
@@ -35,11 +36,13 @@ Module {
Property { name: "desktopAvailableWidth"; revision: 1; type: "int"; isReadonly: true }
Property { name: "desktopAvailableHeight"; revision: 1; type: "int"; isReadonly: true }
Property { name: "logicalPixelDensity"; revision: 1; type: "double"; isReadonly: true }
+ Property { name: "pixelDensity"; revision: 2; type: "double"; isReadonly: true }
Property { name: "primaryOrientation"; type: "Qt::ScreenOrientation"; isReadonly: true }
Property { name: "orientation"; type: "Qt::ScreenOrientation"; isReadonly: true }
Signal { name: "nameChanged"; revision: 1 }
Signal { name: "desktopGeometryChanged"; revision: 1 }
Signal { name: "logicalPixelDensityChanged"; revision: 1 }
+ Signal { name: "pixelDensityChanged"; revision: 2 }
Method {
name: "angleBetween"
type: "int"
@@ -51,8 +54,8 @@ Module {
name: "QQuickWindow"
defaultProperty: "data"
prototype: "QWindow"
- exports: ["QtQuick.Window/Window 2.0", "QtQuick.Window/Window 2.1"]
- exportMetaObjectRevisions: [0, 1]
+ exports: ["QtQuick.Window/Window 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "color"; type: "QColor" }
Property { name: "contentItem"; type: "QQuickItem"; isReadonly: true; isPointer: true }
@@ -83,6 +86,13 @@ Module {
Method { name: "releaseResources" }
}
Component {
+ name: "QQuickWindowQmlImpl"
+ defaultProperty: "data"
+ prototype: "QQuickWindow"
+ exports: ["QtQuick.Window/Window 2.1"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
name: "QWindow"
prototype: "QObject"
Enum {
@@ -103,14 +113,14 @@ Module {
Property { name: "y"; type: "int" }
Property { name: "width"; type: "int" }
Property { name: "height"; type: "int" }
- Property { name: "minimumWidth"; revision: 1; type: "int" }
- Property { name: "minimumHeight"; revision: 1; type: "int" }
- Property { name: "maximumWidth"; revision: 1; type: "int" }
- Property { name: "maximumHeight"; revision: 1; type: "int" }
+ Property { name: "minimumWidth"; type: "int" }
+ Property { name: "minimumHeight"; type: "int" }
+ Property { name: "maximumWidth"; type: "int" }
+ Property { name: "maximumHeight"; type: "int" }
Property { name: "visible"; type: "bool" }
Property { name: "active"; revision: 1; type: "bool"; isReadonly: true }
Property { name: "visibility"; revision: 1; type: "Visibility" }
- Property { name: "contentOrientation"; revision: 1; type: "Qt::ScreenOrientation" }
+ Property { name: "contentOrientation"; type: "Qt::ScreenOrientation" }
Property { name: "opacity"; revision: 1; type: "double" }
Signal {
name: "screenChanged"
@@ -142,22 +152,18 @@ Module {
}
Signal {
name: "minimumWidthChanged"
- revision: 1
Parameter { name: "arg"; type: "int" }
}
Signal {
name: "minimumHeightChanged"
- revision: 1
Parameter { name: "arg"; type: "int" }
}
Signal {
name: "maximumWidthChanged"
- revision: 1
Parameter { name: "arg"; type: "int" }
}
Signal {
name: "maximumHeightChanged"
- revision: 1
Parameter { name: "arg"; type: "int" }
}
Signal {
@@ -172,7 +178,6 @@ Module {
Signal { name: "activeChanged"; revision: 1 }
Signal {
name: "contentOrientationChanged"
- revision: 1
Parameter { name: "orientation"; type: "Qt::ScreenOrientation" }
}
Signal {
@@ -220,26 +225,23 @@ Module {
}
Method {
name: "setMinimumWidth"
- revision: 1
Parameter { name: "w"; type: "int" }
}
Method {
name: "setMinimumHeight"
- revision: 1
Parameter { name: "h"; type: "int" }
}
Method {
name: "setMaximumWidth"
- revision: 1
Parameter { name: "w"; type: "int" }
}
Method {
name: "setMaximumHeight"
- revision: 1
Parameter { name: "h"; type: "int" }
}
Method {
name: "alert"
+ revision: 1
Parameter { name: "msec"; type: "int" }
}
}
diff --git a/src/imports/xmllistmodel/plugins.qmltypes b/src/imports/xmllistmodel/plugins.qmltypes
index d951d07719..0978237027 100644
--- a/src/imports/xmllistmodel/plugins.qmltypes
+++ b/src/imports/xmllistmodel/plugins.qmltypes
@@ -3,7 +3,8 @@ import QtQuick.tooling 1.1
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable QtQuick.XmlListModel 2.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtQuick.XmlListModel 2.0'
Module {
Component {
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
index a1c216dce0..97dc3aba1f 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
@@ -715,7 +715,7 @@ void QQuickXmlListModelPrivate::clear_role(QQmlListProperty<QQuickXmlListModelRo
with a combined value of all key roles that is not already present in
the model.
- \sa {RSS News}
+ \sa {Qt Quick Demo - RSS News}
*/
QQuickXmlListModel::QQuickXmlListModel(QObject *parent)
diff --git a/src/particles/particles.pri b/src/particles/particles.pri
index 9b41a30d6b..af71634ec6 100644
--- a/src/particles/particles.pri
+++ b/src/particles/particles.pri
@@ -63,6 +63,18 @@ SOURCES += \
$$PWD/qquickparticlegroup.cpp \
$$PWD/qquickgroupgoal.cpp
+OTHER_FILES += \
+ $$PWD/shaders/customparticletemplate.vert \
+ $$PWD/shaders/customparticle.vert \
+ $$PWD/shaders/customparticle.frag \
+ $$PWD/shaders/imageparticle.vert \
+ $$PWD/shaders/imageparticle.frag \
+ $$PWD/shaders/customparticletemplate_core.vert \
+ $$PWD/shaders/customparticle_core.vert \
+ $$PWD/shaders/customparticle_core.frag \
+ $$PWD/shaders/imageparticle_core.vert \
+ $$PWD/shaders/imageparticle_core.frag
+
RESOURCES += \
$$PWD/particles.qrc
diff --git a/src/particles/particles.qrc b/src/particles/particles.qrc
index 582520405f..ad44cf406e 100644
--- a/src/particles/particles.qrc
+++ b/src/particles/particles.qrc
@@ -5,4 +5,16 @@
<file>particleresources/glowdot.png</file>
<file>particleresources/star.png</file>
</qresource>
+ <qresource prefix="/particles">
+ <file>shaders/customparticle.frag</file>
+ <file>shaders/customparticle.vert</file>
+ <file>shaders/customparticletemplate.vert</file>
+ <file>shaders/imageparticle.frag</file>
+ <file>shaders/imageparticle.vert</file>
+ <file>shaders/customparticle_core.frag</file>
+ <file>shaders/customparticle_core.vert</file>
+ <file>shaders/customparticletemplate_core.vert</file>
+ <file>shaders/imageparticle_core.frag</file>
+ <file>shaders/imageparticle_core.vert</file>
+ </qresource>
</RCC>
diff --git a/src/particles/qquickcustomparticle.cpp b/src/particles/qquickcustomparticle.cpp
index 4ef35ffcfd..a3b41d0eb2 100644
--- a/src/particles/qquickcustomparticle.cpp
+++ b/src/particles/qquickcustomparticle.cpp
@@ -41,47 +41,11 @@
#include "qquickcustomparticle_p.h"
#include <QtQuick/private/qquickshadereffectmesh_p.h>
+#include <QtQuick/private/qsgshadersourcebuilder_p.h>
#include <cstdlib>
QT_BEGIN_NAMESPACE
-//Includes comments because the code isn't self explanatory
-static const char qt_particles_template_vertex_code[] =
- "attribute highp vec2 qt_ParticlePos;\n"
- "attribute highp vec2 qt_ParticleTex;\n"
- "attribute highp vec4 qt_ParticleData; // x = time, y = lifeSpan, z = size, w = endSize\n"
- "attribute highp vec4 qt_ParticleVec; // x,y = constant velocity, z,w = acceleration\n"
- "attribute highp float qt_ParticleR;\n"
- "uniform highp mat4 qt_Matrix;\n"
- "uniform highp float qt_Timestamp;\n"
- "varying highp vec2 qt_TexCoord0;\n"
- "void defaultMain() {\n"
- " qt_TexCoord0 = qt_ParticleTex;\n"
- " highp float size = qt_ParticleData.z;\n"
- " highp float endSize = qt_ParticleData.w;\n"
- " highp float t = (qt_Timestamp - qt_ParticleData.x) / qt_ParticleData.y;\n"
- " highp float currentSize = mix(size, endSize, t * t);\n"
- " if (t < 0. || t > 1.)\n"
- " currentSize = 0.;\n"
- " highp vec2 pos = qt_ParticlePos\n"
- " - currentSize / 2. + currentSize * qt_ParticleTex // adjust size\n"
- " + qt_ParticleVec.xy * t * qt_ParticleData.y // apply velocity vector..\n"
- " + 0.5 * qt_ParticleVec.zw * pow(t * qt_ParticleData.y, 2.);\n"
- " gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);\n"
- "}";
-static const char qt_particles_default_vertex_code[] =
- "void main() { \n"
- " defaultMain(); \n"
- "}";
-
-static const char qt_particles_default_fragment_code[] =
- "uniform sampler2D source; \n"
- "varying highp vec2 qt_TexCoord0; \n"
- "uniform lowp float qt_Opacity; \n"
- "void main() { \n"
- " gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; \n"
- "}";
-
static QSGGeometry::Attribute PlainParticle_Attributes[] = {
QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // TexCoord
@@ -286,8 +250,11 @@ QSGNode *QQuickCustomParticle::updatePaintNode(QSGNode *oldNode, UpdatePaintNode
if (m_system && m_system->isRunning() && !m_system->isPaused()){
rootNode = prepareNextFrame(rootNode);
- if (rootNode)
+ if (rootNode) {
+ foreach (QSGGeometryNode* node, m_nodes)
+ node->markDirty(QSGNode::DirtyGeometry);
update();
+ }
}
return rootNode;
@@ -306,11 +273,24 @@ QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffec
Q_ASSERT(material);
Key s = m_common.source;
- if (s.sourceCode[Key::FragmentShader].isEmpty())
- s.sourceCode[Key::FragmentShader] = qt_particles_default_fragment_code;
+ QSGShaderSourceBuilder builder;
+ if (s.sourceCode[Key::FragmentShader].isEmpty()) {
+ builder.appendSourceFile(QStringLiteral(":/particles/shaders/customparticle.frag"));
+#if defined(QT_OPENGL_ES_2)
+ builder.removeVersion();
+#endif
+ 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 (s.sourceCode[Key::VertexShader].isEmpty())
- s.sourceCode[Key::VertexShader] = qt_particles_default_vertex_code;
- s.sourceCode[Key::VertexShader] = qt_particles_template_vertex_code + s.sourceCode[Key::VertexShader];
+ builder.appendSourceFile(QStringLiteral(":/particles/shaders/customparticle.vert"));
+ s.sourceCode[Key::VertexShader] = builder.source() + s.sourceCode[Key::VertexShader];
+
s.className = metaObject()->className();
material->setProgramSource(s);
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index fa828d7b63..e5845f4c62 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -51,6 +51,7 @@
#include <private/qquicksprite_p.h>
#include <private/qquickspriteengine_p.h>
#include <QOpenGLFunctions>
+#include <QtQuick/private/qsgshadersourcebuilder_p.h>
#include <QtQuick/private/qsgtexture_p.h>
#include <private/qqmlglobal_p.h>
#include <QtQml/qqmlinfo.h>
@@ -58,190 +59,15 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_OPENGL_ES_2
-#define SHADER_DEFINES "#version 120\n"
+#if defined(Q_OS_BLACKBERRY)
+#define SHADER_PLATFORM_DEFINES "Q_OS_BLACKBERRY\n"
#else
-#define SHADER_DEFINES ""
+#define SHADER_PLATFORM_DEFINES
#endif
//TODO: Make it larger on desktop? Requires fixing up shader code with the same define
#define UNIFORM_ARRAY_SIZE 64
-static const char vertexShaderCode[] =
- "#if defined(DEFORM)\n"
- "attribute highp vec4 vPosTex;\n"
- "#else\n"
- "attribute highp vec2 vPos;\n"
- "#endif\n"
- "attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize\n"
- "attribute highp vec4 vVec; // x,y = constant velocity, z,w = acceleration\n"
- "uniform highp float entry;\n"
- "#if defined(COLOR)\n"
- "attribute highp vec4 vColor;\n"
- "#endif\n"
- "#if defined(DEFORM)\n"
- "attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector\n"
- "attribute highp vec3 vRotation; //x = radians of rotation, y=rotation velocity, z= bool autoRotate\n"
- "#endif\n"
- "#if defined(SPRITE)\n"
- "attribute highp vec3 vAnimData;// w,h(premultiplied of anim), interpolation progress\n"
- "attribute highp vec4 vAnimPos;//x,y, x,y (two frames for interpolation)\n"
- "#endif\n"
- "\n"
- "uniform highp mat4 qt_Matrix;\n"
- "uniform highp float timestamp;\n"
- "#if defined(TABLE)\n"
- "varying lowp vec2 tt;//y is progress if Sprite mode\n"
- "uniform highp float sizetable[64];\n"
- "uniform highp float opacitytable[64];\n"
- "#endif\n"
- "#if defined(SPRITE)\n"
- "varying highp vec4 fTexS;\n"
- "#elif defined(DEFORM)\n"
- "varying highp vec2 fTex;\n"
- "#endif\n"
- "#if defined(COLOR)\n"
- "varying lowp vec4 fColor;\n"
- "#else\n"
- "varying lowp float fFade;\n"
- "#endif\n"
- "\n"
- "\n"
- "void main() {\n"
- "\n"
- " highp float t = (timestamp - vData.x) / vData.y;\n"
- " if (t < 0. || t > 1.) {\n"
- "#if defined(DEFORM)\n"
- " gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
- "#else\n"
- " gl_PointSize = 0.;\n"
- "#endif\n"
- " } else {\n"
- "#if defined(SPRITE)\n"
- " tt.y = vAnimData.z;\n"
- " //Calculate frame location in texture\n"
- " fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy;\n"
- " //Next frame is also passed, for interpolation\n"
- " fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy;\n"
- "\n"
- "#elif defined(DEFORM)\n"
- " fTex = vPosTex.zw;\n"
- "#endif\n"
- " highp float currentSize = mix(vData.z, vData.w, t * t);\n"
-#if defined (Q_OS_BLACKBERRY)
- " highp float fade = 1.;\n"
-#else
- " lowp float fade = 1.;\n"
-#endif
- " highp float fadeIn = min(t * 10., 1.);\n"
- " highp float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);\n"
- "\n"
- "#if defined(TABLE)\n"
- " currentSize = currentSize * sizetable[int(floor(t*64.))];\n"
- " fade = fade * opacitytable[int(floor(t*64.))];\n"
- "#endif\n"
- "\n"
- " if (entry == 1.)\n"
- " fade = fade * fadeIn * fadeOut;\n"
- " else if (entry == 2.)\n"
- " currentSize = currentSize * fadeIn * fadeOut;\n"
- "\n"
- " if (currentSize <= 0.) {\n"
- "#if defined(DEFORM)\n"
- " gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
- "#else\n"
- " gl_PointSize = 0.;\n"
- "#endif\n"
- " } else {\n"
- " if (currentSize < 3.)//Sizes too small look jittery as they move\n"
- " currentSize = 3.;\n"
- "\n"
- " highp vec2 pos;\n"
- "#if defined(DEFORM)\n"
- " highp float rotation = vRotation.x + vRotation.y * t * vData.y;\n"
- " if (vRotation.z == 1.0){\n"
- " highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;\n"
- " if (length(curVel) > 0.)\n"
- " rotation += atan(curVel.y, curVel.x);\n"
- " }\n"
- " highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));\n"
- " highp vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5);\n"
- " highp vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;\n"
- " rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));\n"
- " /* The readable version:\n"
- " highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);\n"
- " highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);\n"
- " highp vec2 xRotatedDeform;\n"
- " xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;\n"
- " xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;\n"
- " highp vec2 yRotatedDeform;\n"
- " yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;\n"
- " yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;\n"
- " */\n"
- " pos = vPosTex.xy\n"
- " + rotatedDeform.xy\n"
- " + rotatedDeform.zw\n"
- " + vVec.xy * t * vData.y // apply velocity\n"
- " + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration\n"
- "#else\n"
- " pos = vPos\n"
- " + vVec.xy * t * vData.y // apply velocity vector..\n"
- " + 0.5 * vVec.zw * pow(t * vData.y, 2.);\n"
- " gl_PointSize = currentSize;\n"
- "#endif\n"
- " gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);\n"
- "\n"
- "#if defined(COLOR)\n"
- " fColor = vColor * fade;\n"
- "#else\n"
- " fFade = fade;\n"
- "#endif\n"
- "#if defined(TABLE)\n"
- " tt.x = t;\n"
- "#endif\n"
- " }\n"
- " }\n"
- "}\n";
-
-static const char fragmentShaderCode[] =
- "uniform sampler2D _qt_texture;\n"
- "uniform lowp float qt_Opacity;\n"
- "\n"
- "#if defined(SPRITE)\n"
- "varying highp vec4 fTexS;\n"
- "#elif defined(DEFORM)\n"
- "varying highp vec2 fTex;\n"
- "#endif\n"
- "#if defined(COLOR)\n"
- "varying lowp vec4 fColor;\n"
- "#else\n"
- "varying lowp float fFade;\n"
- "#endif\n"
- "#if defined(TABLE)\n"
- "varying lowp vec2 tt;\n"
- "uniform sampler2D colortable;\n"
- "#endif\n"
- "\n"
- "void main() {\n"
- "#if defined(SPRITE)\n"
- " gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), texture2D(_qt_texture, fTexS.zw), tt.y)\n"
- " * fColor\n"
- " * texture2D(colortable, tt)\n"
- " * qt_Opacity;\n"
- "#elif defined(TABLE)\n"
- " gl_FragColor = texture2D(_qt_texture, fTex)\n"
- " * fColor\n"
- " * texture2D(colortable, tt)\n"
- " * qt_Opacity;\n"
- "#elif defined(DEFORM)\n"
- " gl_FragColor = (texture2D(_qt_texture, fTex)) * fColor * qt_Opacity;\n"
- "#elif defined(COLOR)\n"
- " gl_FragColor = (texture2D(_qt_texture, gl_PointCoord)) * fColor * qt_Opacity;\n"
- "#else\n"
- " gl_FragColor = texture2D(_qt_texture, gl_PointCoord) * (fFade * qt_Opacity);\n"
- "#endif\n"
- "}\n";
-
const qreal CONV = 0.017453292519943295;
class ImageMaterialData
{
@@ -273,13 +99,29 @@ class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
public:
TabledMaterial()
{
- m_vertex_code = QByteArray(SHADER_DEFINES)
- + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
- + vertexShaderCode;
+ QSGShaderSourceBuilder builder;
+
+ 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
- m_fragment_code = QByteArray(SHADER_DEFINES)
- + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
- + fragmentShaderCode;
+ m_vertex_code = builder.source();
+ builder.clear();
+
+ builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag"));
+ 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
+ m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
Q_ASSERT(!m_fragment_code.isNull());
@@ -335,13 +177,26 @@ class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData
public:
DeformableMaterial()
{
- m_vertex_code = QByteArray(SHADER_DEFINES)
- + QByteArray("#define DEFORM\n#define COLOR\n")
- + vertexShaderCode;
-
- m_fragment_code = QByteArray(SHADER_DEFINES)
- + QByteArray("#define DEFORM\n#define COLOR\n")
- + fragmentShaderCode;
+ QSGShaderSourceBuilder builder;
+
+ 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
+ m_vertex_code = builder.source();
+ builder.clear();
+
+ builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag"));
+ builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
+ builder.addDefinition(QByteArrayLiteral("DEFORM"));
+ builder.addDefinition(QByteArrayLiteral("COLOR"));
+#if defined(QT_OPENGL_ES_2)
+ builder.removeVersion();
+#endif
+ m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
Q_ASSERT(!m_fragment_code.isNull());
@@ -386,13 +241,30 @@ class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData>
public:
SpriteMaterial()
{
- m_vertex_code = QByteArray(SHADER_DEFINES)
- + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
- + vertexShaderCode;
-
- m_fragment_code = QByteArray(SHADER_DEFINES)
- + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
- + fragmentShaderCode;
+ QSGShaderSourceBuilder builder;
+
+ builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert"));
+ builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
+ builder.addDefinition(QByteArrayLiteral("SPRITE"));
+ builder.addDefinition(QByteArrayLiteral("TABLE"));
+ builder.addDefinition(QByteArrayLiteral("DEFORM"));
+ builder.addDefinition(QByteArrayLiteral("COLOR"));
+#if defined(QT_OPENGL_ES_2)
+ builder.removeVersion();
+#endif
+ m_vertex_code = builder.source();
+ builder.clear();
+
+ builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag"));
+ builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
+ builder.addDefinition(QByteArrayLiteral("SPRITE"));
+ builder.addDefinition(QByteArrayLiteral("TABLE"));
+ builder.addDefinition(QByteArrayLiteral("DEFORM"));
+ builder.addDefinition(QByteArrayLiteral("COLOR"));
+#if defined(QT_OPENGL_ES_2)
+ builder.removeVersion();
+#endif
+ m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
Q_ASSERT(!m_fragment_code.isNull());
@@ -450,13 +322,24 @@ class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData>
public:
ColoredMaterial()
{
- m_vertex_code = QByteArray(SHADER_DEFINES)
- + QByteArray("#define COLOR\n")
- + vertexShaderCode;
+ QSGShaderSourceBuilder builder;
- m_fragment_code = QByteArray(SHADER_DEFINES)
- + QByteArray("#define COLOR\n")
- + fragmentShaderCode;
+ 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
+ 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
+ m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
Q_ASSERT(!m_fragment_code.isNull());
@@ -516,11 +399,22 @@ class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData>
public:
SimpleMaterial()
{
- m_vertex_code = QByteArray(SHADER_DEFINES)
- + vertexShaderCode;
+ QSGShaderSourceBuilder builder;
+
+ builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert"));
+ builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
+#if defined(QT_OPENGL_ES_2)
+ builder.removeVersion();
+#endif
+ m_vertex_code = builder.source();
+ builder.clear();
- m_fragment_code = QByteArray(SHADER_DEFINES)
- + fragmentShaderCode;
+ builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag"));
+ builder.addDefinition(QByteArray(SHADER_PLATFORM_DEFINES));
+#if defined(QT_OPENGL_ES_2)
+ builder.removeVersion();
+#endif
+ m_fragment_code = builder.source();
Q_ASSERT(!m_vertex_code.isNull());
Q_ASSERT(!m_fragment_code.isNull());
@@ -645,7 +539,7 @@ void fillUniformArrayFromImage(float* array, const QImage& img, int size)
Note that the sprite image will be scaled to a square based on the size of
the particle being rendered.
- For full details, see the \l{Sprite Animation} overview.
+ For full details, see the \l{Sprite Animations} overview.
*/
/*!
\qmlproperty url QtQuick.Particles::ImageParticle::colorTable
@@ -821,7 +715,6 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
, m_sizeTable(0)
, m_opacityTable(0)
, m_color_variation(0.0)
- , m_rootNode(0)
, m_material(0)
, m_alphaVariation(0.0)
, m_alpha(1.0)
@@ -846,7 +739,7 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
, m_lastLevel(Unknown)
, m_debugMode(false)
, m_entryEffect(Fade)
- , m_buildingNodes(false)
+ , m_startedImageLoading(0)
{
setFlag(ItemHasContents);
}
@@ -863,7 +756,6 @@ QQmlListProperty<QQuickSprite> QQuickImageParticle::sprites()
void QQuickImageParticle::sceneGraphInvalidated()
{
m_nodes.clear();
- m_rootNode = 0;
m_material = 0;
}
@@ -1293,39 +1185,48 @@ bool QQuickImageParticle::loadingSomething()
|| (m_spriteEngine && m_spriteEngine->isLoading());
}
-void QQuickImageParticle::buildParticleNodes()//Starts async parts, like loading images.
+void QQuickImageParticle::mainThreadFetchImageData()
{
- if (m_rootNode || loadingSomething())
- return;
+ if (m_image) {//ImageData created on setSource
+ m_image->pix.clear(this);
+ m_image->pix.load(qmlEngine(this), m_image->source);
+ }
- if (!m_buildingNodes) {
- if (m_image) {//ImageData created on setSource
- m_image->pix.clear(this);
- m_image->pix.load(qmlEngine(this), m_image->source);
- }
+ if (m_spriteEngine)
+ m_spriteEngine->startAssemblingImage();
- if (m_spriteEngine)
- m_spriteEngine->startAssemblingImage();
+ if (m_colorTable)
+ m_colorTable->pix.load(qmlEngine(this), m_colorTable->source);
- if (m_colorTable)
- m_colorTable->pix.load(qmlEngine(this), m_colorTable->source);
+ if (m_sizeTable)
+ m_sizeTable->pix.load(qmlEngine(this), m_sizeTable->source);
- if (m_sizeTable)
- m_sizeTable->pix.load(qmlEngine(this), m_sizeTable->source);
+ if (m_opacityTable)
+ m_opacityTable->pix.load(qmlEngine(this), m_opacityTable->source);
- if (m_opacityTable)
- m_opacityTable->pix.load(qmlEngine(this), m_opacityTable->source);
+ m_startedImageLoading = 2;
+}
- m_buildingNodes = true;
- if (loadingSomething())
- return;
+void QQuickImageParticle::buildParticleNodes(QSGNode** passThrough)
+{
+ // Starts async parts, like loading images, on gui thread
+ // Not on individual properties, because we delay until system is running
+ if (*passThrough || loadingSomething())
+ return;
+
+ if (m_startedImageLoading == 0) {
+ m_startedImageLoading = 1;
+ //stage 1 is in gui thread
+ QQuickImageParticle::staticMetaObject.invokeMethod(this, "mainThreadFetchImageData", Qt::QueuedConnection);
+ } else if (m_startedImageLoading == 2) {
+ finishBuildParticleNodes(passThrough); //rest happens in render thread
}
- finishBuildParticleNodes();
+
+ //No mutex, because it's slow and a compare that fails due to a race condition means just a dropped frame
}
-void QQuickImageParticle::finishBuildParticleNodes()
+void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
{
- m_buildingNodes = false;
#ifdef QT_OPENGL_ES_2
if (m_count * 4 > 0xffff) {
printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
@@ -1385,6 +1286,12 @@ void QQuickImageParticle::finishBuildParticleNodes()
}
#endif
+#ifdef Q_OS_LINUX
+ // Nouveau drivers can potentially freeze a machine entirely when taking the point-sprite path.
+ if (perfLevel < Deformable && strstr((char *) glGetString(GL_VENDOR), "nouveau"))
+ perfLevel = Deformable;
+#endif
+
if (perfLevel >= Colored && !m_color.isValid())
m_color = QColor(Qt::white);//Hidden default, but different from unset
@@ -1548,17 +1455,18 @@ void QQuickImageParticle::finishBuildParticleNodes()
(*(m_nodes.begin()))->appendChildNode(node);
}
- m_rootNode = *(m_nodes.begin());
+ *node = *(m_nodes.begin());
update();
}
-QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
if (m_pleaseReset){
- m_lastLevel = perfLevel;
+ if (node)
+ delete node;
+ node = 0;
- delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
- m_rootNode = 0;
+ m_lastLevel = perfLevel;
m_nodes.clear();
m_idxStarts.clear();
@@ -1568,27 +1476,27 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
m_material = 0;
m_pleaseReset = false;
- m_buildingNodes = false;//Cancel a part-way build
+ m_startedImageLoading = 0;//Cancel a part-way build (may still have a pending load)
}
if (m_system && m_system->isRunning() && !m_system->isPaused()){
- prepareNextFrame();
- if (m_rootNode) {
+ prepareNextFrame(&node);
+ if (node) {
update();
- foreach (QSGGeometryNode* node, m_nodes)
- node->markDirty(QSGNode::DirtyGeometry);
- } else if (m_buildingNodes) {
+ foreach (QSGGeometryNode* n, m_nodes)
+ n->markDirty(QSGNode::DirtyGeometry);
+ } else if (m_startedImageLoading < 2) {
update();//To call prepareNextFrame() again from the renderThread
}
}
- return m_rootNode;
+ return node;
}
-void QQuickImageParticle::prepareNextFrame()
+void QQuickImageParticle::prepareNextFrame(QSGNode **node)
{
- if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
- buildParticleNodes();
+ if (*node == 0){//TODO: Staggered loading (as emitted)
+ buildParticleNodes(node);
if (m_debugMode) {
qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
qDebug() << "QQuickImageParticle Nodes: ";
@@ -1599,7 +1507,7 @@ void QQuickImageParticle::prepareNextFrame()
}
qDebug() << "Total count: " << count;
}
- if (m_rootNode == 0)
+ if (*node == 0)
return;
}
qint64 timeStamp = m_system->systemSync(this);
diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h
index 8f2bb715f8..e9328d79e5 100644
--- a/src/particles/qquickimageparticle_p.h
+++ b/src/particles/qquickimageparticle_p.h
@@ -343,8 +343,8 @@ protected:
virtual void commit(int gIdx, int pIdx);
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
- void prepareNextFrame();
- void buildParticleNodes();
+ void prepareNextFrame(QSGNode**);
+ void buildParticleNodes(QSGNode**);
void sceneGraphInvalidated();
@@ -353,7 +353,8 @@ private Q_SLOTS:
void spriteAdvance(int spriteIndex);
void spritesUpdate(qreal time = 0 );
- void finishBuildParticleNodes();
+ void mainThreadFetchImageData();
+ void finishBuildParticleNodes(QSGNode **n);
private:
struct ImageData {
QUrl source;
@@ -436,7 +437,7 @@ private:
}
EntryEffect m_entryEffect;
Status m_status;
- bool m_buildingNodes;
+ int m_startedImageLoading;
};
QT_END_NAMESPACE
diff --git a/src/particles/qquickparticlesmodule.cpp b/src/particles/qquickparticlesmodule.cpp
index 7d11028e3b..dd0b83f99a 100644
--- a/src/particles/qquickparticlesmodule.cpp
+++ b/src/particles/qquickparticlesmodule.cpp
@@ -69,10 +69,17 @@
#include "qquickparticlegroup_p.h"
#include "qquickgroupgoal_p.h"
+static void initResources()
+{
+ Q_INIT_RESOURCE(particles);
+}
+
QT_BEGIN_NAMESPACE
void QQuickParticlesModule::defineModule()
{
+ initResources();
+
const char* uri = "QtQuick.Particles";
qmlRegisterType<QQuickParticleSystem>(uri, 2, 0, "ParticleSystem");
diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp
index 3cfce0ae90..6f9cd829bb 100644
--- a/src/particles/qquickv4particledata.cpp
+++ b/src/particles/qquickv4particledata.cpp
@@ -298,40 +298,40 @@ public:
QV4::PersistentValue proto;
};
-static QV4::ReturnedValue particleData_discard(QV4::SimpleCallContext *ctx)
+static QV4::ReturnedValue particleData_discard(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject);
if (!r || !r->datum)
- ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
+ return ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
r->datum->lifeSpan = 0; //Don't kill(), because it could still be in the middle of being created
return QV4::Encode::undefined();
}
-static QV4::ReturnedValue particleData_lifeLeft(QV4::SimpleCallContext *ctx)
+static QV4::ReturnedValue particleData_lifeLeft(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject);
if (!r || !r->datum)
- ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
+ return ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
return QV4::Encode(r->datum->lifeLeft());
}
-static QV4::ReturnedValue particleData_curSize(QV4::SimpleCallContext *ctx)
+static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject);
if (!r || !r->datum)
- ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
+ return ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
return QV4::Encode(r->datum->curSize());
}
-#define COLOR_GETTER_AND_SETTER(VAR, NAME) static QV4::ReturnedValue particleData_get_ ## NAME (QV4::SimpleCallContext *ctx) \
+#define COLOR_GETTER_AND_SETTER(VAR, NAME) static QV4::ReturnedValue particleData_get_ ## NAME (QV4::CallContext *ctx) \
{ \
QV4::Scope scope(ctx); \
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
@@ -341,7 +341,7 @@ static QV4::ReturnedValue particleData_curSize(QV4::SimpleCallContext *ctx)
return QV4::Encode((r->datum->color. VAR )/255.0);\
}\
\
-static QV4::ReturnedValue particleData_set_ ## NAME (QV4::SimpleCallContext *ctx)\
+static QV4::ReturnedValue particleData_set_ ## NAME (QV4::CallContext *ctx)\
{\
QV4::Scope scope(ctx); \
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
@@ -354,7 +354,7 @@ static QV4::ReturnedValue particleData_set_ ## NAME (QV4::SimpleCallContext *ctx
}
-#define SEMIBOOL_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::SimpleCallContext *ctx) \
+#define SEMIBOOL_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \
{ \
QV4::Scope scope(ctx); \
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
@@ -364,7 +364,7 @@ static QV4::ReturnedValue particleData_set_ ## NAME (QV4::SimpleCallContext *ctx
return QV4::Encode(r->datum-> VARIABLE);\
}\
\
-static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::SimpleCallContext *ctx)\
+static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\
{\
QV4::Scope scope(ctx); \
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
@@ -375,7 +375,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::SimpleCallContext
return QV4::Encode::undefined(); \
}
-#define FLOAT_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::SimpleCallContext *ctx) \
+#define FLOAT_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \
{ \
QV4::Scope scope(ctx); \
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
@@ -385,7 +385,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::SimpleCallContext
return QV4::Encode(r->datum-> VARIABLE);\
}\
\
-static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::SimpleCallContext *ctx)\
+static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\
{\
QV4::Scope scope(ctx); \
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
@@ -396,7 +396,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::SimpleCallContext
return QV4::Encode::undefined(); \
}
-#define FAKE_FLOAT_GETTER_AND_SETTER(VARIABLE, GETTER, SETTER) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::SimpleCallContext *ctx) \
+#define FAKE_FLOAT_GETTER_AND_SETTER(VARIABLE, GETTER, SETTER) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \
{ \
QV4::Scope scope(ctx); \
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
@@ -406,7 +406,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::SimpleCallContext
return QV4::Encode(r->datum-> GETTER ());\
}\
\
-static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::SimpleCallContext *ctx)\
+static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\
{\
QV4::Scope scope(ctx); \
QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
diff --git a/src/particles/shaders/customparticle.frag b/src/particles/shaders/customparticle.frag
new file mode 100644
index 0000000000..64007029f7
--- /dev/null
+++ b/src/particles/shaders/customparticle.frag
@@ -0,0 +1,11 @@
+#version 120
+
+varying highp vec2 qt_TexCoord0;
+
+uniform sampler2D source;
+uniform lowp float qt_Opacity;
+
+void main()
+{
+ gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity;
+} \ No newline at end of file
diff --git a/src/particles/shaders/customparticle.vert b/src/particles/shaders/customparticle.vert
new file mode 100644
index 0000000000..b99f73ea53
--- /dev/null
+++ b/src/particles/shaders/customparticle.vert
@@ -0,0 +1,4 @@
+void main()
+{
+ defaultMain();
+} \ No newline at end of file
diff --git a/src/particles/shaders/customparticle_core.frag b/src/particles/shaders/customparticle_core.frag
new file mode 100644
index 0000000000..699c834605
--- /dev/null
+++ b/src/particles/shaders/customparticle_core.frag
@@ -0,0 +1,13 @@
+#version 150
+
+in vec2 qt_TexCoord0;
+
+out vec4 fragColor;
+
+uniform sampler2D source;
+uniform float qt_Opacity;
+
+void main()
+{
+ fragColor = texture(source, qt_TexCoord0) * qt_Opacity;
+} \ No newline at end of file
diff --git a/src/particles/shaders/customparticle_core.vert b/src/particles/shaders/customparticle_core.vert
new file mode 100644
index 0000000000..b99f73ea53
--- /dev/null
+++ b/src/particles/shaders/customparticle_core.vert
@@ -0,0 +1,4 @@
+void main()
+{
+ defaultMain();
+} \ No newline at end of file
diff --git a/src/particles/shaders/customparticletemplate.vert b/src/particles/shaders/customparticletemplate.vert
new file mode 100644
index 0000000000..eef8458a85
--- /dev/null
+++ b/src/particles/shaders/customparticletemplate.vert
@@ -0,0 +1,28 @@
+#version 120
+
+attribute highp vec2 qt_ParticlePos;
+attribute highp vec2 qt_ParticleTex;
+attribute highp vec4 qt_ParticleData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 qt_ParticleVec; // x,y = constant velocity, z,w = acceleration
+attribute highp float qt_ParticleR;
+
+uniform highp mat4 qt_Matrix;
+uniform highp float qt_Timestamp;
+
+varying highp vec2 qt_TexCoord0;
+
+void defaultMain()
+{
+ qt_TexCoord0 = qt_ParticleTex;
+ highp float size = qt_ParticleData.z;
+ highp float endSize = qt_ParticleData.w;
+ highp float t = (qt_Timestamp - qt_ParticleData.x) / qt_ParticleData.y;
+ highp float currentSize = mix(size, endSize, t * t);
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+ highp vec2 pos = qt_ParticlePos
+ - currentSize / 2. + currentSize * qt_ParticleTex // adjust size
+ + qt_ParticleVec.xy * t * qt_ParticleData.y // apply velocity vector..
+ + 0.5 * qt_ParticleVec.zw * pow(t * qt_ParticleData.y, 2.);
+ gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);
+}
diff --git a/src/particles/shaders/customparticletemplate_core.vert b/src/particles/shaders/customparticletemplate_core.vert
new file mode 100644
index 0000000000..15d38e797c
--- /dev/null
+++ b/src/particles/shaders/customparticletemplate_core.vert
@@ -0,0 +1,28 @@
+#version 150 core
+
+in vec2 qt_ParticlePos;
+in vec2 qt_ParticleTex;
+in vec4 qt_ParticleData; // x = time, y = lifeSpan, z = size, w = endSize
+in vec4 qt_ParticleVec; // x,y = constant velocity, z,w = acceleration
+in float qt_ParticleR;
+
+out vec2 qt_TexCoord0;
+
+uniform mat4 qt_Matrix;
+uniform float qt_Timestamp;
+
+void defaultMain()
+{
+ qt_TexCoord0 = qt_ParticleTex;
+ float size = qt_ParticleData.z;
+ float endSize = qt_ParticleData.w;
+ float t = (qt_Timestamp - qt_ParticleData.x) / qt_ParticleData.y;
+ float currentSize = mix(size, endSize, t * t);
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+ vec2 pos = qt_ParticlePos
+ - currentSize / 2. + currentSize * qt_ParticleTex // adjust size
+ + qt_ParticleVec.xy * t * qt_ParticleData.y // apply velocity vector..
+ + 0.5 * qt_ParticleVec.zw * pow(t * qt_ParticleData.y, 2.);
+ gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);
+}
diff --git a/src/particles/shaders/imageparticle.frag b/src/particles/shaders/imageparticle.frag
new file mode 100644
index 0000000000..92795a5381
--- /dev/null
+++ b/src/particles/shaders/imageparticle.frag
@@ -0,0 +1,42 @@
+#version 120
+
+uniform sampler2D _qt_texture;
+uniform lowp float qt_Opacity;
+
+#if defined(SPRITE)
+varying highp vec4 fTexS;
+#elif defined(DEFORM)
+varying highp vec2 fTex;
+#endif
+
+#if defined(COLOR)
+varying lowp vec4 fColor;
+#else
+varying lowp float fFade;
+#endif
+
+#if defined(TABLE)
+varying lowp vec2 tt;
+uniform sampler2D colortable;
+#endif
+
+void main()
+{
+#if defined(SPRITE)
+ gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), texture2D(_qt_texture, fTexS.zw), tt.y)
+ * fColor
+ * texture2D(colortable, tt)
+ * qt_Opacity;
+#elif defined(TABLE)
+ gl_FragColor = texture2D(_qt_texture, fTex)
+ * fColor
+ * texture2D(colortable, tt)
+ * qt_Opacity;
+#elif defined(DEFORM)
+ gl_FragColor = (texture2D(_qt_texture, fTex)) * fColor * qt_Opacity;
+#elif defined(COLOR)
+ gl_FragColor = (texture2D(_qt_texture, gl_PointCoord)) * fColor * qt_Opacity;
+#else
+ gl_FragColor = texture2D(_qt_texture, gl_PointCoord) * (fFade * qt_Opacity);
+#endif
+} \ No newline at end of file
diff --git a/src/particles/shaders/imageparticle.vert b/src/particles/shaders/imageparticle.vert
new file mode 100644
index 0000000000..377f831686
--- /dev/null
+++ b/src/particles/shaders/imageparticle.vert
@@ -0,0 +1,145 @@
+#version 120
+
+#if defined(DEFORM)
+attribute highp vec4 vPosTex;
+#else
+attribute highp vec2 vPos;
+#endif
+
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant velocity, z,w = acceleration
+uniform highp float entry;
+
+#if defined(COLOR)
+attribute highp vec4 vColor;
+#endif
+
+#if defined(DEFORM)
+attribute highp vec4 vDeformVec; // x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; // x = radians of rotation, y = rotation velocity, z = bool autoRotate
+#endif
+
+#if defined(SPRITE)
+attribute highp vec3 vAnimData; // w,h(premultiplied of anim), interpolation progress
+attribute highp vec4 vAnimPos; // x,y, x,y (two frames for interpolation)
+#endif
+
+uniform highp mat4 qt_Matrix;
+uniform highp float timestamp;
+
+#if defined(TABLE)
+varying lowp vec2 tt;//y is progress if Sprite mode
+uniform highp float sizetable[64];
+uniform highp float opacitytable[64];
+#endif
+
+#if defined(SPRITE)
+varying highp vec4 fTexS;
+#elif defined(DEFORM)
+varying highp vec2 fTex;
+#endif
+
+#if defined(COLOR)
+varying lowp vec4 fColor;
+#else
+varying lowp float fFade;
+#endif
+
+
+void main()
+{
+ highp float t = (timestamp - vData.x) / vData.y;
+ if (t < 0. || t > 1.) {
+#if defined(DEFORM)
+ gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);
+#else
+ gl_PointSize = 0.;
+#endif
+ } else {
+#if defined(SPRITE)
+ tt.y = vAnimData.z;
+
+ // Calculate frame location in texture
+ fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy;
+
+ // Next frame is also passed, for interpolation
+ fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy;
+
+#elif defined(DEFORM)
+ fTex = vPosTex.zw;
+#endif
+ highp float currentSize = mix(vData.z, vData.w, t * t);
+#if defined (Q_OS_BLACKBERRY)
+ highp float fade = 1.;
+#else
+ lowp float fade = 1.;
+#endif
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);
+
+#if defined(TABLE)
+ currentSize = currentSize * sizetable[int(floor(t*64.))];
+ fade = fade * opacitytable[int(floor(t*64.))];
+#endif
+
+ if (entry == 1.)
+ fade = fade * fadeIn * fadeOut;
+ else if (entry == 2.)
+ currentSize = currentSize * fadeIn * fadeOut;
+
+ if (currentSize <= 0.) {
+#if defined(DEFORM)
+ gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);
+#else
+ gl_PointSize = 0.;
+#endif
+ } else {
+ if (currentSize < 3.) // Sizes too small look jittery as they move
+ currentSize = 3.;
+
+ highp vec2 pos;
+#if defined(DEFORM)
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if (vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ if (length(curVel) > 0.)
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5);
+ highp vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;
+ rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));
+ /* The readable version:
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ */
+ pos = vPosTex.xy
+ + rotatedDeform.xy
+ + rotatedDeform.zw
+ + vVec.xy * t * vData.y // apply velocity
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+#else
+ pos = vPos
+ + vVec.xy * t * vData.y // apply velocity vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+ gl_PointSize = currentSize;
+#endif
+ gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);
+
+#if defined(COLOR)
+ fColor = vColor * fade;
+#else
+ fFade = fade;
+#endif
+#if defined(TABLE)
+ tt.x = t;
+#endif
+ }
+ }
+} \ No newline at end of file
diff --git a/src/particles/shaders/imageparticle_core.frag b/src/particles/shaders/imageparticle_core.frag
new file mode 100644
index 0000000000..3ac8c8d34e
--- /dev/null
+++ b/src/particles/shaders/imageparticle_core.frag
@@ -0,0 +1,44 @@
+#version 150 core
+
+#if defined(SPRITE)
+in vec4 fTexS;
+#elif defined(DEFORM)
+in vec2 fTex;
+#endif
+
+#if defined(COLOR)
+in vec4 fColor;
+#else
+in float fFade;
+#endif
+
+#if defined(TABLE)
+in vec2 tt;
+uniform sampler2D colortable;
+#endif
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform float qt_Opacity;
+
+void main()
+{
+#if defined(SPRITE)
+ fragColor = mix(texture(_qt_texture, fTexS.xy), texture(_qt_texture, fTexS.zw), tt.y)
+ * fColor
+ * texture(colortable, tt)
+ * qt_Opacity;
+#elif defined(TABLE)
+ fragColor = texture(_qt_texture, fTex)
+ * fColor
+ * texture(colortable, tt)
+ * qt_Opacity;
+#elif defined(DEFORM)
+ fragColor = texture(_qt_texture, fTex) * fColor * qt_Opacity;
+#elif defined(COLOR)
+ fragColor = texture(_qt_texture, gl_PointCoord) * fColor * qt_Opacity;
+#else
+ fragColor = texture(_qt_texture, gl_PointCoord) * fFade * qt_Opacity;
+#endif
+} \ No newline at end of file
diff --git a/src/particles/shaders/imageparticle_core.vert b/src/particles/shaders/imageparticle_core.vert
new file mode 100644
index 0000000000..ed9a918eb3
--- /dev/null
+++ b/src/particles/shaders/imageparticle_core.vert
@@ -0,0 +1,145 @@
+#version 150 core
+
+#if defined(DEFORM)
+in vec4 vPosTex;
+#else
+in vec2 vPos;
+#endif
+
+in vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+in vec4 vVec; // x,y = constant velocity, z,w = acceleration
+uniform float entry;
+
+#if defined(COLOR)
+in vec4 vColor;
+#endif
+
+#if defined(DEFORM)
+in vec4 vDeformVec; // x,y x unit vector; z,w = y unit vector
+in vec3 vRotation; // x = radians of rotation, y = rotation velocity, z = bool autoRotate
+#endif
+
+#if defined(SPRITE)
+in vec3 vAnimData; // w,h(premultiplied of anim), interpolation progress
+in vec4 vAnimPos; // x,y, x,y (two frames for interpolation)
+#endif
+
+uniform mat4 qt_Matrix;
+uniform float timestamp;
+
+#if defined(TABLE)
+out vec2 tt;//y is progress if Sprite mode
+uniform float sizetable[64];
+uniform float opacitytable[64];
+#endif
+
+#if defined(SPRITE)
+out vec4 fTexS;
+#elif defined(DEFORM)
+out vec2 fTex;
+#endif
+
+#if defined(COLOR)
+out vec4 fColor;
+#else
+out float fFade;
+#endif
+
+
+void main()
+{
+ float t = (timestamp - vData.x) / vData.y;
+ if (t < 0. || t > 1.) {
+#if defined(DEFORM)
+ gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);
+#else
+ gl_PointSize = 0.;
+#endif
+ } else {
+#if defined(SPRITE)
+ tt.y = vAnimData.z;
+
+ // Calculate frame location in texture
+ fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy;
+
+ // Next frame is also passed, for interpolation
+ fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy;
+
+#elif defined(DEFORM)
+ fTex = vPosTex.zw;
+#endif
+ float currentSize = mix(vData.z, vData.w, t * t);
+#if defined (Q_OS_BLACKBERRY)
+ float fade = 1.;
+#else
+ float fade = 1.;
+#endif
+ float fadeIn = min(t * 10., 1.);
+ float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);
+
+#if defined(TABLE)
+ currentSize = currentSize * sizetable[int(floor(t*64.))];
+ fade = fade * opacitytable[int(floor(t*64.))];
+#endif
+
+ if (entry == 1.)
+ fade = fade * fadeIn * fadeOut;
+ else if (entry == 2.)
+ currentSize = currentSize * fadeIn * fadeOut;
+
+ if (currentSize <= 0.) {
+#if defined(DEFORM)
+ gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);
+#else
+ gl_PointSize = 0.;
+#endif
+ } else {
+ if (currentSize < 3.) // Sizes too small look jittery as they move
+ currentSize = 3.;
+
+ vec2 pos;
+#if defined(DEFORM)
+ float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if (vRotation.z == 1.0) {
+ vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ if (length(curVel) > 0.)
+ rotation += atan(curVel.y, curVel.x);
+ }
+ vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5);
+ vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;
+ rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));
+ /* The readable version:
+ vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ */
+ pos = vPosTex.xy
+ + rotatedDeform.xy
+ + rotatedDeform.zw
+ + vVec.xy * t * vData.y // apply velocity
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+#else
+ pos = vPos
+ + vVec.xy * t * vData.y // apply velocity vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+ gl_PointSize = currentSize;
+#endif
+ gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);
+
+#if defined(COLOR)
+ fColor = vColor * fade;
+#else
+ fFade = fade;
+#endif
+#if defined(TABLE)
+ tt.x = t;
+#endif
+ }
+ }
+} \ No newline at end of file
diff --git a/src/plugins/accessible/quick/qaccessiblequickview.h b/src/plugins/accessible/quick/qaccessiblequickview.h
index 3bfc4ab4fd..41c34c5432 100644
--- a/src/plugins/accessible/quick/qaccessiblequickview.h
+++ b/src/plugins/accessible/quick/qaccessiblequickview.h
@@ -42,7 +42,6 @@
#ifndef QAccessibleQuickView_H
#define QAccessibleQuickView_H
-#include <QtGui/private/qaccessible2_p.h>
#include <QtGui/qaccessibleobject.h>
#include <QtQuick/qquickwindow.h>
diff --git a/src/plugins/accessible/shared/qqmlaccessible.h b/src/plugins/accessible/shared/qqmlaccessible.h
index 5280c78485..b6da016b2d 100644
--- a/src/plugins/accessible/shared/qqmlaccessible.h
+++ b/src/plugins/accessible/shared/qqmlaccessible.h
@@ -43,7 +43,6 @@
#define QQMLACCESSIBLE_H
#include <QtGui/qaccessibleobject.h>
-#include <QtGui/private/qaccessible2_p.h>
#include <QtQml/qqmlproperty.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
index 43dda478f7..85a8527c6b 100644
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -227,7 +227,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
if (!running
&& ((m_direction == Forward && m_currentLoop == m_loopCount -1)
- || m_direction == Backward && m_currentLoop == 0)) {
+ || (m_direction == Backward && m_currentLoop == 0))) {
stop();
}
}
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 2aa5aa5a3c..c32ad2958d 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -47,6 +47,10 @@
#include <private/qqmlcompiler_p.h>
#include <QCoreApplication>
+#ifdef CONST
+#undef CONST
+#endif
+
QT_USE_NAMESPACE
using namespace QtQml;
@@ -538,7 +542,7 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
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, t->nameLength)) {
+ QHashedString::compare(memberType.constData(), t->name, static_cast<int>(t->nameLength))) {
type = t;
break;
}
@@ -596,7 +600,7 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
QV4::CompiledData::Property::Type type;
if ((unsigned)memberType.length() == strlen("alias") &&
- QHashedString::compare(memberType.constData(), "alias", strlen("alias"))) {
+ QHashedString::compare(memberType.constData(), "alias", static_cast<int>(strlen("alias")))) {
type = QV4::CompiledData::Property::Alias;
typeFound = true;
}
@@ -604,7 +608,7 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
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, t->nameLength)) {
+ QHashedString::compare(memberType.constData(), t->name, static_cast<int>(t->nameLength))) {
type = t->type;
typeFound = true;
}
@@ -616,7 +620,7 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
if (typeModifier.isEmpty()) {
type = QV4::CompiledData::Property::Custom;
} else if ((unsigned)typeModifier.length() == strlen("list") &&
- QHashedString::compare(typeModifier.constData(), "list", strlen("list"))) {
+ QHashedString::compare(typeModifier.constData(), "list", static_cast<int>(strlen("list")))) {
type = QV4::CompiledData::Property::CustomList;
} else {
QQmlError error;
@@ -1040,18 +1044,18 @@ bool QQmlCodeGenerator::isStatementNodeScript(AST::Statement *statement)
{
if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(statement)) {
AST::ExpressionNode *expr = stmt->expression;
- if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr))
+ if (AST::cast<AST::StringLiteral *>(expr))
return false;
else if (expr->kind == AST::Node::Kind_TrueLiteral)
return false;
else if (expr->kind == AST::Node::Kind_FalseLiteral)
return false;
- else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr))
+ else if (AST::cast<AST::NumericLiteral *>(expr))
return false;
else {
if (AST::UnaryMinusExpression *unaryMinus = AST::cast<AST::UnaryMinusExpression *>(expr)) {
- if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) {
+ if (AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) {
return false;
}
}
@@ -1064,7 +1068,6 @@ bool QQmlCodeGenerator::isStatementNodeScript(AST::Statement *statement)
QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices)
{
jsUnitGenerator = &output.jsGenerator;
- const QmlObject *rootObject = output.objects.at(output.indexOfRootObject);
int unitSize = 0;
QV4::CompiledData::Unit *jsUnit = jsUnitGenerator->generateUnit(&unitSize);
@@ -1198,33 +1201,61 @@ int QmlUnitGenerator::getStringId(const QString &str) const
return jsUnitGenerator->getStringId(str);
}
-QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output)
+JSCodeGen::JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports)
+ : QQmlJS::Codegen(/*strict mode*/false)
+ , engine(enginePrivate)
+ , sourceCode(sourceCode)
+ , jsEngine(jsEngine)
+ , qmlRoot(qmlRoot)
+ , imports(imports)
+ , _contextObject(0)
+ , _scopeObject(0)
+ , _contextObjectTemp(-1)
+ , _scopeObjectTemp(-1)
+ , _importedScriptsTemp(-1)
+ , _idArrayTemp(-1)
{
- return generateJSCodeForFunctionsAndBindings(fileName, output->code, &output->jsModule, &output->jsParserEngine,
- output->program, output->functions);
+ _module = jsModule;
+ _module->setFileName(fileName);
+ _fileNameIsUrl = true;
}
-QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
- QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, const QList<AST::Node*> &functions)
+void JSCodeGen::beginContextScope(const JSCodeGen::ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject)
+{
+ _idObjects = objectIds;
+ _contextObject = contextObject;
+ _scopeObject = 0;
+}
+
+void JSCodeGen::beginObjectScope(QQmlPropertyCache *scopeObject)
+{
+ _scopeObject = scopeObject;
+}
+
+QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames)
{
QVector<int> runtimeFunctionIndices(functions.size());
- _module = jsModule;
- _module->setFileName(fileName);
- QmlScanner scan(this, sourceCode);
- scan.begin(qmlRoot, QmlBinding);
+ ScanFunctions scan(this, sourceCode, GlobalCode);
+ scan.enterEnvironment(0, QmlBinding);
+ scan.enterQmlScope(qmlRoot, QStringLiteral("context scope"));
foreach (AST::Node *node, functions) {
Q_ASSERT(node != qmlRoot);
AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
- scan.enterEnvironment(node, function ? FunctionCode : QmlBinding);
+ if (function)
+ scan.enterQmlFunction(function);
+ else
+ scan.enterEnvironment(node, QmlBinding);
+
scan(function ? function->body : node);
scan.leaveEnvironment();
}
- scan.end();
+ scan.leaveEnvironment();
+ scan.leaveEnvironment();
_env = 0;
- _function = _module->functions.at(defineFunction(QString("context scope"), qmlRoot, 0, 0));
+ _function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0));
for (int i = 0; i < functions.count(); ++i) {
AST::Node *node = functions.at(i);
@@ -1236,7 +1267,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fil
if (function)
name = function->name.toString();
else
- name = QStringLiteral("%qml-expression-entry");
+ name = functionNames.value(i, QStringLiteral("%qml-expression-entry"));
AST::SourceElements *body;
if (function)
@@ -1267,16 +1298,224 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fil
return runtimeFunctionIndices;
}
+QQmlPropertyData *JSCodeGen::lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup)
+{
+ if (propertyExistsButForceNameLookup)
+ *propertyExistsButForceNameLookup = false;
+ QQmlPropertyData *pd = cache->property(name, /*object*/0, /*context*/0);
+
+ // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time
+ if (pd && pd->isFunction()) {
+ if (propertyExistsButForceNameLookup)
+ *propertyExistsButForceNameLookup = true;
+ pd = 0;
+ }
+
+ if (pd && !cache->isAllowedInRevision(pd))
+ pd = 0;
+
+ // Return a copy allocated from our memory pool. Property data pointers can change
+ // otherwise when the QQmlPropertyCache changes later in the QML type compilation process.
+ if (pd) {
+ QQmlPropertyData *copy = pd;
+ pd = _function->New<QQmlPropertyData>();
+ *pd = *copy;
+ }
+ return pd;
+}
+
+static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+
+enum MetaObjectResolverFlags {
+ AllPropertiesAreFinal = 0x1,
+ LookupsIncludeEnums = 0x2,
+ LookupsExcludeProperties = 0x4
+};
+
+static V4IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member)
+{
+ V4IR::Type result = V4IR::VarType;
+ QQmlPropertyCache *metaObject = static_cast<QQmlPropertyCache*>(resolver->data);
+
+ if (member->name->constData()->isUpper() && (resolver->flags & LookupsIncludeEnums)) {
+ const QMetaObject *mo = metaObject->createMetaObject();
+ QByteArray enumName = member->name->toUtf8();
+ for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum metaEnum = mo->enumerator(ii);
+ bool ok;
+ int value = metaEnum.keyToValue(enumName.constData(), &ok);
+ if (ok) {
+ member->memberIsEnum = true;
+ member->enumValue = value;
+ resolver->clear();
+ return V4IR::SInt32Type;
+ }
+ }
+ }
+
+ if (qmlEngine && !(resolver->flags & LookupsExcludeProperties)) {
+ QQmlPropertyData *property = member->property;
+ if (!property && metaObject) {
+ if (QQmlPropertyData *candidate = metaObject->property(*member->name, /*object*/0, /*context*/0)) {
+ const bool isFinalProperty = (candidate->isFinal() || (resolver->flags & AllPropertiesAreFinal))
+ && !candidate->isFunction();
+ if (isFinalProperty && metaObject->isAllowedInRevision(candidate)) {
+ property = candidate;
+ member->property = candidate; // Cache for next iteration and isel needs it.
+ }
+ }
+ }
+
+ if (property) {
+ // 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 V4IR::VarType;
+
+ switch (property->propType) {
+ case QMetaType::Bool: result = V4IR::BoolType; break;
+ case QMetaType::Int: result = V4IR::SInt32Type; break;
+ case QMetaType::Double: result = V4IR::DoubleType; break;
+ case QMetaType::QString: result = V4IR::StringType; break;
+ default:
+ if (property->isQObject()) {
+ if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType)) {
+ initMetaObjectResolver(resolver, cache);
+ return V4IR::QObjectType;
+ }
+ }
+ break;
+ }
+ }
+ }
+ resolver->clear();
+ return result;
+}
+
+static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject)
+{
+ resolver->resolveMember = &resolveMetaObjectProperty;
+ resolver->data = metaObject;
+ resolver->flags = 0;
+}
-void JSCodeGen::QmlScanner::begin(AST::Node *rootNode, CompilationMode compilationMode)
+void JSCodeGen::beginFunctionBodyHook()
{
- enterEnvironment(0, compilationMode);
- enterFunction(rootNode, "context scope", 0, 0, 0, /*isExpression*/false);
+ _contextObjectTemp = _block->newTemp();
+ _scopeObjectTemp = _block->newTemp();
+ _importedScriptsTemp = _block->newTemp();
+ _idArrayTemp = _block->newTemp();
+
+ V4IR::Temp *temp = _block->TEMP(_contextObjectTemp);
+ initMetaObjectResolver(&temp->memberResolver, _contextObject);
+ move(temp, _block->NAME(V4IR::Name::builtin_qml_context_object, 0, 0));
+
+ temp = _block->TEMP(_scopeObjectTemp);
+ initMetaObjectResolver(&temp->memberResolver, _scopeObject);
+ move(temp, _block->NAME(V4IR::Name::builtin_qml_scope_object, 0, 0));
+
+ move(_block->TEMP(_importedScriptsTemp), _block->NAME(V4IR::Name::builtin_qml_imported_scripts_object, 0, 0));
+ move(_block->TEMP(_idArrayTemp), _block->NAME(V4IR::Name::builtin_qml_id_array, 0, 0));
}
-void JSCodeGen::QmlScanner::end()
+V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
{
- leaveEnvironment();
+ Q_UNUSED(line)
+ Q_UNUSED(col)
+ // Implement QML lookup semantics in the current file context.
+ //
+ // Note: We do not check if properties of the qml scope object or context object
+ // are final. That's because QML tries to get as close as possible to lexical scoping,
+ // which means in terms of properties that only those visible at compile time are chosen.
+ // I.e. access to a "foo" property declared within the same QML component as "property int foo"
+ // will always access that instance and as integer. If a sub-type implements its own property string foo,
+ // then that one is not chosen for accesses from within this file, because it wasn't visible at compile
+ // time. This corresponds to the logic in QQmlPropertyCache::findProperty to find the property associated
+ // with the correct QML context.
+
+ // Look for IDs first.
+ foreach (const IdMapping &mapping, _idObjects)
+ if (name == mapping.name) {
+ _function->idObjectDependencies.insert(mapping.idIndex);
+ V4IR::Expr *s = subscript(_block->TEMP(_idArrayTemp), _block->CONST(V4IR::SInt32Type, mapping.idIndex));
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+ initMetaObjectResolver(&result->memberResolver, mapping.type);
+ _block->MOVE(result, s);
+ result = _block->TEMP(result->index);
+ result->isReadOnly = true; // don't allow use as lvalue
+ return result;
+ }
+
+ {
+ QQmlTypeNameCache::Result r = imports->query(name);
+ if (r.isValid()) {
+ if (r.scriptIndex != -1) {
+ return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(V4IR::SInt32Type, r.scriptIndex));
+ } else if (r.type) {
+ V4IR::Name *typeName = _block->NAME(name, line, col);
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+
+ if (r.type->isSingleton()) {
+ if (r.type->isCompositeSingleton()) {
+ QQmlTypeData *tdata = engine->typeLoader.getType(r.type->singletonInstanceInfo()->url);
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+ initMetaObjectResolver(&result->memberResolver, engine->propertyCacheForType(tdata->compiledData()->metaTypeId));
+ result->memberResolver.flags |= AllPropertiesAreFinal;
+ } else {
+ const QMetaObject *singletonMo = r.type->singletonInstanceInfo()->instanceMetaObject;
+ if (!singletonMo) // We can only accelerate C++ singletons that were registered with their meta-type
+ return 0;
+ initMetaObjectResolver(&result->memberResolver, engine->cache(singletonMo));
+ }
+
+ // Instruct the isel to not load this as activation property but through the
+ // run-time's singleton getter.
+ typeName->qmlSingleton = true;
+ } else {
+ initMetaObjectResolver(&result->memberResolver,engine->cache(r.type->metaObject()));
+ result->memberResolver.flags |= LookupsExcludeProperties;
+ }
+ typeName->freeOfSideEffects = true;
+ result->memberResolver.flags |= LookupsIncludeEnums;
+ _block->MOVE(result, typeName);
+ return _block->TEMP(result->index);
+ } else {
+ return 0; // TODO: We can't do fast lookup for these yet.
+ }
+ }
+ }
+
+ if (_scopeObject) {
+ bool propertyExistsButForceNameLookup = false;
+ QQmlPropertyData *pd = lookupQmlCompliantProperty(_scopeObject, name, &propertyExistsButForceNameLookup);
+ if (propertyExistsButForceNameLookup)
+ return 0;
+ if (pd) {
+ if (!pd->isConstant())
+ _function->scopeObjectDependencies.insert(pd);
+ V4IR::Temp *base = _block->TEMP(_scopeObjectTemp);
+ initMetaObjectResolver(&base->memberResolver, _scopeObject);
+ return _block->MEMBER(base, _function->newString(name), pd);
+ }
+ }
+
+ if (_contextObject) {
+ bool propertyExistsButForceNameLookup = false;
+ QQmlPropertyData *pd = lookupQmlCompliantProperty(_contextObject, name, &propertyExistsButForceNameLookup);
+ if (propertyExistsButForceNameLookup)
+ return 0;
+ if (pd) {
+ if (!pd->isConstant())
+ _function->contextObjectDependencies.insert(pd);
+ V4IR::Temp *base = _block->TEMP(_contextObjectTemp);
+ initMetaObjectResolver(&base->memberResolver, _contextObject);
+ return _block->MEMBER(base, _function->newString(name), pd);
+ }
+ }
+
+ // fall back to name lookup at run-time.
+ return 0;
}
SignalHandlerConverter::SignalHandlerConverter(QQmlEnginePrivate *enginePrivate, ParsedQML *parsedQML,
@@ -1382,7 +1621,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
QHash<QString, QStringList>::ConstIterator entry = customSignals.find(propertyName);
if (entry == customSignals.constEnd() && propertyName.endsWith(QStringLiteral("Changed"))) {
- QString alternateName = propertyName.mid(0, propertyName.length() - strlen("Changed"));
+ QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed")));
entry = customSignals.find(alternateName);
}
@@ -1474,7 +1713,7 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis
}
if (name.endsWith(QStringLiteral("Changed"))) {
- QString propName = name.mid(0, name.length() - strlen("Changed"));
+ QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
d = property(propName, notInRevision);
if (d)
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index 8de08a81d1..f16f910078 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -55,6 +55,8 @@
QT_BEGIN_NAMESPACE
+class QQmlTypeNameCache;
+
namespace QtQml {
using namespace QQmlJS;
@@ -166,8 +168,9 @@ struct Pragma
struct ParsedQML
{
- ParsedQML()
- : jsGenerator(&jsModule, sizeof(QV4::CompiledData::QmlUnit))
+ ParsedQML(bool debugMode)
+ : jsModule(debugMode)
+ , jsGenerator(&jsModule, sizeof(QV4::CompiledData::QmlUnit))
{}
QString code;
QQmlJS::Engine jsParserEngine;
@@ -344,28 +347,43 @@ private:
struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
{
- JSCodeGen()
- : QQmlJS::Codegen(/*strict mode*/false)
- {}
+ JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
+ QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports);
+
+ struct IdMapping
+ {
+ QString name;
+ int idIndex;
+ QQmlPropertyCache *type;
+ };
+ typedef QVector<IdMapping> ObjectIdMapping;
+
+ void beginContextScope(const ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject);
+ void beginObjectScope(QQmlPropertyCache *scopeObject);
// Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions
- QVector<int> generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output);
- QVector<int> generateJSCodeForFunctionsAndBindings(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
- QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, const QList<AST::Node*> &functions);
+ QVector<int> generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames);
-private:
- struct QmlScanner : public ScanFunctions
- {
- QmlScanner(JSCodeGen *cg, const QString &sourceCode)
- : ScanFunctions(cg, sourceCode, /*default program mode*/GlobalCode)
- , codeGen(cg)
- {}
+protected:
+ virtual void beginFunctionBodyHook();
+ virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
- void begin(AST::Node *rootNode, CompilationMode compilationMode);
- void end();
+private:
+ QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup = 0);
- JSCodeGen *codeGen;
- };
+ QQmlEnginePrivate *engine;
+ QString sourceCode;
+ QQmlJS::Engine *jsEngine; // needed for memory pool
+ AST::UiProgram *qmlRoot;
+ QQmlTypeNameCache *imports;
+
+ ObjectIdMapping _idObjects;
+ QQmlPropertyCache *_contextObject;
+ QQmlPropertyCache *_scopeObject;
+ int _contextObjectTemp;
+ int _scopeObjectTemp;
+ int _importedScriptsTemp;
+ int _idArrayTemp;
};
} // namespace QtQml
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index a68920235e..a8338f8656 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -55,7 +55,6 @@
#include <qv4context_p.h>
#include <cmath>
#include <iostream>
-#include <cassert>
#ifdef CONST
#undef CONST
@@ -132,7 +131,7 @@ void Codegen::ScanFunctions::checkName(const QStringRef &name, const SourceLocat
|| name == QLatin1String("public")
|| name == QLatin1String("static")
|| name == QLatin1String("yield")) {
- _cg->throwSyntaxError(loc, QCoreApplication::translate("qv4codegen", "Unexpected strict mode reserved word"));
+ _cg->throwSyntaxError(loc, QStringLiteral("Unexpected strict mode reserved word"));
}
}
}
@@ -203,7 +202,7 @@ bool Codegen::ScanFunctions::visit(ArrayLiteral *ast)
bool Codegen::ScanFunctions::visit(VariableDeclaration *ast)
{
if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
- _cg->throwSyntaxError(ast->identifierToken, QCoreApplication::translate("qv4codegen", "Variable name may not be eval or arguments in strict mode"));
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
checkName(ast->name, ast->identifierToken);
if (ast->name == QLatin1String("arguments"))
_env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
@@ -223,7 +222,7 @@ bool Codegen::ScanFunctions::visit(ExpressionStatement *ast)
{
if (FunctionExpression* expr = AST::cast<AST::FunctionExpression*>(ast->expression)) {
if (!_allowFuncDecls)
- _cg->throwSyntaxError(expr->functionToken, QCoreApplication::translate("qv4codegen", "conditional function or closure declaration"));
+ _cg->throwSyntaxError(expr->functionToken, QStringLiteral("conditional function or closure declaration"));
enterFunction(expr, /*enterName*/ true);
Node::accept(expr->formals, this);
@@ -233,7 +232,7 @@ bool Codegen::ScanFunctions::visit(ExpressionStatement *ast)
} else {
SourceLocation firstToken = ast->firstSourceLocation();
if (_sourceCode.midRef(firstToken.offset, firstToken.length) == QStringLiteral("function")) {
- _cg->throwSyntaxError(firstToken, QCoreApplication::translate("qv4codegen", "unexpected token"));
+ _cg->throwSyntaxError(firstToken, QStringLiteral("unexpected token"));
}
}
return true;
@@ -248,7 +247,7 @@ bool Codegen::ScanFunctions::visit(FunctionExpression *ast)
void Codegen::ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName, bool isExpression)
{
if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
- _cg->throwSyntaxError(ast->identifierToken, QCoreApplication::translate("qv4codegen", "Function name may not be eval or arguments in strict mode"));
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode"));
enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName ? ast : 0, isExpression);
}
@@ -298,7 +297,7 @@ void Codegen::ScanFunctions::endVisit(FunctionDeclaration *)
bool Codegen::ScanFunctions::visit(WithStatement *ast)
{
if (_env->isStrict) {
- _cg->throwSyntaxError(ast->withToken, QCoreApplication::translate("qv4codegen", "'with' statement is not allowed in strict mode"));
+ _cg->throwSyntaxError(ast->withToken, QStringLiteral("'with' statement is not allowed in strict mode"));
return false;
}
@@ -356,6 +355,12 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) {
return false;
}
+bool Codegen::ScanFunctions::visit(ThisExpression *)
+{
+ _env->usesThis = true;
+ return false;
+}
+
bool Codegen::ScanFunctions::visit(Block *ast) {
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _env->isStrict ? false : _allowFuncDecls);
Node::accept(ast->statements, this);
@@ -388,10 +393,14 @@ void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, Forma
QStringList args;
for (FormalParameterList *it = formals; it; it = it->next) {
QString arg = it->name.toString();
- if (args.contains(arg))
- _cg->throwSyntaxError(it->identifierToken, QCoreApplication::translate("qv4codegen", "Duplicate parameter name '%1' is not allowed in strict mode").arg(arg));
- if (arg == QLatin1String("eval") || arg == QLatin1String("arguments"))
- _cg->throwSyntaxError(it->identifierToken, QCoreApplication::translate("qv4codegen", "'%1' cannot be used as parameter name in strict mode").arg(arg));
+ if (args.contains(arg)) {
+ _cg->throwSyntaxError(it->identifierToken, QStringLiteral("Duplicate parameter name '%1' is not allowed in strict mode").arg(arg));
+ return;
+ }
+ if (arg == QLatin1String("eval") || arg == QLatin1String("arguments")) {
+ _cg->throwSyntaxError(it->identifierToken, QStringLiteral("'%1' cannot be used as parameter name in strict mode").arg(arg));
+ return;
+ }
args += arg;
}
}
@@ -403,13 +412,14 @@ Codegen::Codegen(bool strict)
, _function(0)
, _block(0)
, _exitBlock(0)
- , _throwBlock(0)
, _returnAddress(0)
, _env(0)
, _loop(0)
, _labelledStatement(0)
, _scopeAndFinally(0)
, _strictMode(strict)
+ , _fileNameIsUrl(false)
+ , hasError(false)
{
}
@@ -420,7 +430,7 @@ void Codegen::generateFromProgram(const QString &fileName,
CompilationMode mode,
const QStringList &inheritedLocals)
{
- assert(node);
+ Q_ASSERT(node);
_module = module;
_env = 0;
@@ -460,12 +470,12 @@ void Codegen::generateFromFunctionExpression(const QString &fileName,
void Codegen::enterEnvironment(Node *node)
{
_env = _envMap.value(node);
- assert(_env);
+ Q_ASSERT(_env);
}
void Codegen::leaveEnvironment()
{
- assert(_env);
+ Q_ASSERT(_env);
_env = _env->parent;
}
@@ -488,6 +498,9 @@ void Codegen::leaveLoop()
V4IR::Expr *Codegen::member(V4IR::Expr *base, const QString *name)
{
+ if (hasError)
+ return 0;
+
if (base->asTemp() /*|| base->asName()*/)
return _block->MEMBER(base->asTemp(), name);
else {
@@ -499,6 +512,9 @@ V4IR::Expr *Codegen::member(V4IR::Expr *base, const QString *name)
V4IR::Expr *Codegen::subscript(V4IR::Expr *base, V4IR::Expr *index)
{
+ if (hasError)
+ return 0;
+
if (! base->asTemp()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), base);
@@ -511,7 +527,7 @@ V4IR::Expr *Codegen::subscript(V4IR::Expr *base, V4IR::Expr *index)
index = _block->TEMP(t);
}
- assert(base->asTemp() && index->asTemp());
+ Q_ASSERT(base->asTemp() && index->asTemp());
return _block->SUBSCRIPT(base->asTemp(), index->asTemp());
}
@@ -528,6 +544,9 @@ V4IR::Expr *Codegen::argument(V4IR::Expr *expr)
// keeps references alive, converts other expressions to temps
V4IR::Expr *Codegen::reference(V4IR::Expr *expr)
{
+ if (hasError)
+ return 0;
+
if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember() && !expr->asSubscript()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), expr);
@@ -538,6 +557,9 @@ V4IR::Expr *Codegen::reference(V4IR::Expr *expr)
V4IR::Expr *Codegen::unop(V4IR::AluOp op, V4IR::Expr *expr)
{
+ if (hasError)
+ return 0;
+
Q_ASSERT(op != V4IR::OpIncrement);
Q_ASSERT(op != V4IR::OpDecrement);
@@ -566,12 +588,15 @@ V4IR::Expr *Codegen::unop(V4IR::AluOp op, V4IR::Expr *expr)
move(_block->TEMP(t), expr);
expr = _block->TEMP(t);
}
- assert(expr->asTemp());
+ Q_ASSERT(expr->asTemp());
return _block->UNOP(op, expr->asTemp());
}
V4IR::Expr *Codegen::binop(V4IR::AluOp op, V4IR::Expr *left, V4IR::Expr *right)
{
+ if (hasError)
+ return 0;
+
if (V4IR::Const *c1 = left->asConst()) {
if (V4IR::Const *c2 = right->asConst()) {
if (c1->type == V4IR::NumberType && c2->type == V4IR::NumberType) {
@@ -634,21 +659,26 @@ V4IR::Expr *Codegen::binop(V4IR::AluOp op, V4IR::Expr *left, V4IR::Expr *right)
right = _block->TEMP(t);
}
- assert(left->asTemp());
- assert(right->asTemp());
+ Q_ASSERT(left->asTemp());
+ Q_ASSERT(right->asTemp());
return _block->BINOP(op, left, right);
}
V4IR::Expr *Codegen::call(V4IR::Expr *base, V4IR::ExprList *args)
{
+ if (hasError)
+ return 0;
base = reference(base);
return _block->CALL(base, args);
}
void Codegen::move(V4IR::Expr *target, V4IR::Expr *source, V4IR::AluOp op)
{
- assert(target->isLValue());
+ if (hasError)
+ return;
+
+ Q_ASSERT(target->isLValue());
if (op != V4IR::OpInvalid) {
move(target, binop(op, target, source));
@@ -671,6 +701,9 @@ void Codegen::move(V4IR::Expr *target, V4IR::Expr *source, V4IR::AluOp op)
void Codegen::cjump(V4IR::Expr *cond, V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse)
{
+ if (hasError)
+ return;
+
if (! (cond->asTemp() || cond->asBinop())) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), cond);
@@ -681,6 +714,9 @@ void Codegen::cjump(V4IR::Expr *cond, V4IR::BasicBlock *iftrue, V4IR::BasicBlock
void Codegen::accept(Node *node)
{
+ if (hasError)
+ return;
+
if (node)
node->accept(this);
}
@@ -699,6 +735,8 @@ void Codegen::statement(ExpressionNode *ast)
Result r(nx);
qSwap(_expr, r);
accept(ast);
+ if (hasError)
+ return;
qSwap(_expr, r);
if (r.format == ex) {
if (r->asCall()) {
@@ -787,6 +825,8 @@ void Codegen::sourceElements(SourceElements *ast)
{
for (SourceElements *it = ast; it; it = it->next) {
sourceElement(it->element);
+ if (hasError)
+ return;
}
}
@@ -796,7 +836,10 @@ void Codegen::variableDeclaration(VariableDeclaration *ast)
if (!ast->expression)
return;
Result expr = expression(ast->expression);
- assert(expr.code);
+ if (hasError)
+ return;
+
+ Q_ASSERT(expr.code);
initializer = *expr;
int initialized = _block->newTemp();
@@ -814,180 +857,183 @@ void Codegen::variableDeclarationList(VariableDeclarationList *ast)
bool Codegen::visit(ArgumentList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(CaseBlock *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(CaseClause *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(CaseClauses *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(Catch *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(DefaultClause *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(ElementList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(Elision *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(Finally *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(FormalParameterList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(FunctionBody *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(Program *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(PropertyAssignmentList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(PropertyNameAndValue *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(PropertyGetterSetter *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(SourceElements *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(StatementList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiArrayMemberList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiImport *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiHeaderItemList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiPragma *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiObjectInitializer *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiObjectMemberList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiParameterList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiProgram *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiQualifiedId *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(UiQualifiedPragmaId *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(VariableDeclaration *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(VariableDeclarationList *)
{
- assert(!"unreachable");
+ Q_ASSERT(!"unreachable");
return false;
}
bool Codegen::visit(Expression *ast)
{
+ if (hasError)
+ return false;
+
statement(ast->left);
accept(ast->right);
return false;
@@ -995,6 +1041,9 @@ bool Codegen::visit(Expression *ast)
bool Codegen::visit(ArrayLiteral *ast)
{
+ if (hasError)
+ return false;
+
V4IR::ExprList *args = 0;
V4IR::ExprList *current = 0;
for (ElementList *it = ast->elements; it; it = it->next) {
@@ -1046,6 +1095,9 @@ bool Codegen::visit(ArrayLiteral *ast)
bool Codegen::visit(ArrayMemberExpression *ast)
{
+ if (hasError)
+ return false;
+
Result base = expression(ast->base);
Result index = expression(ast->expression);
_expr.code = subscript(*base, *index);
@@ -1072,15 +1124,18 @@ static V4IR::AluOp baseOp(int op)
bool Codegen::visit(BinaryExpression *ast)
{
+ if (hasError)
+ return false;
+
if (ast->op == QSOperator::And) {
if (_expr.accept(cx)) {
- V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
condition(ast->left, iftrue, _expr.iffalse);
_block = iftrue;
condition(ast->right, _expr.iftrue, _expr.iffalse);
} else {
- V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
const unsigned r = _block->newTemp();
@@ -1096,13 +1151,13 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
} else if (ast->op == QSOperator::Or) {
if (_expr.accept(cx)) {
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
condition(ast->left, _expr.iftrue, iffalse);
_block = iffalse;
condition(ast->right, _expr.iftrue, _expr.iffalse);
} else {
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
const unsigned r = _block->newTemp();
move(_block->TEMP(r), *expression(ast->left));
@@ -1125,10 +1180,13 @@ bool Codegen::visit(BinaryExpression *ast)
break;
case QSOperator::Assign: {
- throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation());
+ if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
+ return false;
V4IR::Expr* right = *expression(ast->right);
- if (! (left->asTemp() || left->asName() || left->asSubscript() || left->asMember()))
- throwReferenceError(ast->operatorToken, QCoreApplication::translate("qv4codegen", "left-hand side of assignment operator is not an lvalue"));
+ if (!left->isLValue()) {
+ throwReferenceError(ast->operatorToken, QStringLiteral("left-hand side of assignment operator is not an lvalue"));
+ return false;
+ }
if (_expr.accept(nx)) {
move(left, right);
@@ -1152,10 +1210,13 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::InplaceRightShift:
case QSOperator::InplaceURightShift:
case QSOperator::InplaceXor: {
- throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation());
+ if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
+ return false;
V4IR::Expr* right = *expression(ast->right);
- if (!left->isLValue())
- throwSyntaxError(ast->operatorToken, QCoreApplication::translate("qv4codegen", "left-hand side of inplace operator is not an lvalue"));
+ if (!left->isLValue()) {
+ throwSyntaxError(ast->operatorToken, QStringLiteral("left-hand side of inplace operator is not an lvalue"));
+ return false;
+ }
if (_expr.accept(nx)) {
move(left, right, baseOp(ast->op));
@@ -1238,6 +1299,9 @@ bool Codegen::visit(BinaryExpression *ast)
bool Codegen::visit(CallExpression *ast)
{
+ if (hasError)
+ return false;
+
Result base = expression(ast->base);
V4IR::ExprList *args = 0, **args_it = &args;
for (ArgumentList *it = ast->arguments; it; it = it->next) {
@@ -1253,9 +1317,12 @@ bool Codegen::visit(CallExpression *ast)
bool Codegen::visit(ConditionalExpression *ast)
{
- V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
+
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
const unsigned t = _block->newTemp();
@@ -1278,18 +1345,25 @@ bool Codegen::visit(ConditionalExpression *ast)
bool Codegen::visit(DeleteExpression *ast)
{
+ if (hasError)
+ return false;
+
V4IR::Expr* expr = *expression(ast->expression);
// Temporaries cannot be deleted
V4IR::Temp *t = expr->asTemp();
- if (t && t->index < _env->members.size()) {
+ if (t && t->index < static_cast<unsigned>(_env->members.size())) {
// Trying to delete a function argument might throw.
- if (_function->isStrict)
- throwSyntaxError(ast->deleteToken, "Delete of an unqualified identifier in strict mode.");
+ if (_function->isStrict) {
+ throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode."));
+ return false;
+ }
_expr.code = _block->CONST(V4IR::BoolType, 0);
return false;
}
- if (_function->isStrict && expr->asName())
- throwSyntaxError(ast->deleteToken, "Delete of an unqualified identifier in strict mode.");
+ if (_function->isStrict && expr->asName()) {
+ throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode."));
+ return false;
+ }
// [[11.4.1]] Return true if it's not a reference
if (expr->asConst() || expr->asString()) {
@@ -1304,7 +1378,7 @@ bool Codegen::visit(DeleteExpression *ast)
_expr.code = _block->CONST(V4IR::BoolType, 1);
return false;
}
- if (expr->asTemp() && expr->asTemp()->index >= _env->members.size()) {
+ if (expr->asTemp() && expr->asTemp()->index >= static_cast<unsigned>(_env->members.size())) {
_expr.code = _block->CONST(V4IR::BoolType, 1);
return false;
}
@@ -1317,6 +1391,9 @@ bool Codegen::visit(DeleteExpression *ast)
bool Codegen::visit(FalseLiteral *)
{
+ if (hasError)
+ return false;
+
if (_expr.accept(cx)) {
_block->JUMP(_expr.iffalse);
} else {
@@ -1327,6 +1404,9 @@ bool Codegen::visit(FalseLiteral *)
bool Codegen::visit(FieldMemberExpression *ast)
{
+ if (hasError)
+ return false;
+
Result base = expression(ast->base);
_expr.code = member(*base, _function->newString(ast->name.toString()));
return false;
@@ -1334,6 +1414,9 @@ bool Codegen::visit(FieldMemberExpression *ast)
bool Codegen::visit(FunctionExpression *ast)
{
+ if (hasError)
+ return false;
+
int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
_expr.code = _block->CLOSURE(function);
return false;
@@ -1341,19 +1424,22 @@ bool Codegen::visit(FunctionExpression *ast)
V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
{
+ if (hasError)
+ return 0;
+
uint scope = 0;
Environment *e = _env;
V4IR::Function *f = _function;
- while (f && e->parent && e->compilationMode != QmlBinding) {
+ while (f && e->parent) {
if (f->insideWithOrCatch || (f->isNamedExpression && f->name == name))
return _block->NAME(name, line, col);
int index = e->findMember(name);
- assert (index < e->members.size());
+ Q_ASSERT (index < e->members.size());
if (index != -1) {
V4IR::Temp *t = _block->LOCAL(index, scope);
- if (name == "arguments" || name == "eval")
+ if (name == QStringLiteral("arguments") || name == QStringLiteral("eval"))
t->isArgumentsOrEval = true;
return t;
}
@@ -1369,6 +1455,10 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
f = f->outer;
}
+ // This hook allows implementing QML lookup semantics
+ if (V4IR::Expr *fallback = fallbackNameLookup(name, line, col))
+ return fallback;
+
if (!e->parent && (!f || !f->insideWithOrCatch) && _env->compilationMode != EvalCode && e->compilationMode != QmlBinding)
return _block->GLOBALNAME(name, line, col);
@@ -1377,20 +1467,37 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
}
+V4IR::Expr *Codegen::fallbackNameLookup(const QString &name, int line, int col)
+{
+ Q_UNUSED(name)
+ Q_UNUSED(line)
+ Q_UNUSED(col)
+ return 0;
+}
+
bool Codegen::visit(IdentifierExpression *ast)
{
+ if (hasError)
+ return false;
+
_expr.code = identifier(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn);
return false;
}
bool Codegen::visit(NestedExpression *ast)
{
+ if (hasError)
+ return false;
+
accept(ast->expression);
return false;
}
bool Codegen::visit(NewExpression *ast)
{
+ if (hasError)
+ return false;
+
Result base = expression(ast->expression);
V4IR::Expr *expr = *base;
if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember()) {
@@ -1404,6 +1511,9 @@ bool Codegen::visit(NewExpression *ast)
bool Codegen::visit(NewMemberExpression *ast)
{
+ if (hasError)
+ return false;
+
Result base = expression(ast->base);
V4IR::Expr *expr = *base;
if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember()) {
@@ -1428,6 +1538,9 @@ bool Codegen::visit(NewMemberExpression *ast)
bool Codegen::visit(NotExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->expression);
const unsigned r = _block->newTemp();
move(_block->TEMP(r), unop(V4IR::OpNot, *expr));
@@ -1437,6 +1550,9 @@ bool Codegen::visit(NotExpression *ast)
bool Codegen::visit(NullExpression *)
{
+ if (hasError)
+ return false;
+
if (_expr.accept(cx)) _block->JUMP(_expr.iffalse);
else _expr.code = _block->CONST(V4IR::NullType, 0);
@@ -1445,6 +1561,9 @@ bool Codegen::visit(NullExpression *)
bool Codegen::visit(NumericLiteral *ast)
{
+ if (hasError)
+ return false;
+
if (_expr.accept(cx)) {
if (ast->value) _block->JUMP(_expr.iftrue);
else _block->JUMP(_expr.iffalse);
@@ -1471,6 +1590,9 @@ struct ObjectPropertyValue {
bool Codegen::visit(ObjectLiteral *ast)
{
+ if (hasError)
+ return false;
+
QMap<QString, ObjectPropertyValue> valueMap;
for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
@@ -1478,9 +1600,11 @@ bool Codegen::visit(ObjectLiteral *ast)
QString name = propertyName(nv->name);
Result value = expression(nv->value);
ObjectPropertyValue &v = valueMap[name];
- if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value))
+ if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value)) {
throwSyntaxError(nv->lastSourceLocation(),
- QCoreApplication::translate("qv4codegen", "Illegal duplicate key '%1' in object literal").arg(name));
+ QStringLiteral("Illegal duplicate key '%1' in object literal").arg(name));
+ return false;
+ }
valueMap[name].value = *value;
} else if (PropertyGetterSetter *gs = AST::cast<AST::PropertyGetterSetter *>(it->assignment)) {
@@ -1489,9 +1613,11 @@ bool Codegen::visit(ObjectLiteral *ast)
ObjectPropertyValue &v = valueMap[name];
if (v.value ||
(gs->type == PropertyGetterSetter::Getter && v.hasGetter()) ||
- (gs->type == PropertyGetterSetter::Setter && v.hasSetter()))
+ (gs->type == PropertyGetterSetter::Setter && v.hasSetter())) {
throwSyntaxError(gs->lastSourceLocation(),
- QCoreApplication::translate("qv4codegen", "Illegal duplicate key '%1' in object literal").arg(name));
+ QStringLiteral("Illegal duplicate key '%1' in object literal").arg(name));
+ return false;
+ }
if (gs->type == PropertyGetterSetter::Getter)
v.getter = function;
else
@@ -1605,10 +1731,16 @@ bool Codegen::visit(ObjectLiteral *ast)
bool Codegen::visit(PostDecrementExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->base);
- if (!expr->isLValue())
- throwReferenceError(ast->base->lastSourceLocation(), "Invalid left-hand side expression in postfix operation");
- throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->decrementToken);
+ if (!expr->isLValue()) {
+ throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
+ return false;
+ }
+ if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->decrementToken))
+ return false;
const unsigned oldValue = _block->newTemp();
move(_block->TEMP(oldValue), unop(V4IR::OpUPlus, *expr));
@@ -1625,10 +1757,16 @@ bool Codegen::visit(PostDecrementExpression *ast)
bool Codegen::visit(PostIncrementExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->base);
- if (!expr->isLValue())
- throwReferenceError(ast->base->lastSourceLocation(), "Invalid left-hand side expression in postfix operation");
- throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->incrementToken);
+ if (!expr->isLValue()) {
+ throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
+ return false;
+ }
+ if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->incrementToken))
+ return false;
const unsigned oldValue = _block->newTemp();
move(_block->TEMP(oldValue), unop(V4IR::OpUPlus, *expr));
@@ -1645,8 +1783,17 @@ bool Codegen::visit(PostIncrementExpression *ast)
bool Codegen::visit(PreDecrementExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->expression);
- throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->decrementToken);
+ if (!expr->isLValue()) {
+ throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
+ return false;
+ }
+
+ if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->decrementToken))
+ return false;
V4IR::Expr *op = binop(V4IR::OpSub, *expr, _block->CONST(V4IR::NumberType, 1));
if (_expr.accept(nx)) {
move(*expr, op);
@@ -1661,8 +1808,17 @@ bool Codegen::visit(PreDecrementExpression *ast)
bool Codegen::visit(PreIncrementExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->expression);
- throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->incrementToken);
+ if (!expr->isLValue()) {
+ throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
+ return false;
+ }
+
+ if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->incrementToken))
+ return false;
V4IR::Expr *op = binop(V4IR::OpAdd, unop(V4IR::OpUPlus, *expr), _block->CONST(V4IR::NumberType, 1));
if (_expr.accept(nx)) {
move(*expr, op);
@@ -1677,24 +1833,36 @@ bool Codegen::visit(PreIncrementExpression *ast)
bool Codegen::visit(RegExpLiteral *ast)
{
+ if (hasError)
+ return false;
+
_expr.code = _block->REGEXP(_function->newString(ast->pattern.toString()), ast->flags);
return false;
}
bool Codegen::visit(StringLiteral *ast)
{
+ if (hasError)
+ return false;
+
_expr.code = _block->STRING(_function->newString(ast->value.toString()));
return false;
}
bool Codegen::visit(ThisExpression *ast)
{
+ if (hasError)
+ return false;
+
_expr.code = _block->NAME(QStringLiteral("this"), ast->thisToken.startLine, ast->thisToken.startColumn);
return false;
}
bool Codegen::visit(TildeExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->expression);
const unsigned t = _block->newTemp();
move(_block->TEMP(t), unop(V4IR::OpCompl, *expr));
@@ -1704,6 +1872,9 @@ bool Codegen::visit(TildeExpression *ast)
bool Codegen::visit(TrueLiteral *)
{
+ if (hasError)
+ return false;
+
if (_expr.accept(cx)) {
_block->JUMP(_expr.iftrue);
} else {
@@ -1714,6 +1885,9 @@ bool Codegen::visit(TrueLiteral *)
bool Codegen::visit(TypeOfExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->expression);
V4IR::ExprList *args = _function->New<V4IR::ExprList>();
args->init(reference(*expr));
@@ -1723,6 +1897,9 @@ bool Codegen::visit(TypeOfExpression *ast)
bool Codegen::visit(UnaryMinusExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->expression);
const unsigned t = _block->newTemp();
move(_block->TEMP(t), unop(V4IR::OpUMinus, *expr));
@@ -1732,6 +1909,9 @@ bool Codegen::visit(UnaryMinusExpression *ast)
bool Codegen::visit(UnaryPlusExpression *ast)
{
+ if (hasError)
+ return false;
+
Result expr = expression(ast->expression);
const unsigned t = _block->newTemp();
move(_block->TEMP(t), unop(V4IR::OpUPlus, *expr));
@@ -1741,6 +1921,9 @@ bool Codegen::visit(UnaryPlusExpression *ast)
bool Codegen::visit(VoidExpression *ast)
{
+ if (hasError)
+ return false;
+
statement(ast->expression);
_expr.code = _block->CONST(V4IR::UndefinedType, 0);
return false;
@@ -1748,6 +1931,9 @@ bool Codegen::visit(VoidExpression *ast)
bool Codegen::visit(FunctionDeclaration * ast)
{
+ if (hasError)
+ return false;
+
if (_env->compilationMode == QmlBinding)
move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0));
_expr.accept(nx);
@@ -1761,6 +1947,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
{
Loop *loop = 0;
qSwap(_loop, loop);
+ QStack<V4IR::BasicBlock *> exceptionHandlers;
+ qSwap(_exceptionHandlers, exceptionHandlers);
ScopeAndFinally *scopeAndFinally = 0;
@@ -1768,11 +1956,11 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
V4IR::Function *function = _module->newFunction(name, _function);
int functionIndex = _module->functions.count() - 1;
- V4IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), V4IR::Function::DontInsertBlock);
- V4IR::BasicBlock *throwBlock = function->newBasicBlock(groupStartBlock());
- function->hasDirectEval = _env->hasDirectEval;
+ V4IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock(), 0);
+ V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), 0, V4IR::Function::DontInsertBlock);
+ function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode;
function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
+ function->usesThis = _env->usesThis;
function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
function->isStrict = _env->isStrict;
function->isNamedExpression = _env->isNamedFunctionExpression;
@@ -1782,10 +1970,10 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
function->column = loc.startColumn;
if (function->usesArgumentsObject)
- _env->enter("arguments", Environment::VariableDeclaration);
+ _env->enter(QStringLiteral("arguments"), Environment::VariableDeclaration);
// variables in global code are properties of the global context object, not locals as with other functions.
- if (_env->compilationMode == FunctionCode) {
+ if (_env->compilationMode == FunctionCode || _env->compilationMode == QmlBinding) {
unsigned t = 0;
for (Environment::MemberMap::iterator it = _env->members.begin(); it != _env->members.end(); ++it) {
const QString &local = it.key();
@@ -1827,15 +2015,10 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
entryBlock->MOVE(entryBlock->TEMP(returnAddress), entryBlock->CONST(V4IR::UndefinedType, 0));
exitBlock->RET(exitBlock->TEMP(returnAddress));
- V4IR::ExprList *throwArgs = function->New<V4IR::ExprList>();
- throwArgs->expr = throwBlock->TEMP(returnAddress);
- throwBlock->EXP(throwBlock->CALL(throwBlock->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
- throwBlock->JUMP(exitBlock);
qSwap(_function, function);
qSwap(_block, entryBlock);
qSwap(_exitBlock, exitBlock);
- qSwap(_throwBlock, throwBlock);
qSwap(_returnAddress, returnAddress);
qSwap(_scopeAndFinally, scopeAndFinally);
@@ -1847,20 +2030,27 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
if (member.function) {
const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
member.function->body ? member.function->body->elements : 0);
- if (! _env->parent || _env->compilationMode == QmlBinding) {
+ if (! _env->parent) {
move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn),
_block->CLOSURE(function));
} else {
- assert(member.index >= 0);
+ Q_ASSERT(member.index >= 0);
move(_block->LOCAL(member.index, 0), _block->CLOSURE(function));
}
}
}
if (_function->usesArgumentsObject) {
- move(identifier("arguments", ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn),
+ move(identifier(QStringLiteral("arguments"), ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn),
_block->CALL(_block->NAME(V4IR::Name::builtin_setup_argument_object,
ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0));
}
+ if (_function->usesThis && !_function->isStrict) {
+ // make sure we convert this to an object
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_convert_this_to_object,
+ ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0));
+ }
+
+ beginFunctionBodyHook();
sourceElements(body);
@@ -1871,9 +2061,9 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
qSwap(_function, function);
qSwap(_block, entryBlock);
qSwap(_exitBlock, exitBlock);
- qSwap(_throwBlock, throwBlock);
qSwap(_returnAddress, returnAddress);
qSwap(_scopeAndFinally, scopeAndFinally);
+ qSwap(_exceptionHandlers, exceptionHandlers);
qSwap(_loop, loop);
leaveEnvironment();
@@ -1883,36 +2073,54 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool Codegen::visit(IdentifierPropertyName *ast)
{
+ if (hasError)
+ return false;
+
_property = ast->id.toString();
return false;
}
bool Codegen::visit(NumericLiteralPropertyName *ast)
{
+ if (hasError)
+ return false;
+
_property = QString::number(ast->id, 'g', 16);
return false;
}
bool Codegen::visit(StringLiteralPropertyName *ast)
{
+ if (hasError)
+ return false;
+
_property = ast->id.toString();
return false;
}
bool Codegen::visit(FunctionSourceElement *ast)
{
+ if (hasError)
+ return false;
+
statement(ast->declaration);
return false;
}
bool Codegen::visit(StatementSourceElement *ast)
{
+ if (hasError)
+ return false;
+
statement(ast->statement);
return false;
}
bool Codegen::visit(Block *ast)
{
+ if (hasError)
+ return false;
+
for (StatementList *it = ast->statements; it; it = it->next) {
statement(it->statement);
}
@@ -1921,8 +2129,13 @@ bool Codegen::visit(Block *ast)
bool Codegen::visit(BreakStatement *ast)
{
- if (!_loop)
- throwSyntaxError(ast->lastSourceLocation(), QCoreApplication::translate("qv4codegen", "Break outside of loop"));
+ if (hasError)
+ return false;
+
+ if (!_loop) {
+ throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop"));
+ return false;
+ }
Loop *loop = 0;
if (ast->label.isEmpty())
loop = _loop;
@@ -1931,8 +2144,10 @@ bool Codegen::visit(BreakStatement *ast)
if (loop->labelledStatement && loop->labelledStatement->label == ast->label)
break;
}
- if (!loop)
- throwSyntaxError(ast->lastSourceLocation(), QCoreApplication::translate("qv4codegen", "Undefined label '%1'").arg(ast->label.toString()));
+ if (!loop) {
+ throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Undefined label '%1'").arg(ast->label.toString()));
+ return false;
+ }
}
unwindException(loop->scopeAndFinally);
_block->JUMP(loop->breakBlock);
@@ -1941,6 +2156,9 @@ bool Codegen::visit(BreakStatement *ast)
bool Codegen::visit(ContinueStatement *ast)
{
+ if (hasError)
+ return false;
+
Loop *loop = 0;
if (ast->label.isEmpty()) {
for (loop = _loop; loop; loop = loop->parent) {
@@ -1955,11 +2173,15 @@ bool Codegen::visit(ContinueStatement *ast)
break;
}
}
- if (!loop)
- throwSyntaxError(ast->lastSourceLocation(), QCoreApplication::translate("qv4codegen", "Undefined label '%1'").arg(ast->label.toString()));
+ if (!loop) {
+ throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Undefined label '%1'").arg(ast->label.toString()));
+ return false;
+ }
+ }
+ if (!loop) {
+ throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("continue outside of loop"));
+ return false;
}
- if (!loop)
- throwSyntaxError(ast->lastSourceLocation(), QCoreApplication::translate("qv4codegen", "continue outside of loop"));
unwindException(loop->scopeAndFinally);
_block->JUMP(loop->continueBlock);
return false;
@@ -1973,9 +2195,12 @@ bool Codegen::visit(DebuggerStatement *)
bool Codegen::visit(DoWhileStatement *ast)
{
- V4IR::BasicBlock *loopbody = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *loopcond = _function->newBasicBlock(loopbody);
- V4IR::BasicBlock *loopend = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
+
+ V4IR::BasicBlock *loopbody = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *loopcond = _function->newBasicBlock(loopbody, exceptionHandler());
+ V4IR::BasicBlock *loopend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, loopbody, loopend, loopcond);
@@ -1997,11 +2222,17 @@ bool Codegen::visit(DoWhileStatement *ast)
bool Codegen::visit(EmptyStatement *)
{
+ if (hasError)
+ return true;
+
return false;
}
bool Codegen::visit(ExpressionStatement *ast)
{
+ if (hasError)
+ return true;
+
if (_env->compilationMode == EvalCode || _env->compilationMode == QmlBinding) {
Result e = expression(ast->expression);
if (*e)
@@ -2014,9 +2245,12 @@ bool Codegen::visit(ExpressionStatement *ast)
bool Codegen::visit(ForEachStatement *ast)
{
- V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin);
- V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
+
+ V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler());
+ V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, foreachin, foreachend, foreachin);
@@ -2052,16 +2286,19 @@ bool Codegen::visit(ForEachStatement *ast)
bool Codegen::visit(ForStatement *ast)
{
- V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond);
- V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond);
- V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
- enterLoop(ast, forcond, forend, forstep);
+ V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond, exceptionHandler());
+ V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond, exceptionHandler());
+ V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
statement(ast->initialiser);
_block->JUMP(forcond);
+ enterLoop(ast, forcond, forend, forstep);
+
_block = forcond;
if (ast->condition)
condition(ast->condition, forbody, forend);
@@ -2085,9 +2322,13 @@ bool Codegen::visit(ForStatement *ast)
bool Codegen::visit(IfStatement *ast)
{
- V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(groupStartBlock()) : 0;
- V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
+
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(groupStartBlock(), exceptionHandler()) : 0;
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+
condition(ast->expression, iftrue, ast->ko ? iffalse : endif);
_block = iftrue;
@@ -2107,12 +2348,16 @@ bool Codegen::visit(IfStatement *ast)
bool Codegen::visit(LabelledStatement *ast)
{
+ if (hasError)
+ return true;
+
// check that no outer loop contains the label
Loop *l = _loop;
while (l) {
if (l->labelledStatement && l->labelledStatement->label == ast->label) {
QString error = QString(QStringLiteral("Label '%1' has already been declared")).arg(ast->label.toString());
throwSyntaxError(ast->firstSourceLocation(), error);
+ return false;
}
l = l->parent;
}
@@ -2127,7 +2372,7 @@ bool Codegen::visit(LabelledStatement *ast)
AST::cast<AST::LocalForEachStatement *>(ast->statement)) {
statement(ast->statement); // labelledStatement will be associated with the ast->statement's loop.
} else {
- V4IR::BasicBlock *breakBlock = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *breakBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast->statement, 0, breakBlock, /*continueBlock*/ 0);
statement(ast->statement);
_block->JUMP(breakBlock);
@@ -2140,9 +2385,12 @@ bool Codegen::visit(LabelledStatement *ast)
bool Codegen::visit(LocalForEachStatement *ast)
{
- V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin);
- V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
+
+ V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler());
+ V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, foreachin, foreachend, foreachin);
@@ -2178,16 +2426,19 @@ bool Codegen::visit(LocalForEachStatement *ast)
bool Codegen::visit(LocalForStatement *ast)
{
- V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond);
- V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond);
- V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
- enterLoop(ast, forcond, forend, forstep);
+ V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond, exceptionHandler());
+ V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond, exceptionHandler());
+ V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
variableDeclarationList(ast->declarations);
_block->JUMP(forcond);
+ enterLoop(ast, forcond, forend, forstep);
+
_block = forcond;
if (ast->condition)
condition(ast->condition, forbody, forend);
@@ -2211,8 +2462,13 @@ bool Codegen::visit(LocalForStatement *ast)
bool Codegen::visit(ReturnStatement *ast)
{
- if (_env->compilationMode != FunctionCode && _env->compilationMode != QmlBinding)
- throwSyntaxError(ast->returnToken, QCoreApplication::translate("qv4codegen", "Return statement outside of function"));
+ if (hasError)
+ return true;
+
+ if (_env->compilationMode != FunctionCode && _env->compilationMode != QmlBinding) {
+ throwSyntaxError(ast->returnToken, QStringLiteral("Return statement outside of function"));
+ return false;
+ }
if (ast->expression) {
Result expr = expression(ast->expression);
move(_block->TEMP(_returnAddress), *expr);
@@ -2225,11 +2481,14 @@ bool Codegen::visit(ReturnStatement *ast)
bool Codegen::visit(SwitchStatement *ast)
{
- V4IR::BasicBlock *switchend = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
+
+ V4IR::BasicBlock *switchend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
if (ast->block) {
Result lhs = expression(ast->expression);
- V4IR::BasicBlock *switchcond = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *switchcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
_block->JUMP(switchcond);
V4IR::BasicBlock *previousBlock = 0;
@@ -2240,7 +2499,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
CaseClause *clause = it->clause;
- _block = _function->newBasicBlock(groupStartBlock());
+ _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
blockMap[clause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2253,7 +2512,7 @@ bool Codegen::visit(SwitchStatement *ast)
}
if (ast->block->defaultClause) {
- _block = _function->newBasicBlock(groupStartBlock());
+ _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
blockMap[ast->block->defaultClause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2268,7 +2527,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
CaseClause *clause = it->clause;
- _block = _function->newBasicBlock(groupStartBlock());
+ _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
blockMap[clause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2289,7 +2548,7 @@ bool Codegen::visit(SwitchStatement *ast)
CaseClause *clause = it->clause;
Result rhs = expression(clause->expression);
V4IR::BasicBlock *iftrue = blockMap[clause];
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
cjump(binop(V4IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse);
_block = iffalse;
}
@@ -2298,7 +2557,7 @@ bool Codegen::visit(SwitchStatement *ast)
CaseClause *clause = it->clause;
Result rhs = expression(clause->expression);
V4IR::BasicBlock *iftrue = blockMap[clause];
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
cjump(binop(V4IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse);
_block = iffalse;
}
@@ -2316,98 +2575,114 @@ bool Codegen::visit(SwitchStatement *ast)
bool Codegen::visit(ThrowStatement *ast)
{
+ if (hasError)
+ return true;
+
Result expr = expression(ast->expression);
move(_block->TEMP(_returnAddress), *expr);
- _block->JUMP(_throwBlock);
+ V4IR::ExprList *throwArgs = _function->New<V4IR::ExprList>();
+ throwArgs->expr = _block->TEMP(_returnAddress);
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
return false;
}
bool Codegen::visit(TryStatement *ast)
{
+ if (hasError)
+ return true;
+
_function->hasTry = true;
if (_function->isStrict && ast->catchExpression &&
- (ast->catchExpression->name == QLatin1String("eval") || ast->catchExpression->name == QLatin1String("arguments")))
- throwSyntaxError(ast->catchExpression->identifierToken, QCoreApplication::translate("qv4codegen", "Catch variable name may not be eval or arguments in strict mode"));
+ (ast->catchExpression->name == QLatin1String("eval") || ast->catchExpression->name == QLatin1String("arguments"))) {
+ throwSyntaxError(ast->catchExpression->identifierToken, QStringLiteral("Catch variable name may not be eval or arguments in strict mode"));
+ return false;
+ }
+
+ V4IR::BasicBlock *surroundingExceptionHandler = exceptionHandler();
- V4IR::BasicBlock *tryBody = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *catchBody = _function->newBasicBlock(groupStartBlock());
// We always need a finally body to clean up the exception handler
- V4IR::BasicBlock *finallyBody = _function->newBasicBlock(groupStartBlock());
+ // exceptions thrown in finally get catched by the surrounding catch block
+ V4IR::BasicBlock *finallyBody = 0;
+ V4IR::BasicBlock *catchBody = 0;
+ V4IR::BasicBlock *catchExceptionHandler = 0;
+ V4IR::BasicBlock *end = _function->newBasicBlock(groupStartBlock(), surroundingExceptionHandler, V4IR::Function::DontInsertBlock);
- V4IR::BasicBlock *throwBlock = _function->newBasicBlock(groupStartBlock());
- V4IR::ExprList *throwArgs = _function->New<V4IR::ExprList>();
- throwArgs->expr = throwBlock->TEMP(_returnAddress);
- throwBlock->EXP(throwBlock->CALL(throwBlock->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
- throwBlock->JUMP(catchBody);
- qSwap(_throwBlock, throwBlock);
+ if (ast->finallyExpression)
+ finallyBody = _function->newBasicBlock(groupStartBlock(), surroundingExceptionHandler, V4IR::Function::DontInsertBlock);
- int hasException = _block->newTemp();
- move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, false));
+ if (ast->catchExpression) {
+ // exception handler for the catch body
+ catchExceptionHandler = _function->newBasicBlock(groupStartBlock(), 0, V4IR::Function::DontInsertBlock);
+ pushExceptionHandler(catchExceptionHandler);
+ catchBody = _function->newBasicBlock(groupStartBlock(), catchExceptionHandler, V4IR::Function::DontInsertBlock);
+ popExceptionHandler();
+ pushExceptionHandler(catchBody);
+ } else {
+ Q_ASSERT(finallyBody);
+ pushExceptionHandler(finallyBody);
+ }
- // Pass the hidden "needRethrow" TEMP to the
- // builtin_delete_exception_handler, in order to have those TEMPs alive for
- // the duration of the exception handling block.
- V4IR::ExprList *finishTryArgs = _function->New<V4IR::ExprList>();
- finishTryArgs->init(_block->TEMP(hasException));
+ V4IR::BasicBlock *tryBody = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ _block->JUMP(tryBody);
- ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression, finishTryArgs);
+ ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression);
_scopeAndFinally = &tcf;
- int exception_to_rethrow = _block->newTemp();
-
- _block->TRY(tryBody, catchBody,
- _function->newString(ast->catchExpression ? ast->catchExpression->name.toString() : QString()),
- _block->TEMP(exception_to_rethrow));
-
_block = tryBody;
statement(ast->statement);
- _block->JUMP(finallyBody);
+ _block->JUMP(finallyBody ? finallyBody : end);
- _block = catchBody;
+ popExceptionHandler();
if (ast->catchExpression) {
- // check if an exception got thrown within catch. Go to finally
- // and then rethrow
- V4IR::BasicBlock *b = _function->newBasicBlock(groupStartBlock());
- _block->CJUMP(_block->TEMP(hasException), finallyBody, b);
- _block = b;
- }
+ pushExceptionHandler(catchExceptionHandler);
+ _function->insertBasicBlock(catchBody);
+ _block = catchBody;
- move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, true));
-
- if (ast->catchExpression) {
++_function->insideWithOrCatch;
+ V4IR::ExprList *catchArgs = _function->New<V4IR::ExprList>();
+ catchArgs->init(_block->STRING(_function->newString(ast->catchExpression->name.toString())));
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_push_catch_scope, 0, 0), catchArgs));
{
ScopeAndFinally scope(_scopeAndFinally, ScopeAndFinally::CatchScope);
_scopeAndFinally = &scope;
statement(ast->catchExpression->statement);
_scopeAndFinally = scope.parent;
}
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
--_function->insideWithOrCatch;
- move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, false));
+ _block->JUMP(finallyBody ? finallyBody : end);
+ popExceptionHandler();
+
+ _function->insertBasicBlock(catchExceptionHandler);
+ catchExceptionHandler->EXP(catchExceptionHandler->CALL(catchExceptionHandler->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
+ if (finallyBody || surroundingExceptionHandler)
+ catchExceptionHandler->JUMP(finallyBody ? finallyBody : surroundingExceptionHandler);
+ else
+ catchExceptionHandler->EXP(catchExceptionHandler->CALL(catchExceptionHandler->NAME(V4IR::Name::builtin_rethrow, 0, 0), 0));
}
- _block->JUMP(finallyBody);
_scopeAndFinally = tcf.parent;
- qSwap(_throwBlock, throwBlock);
+ if (finallyBody) {
+ _function->insertBasicBlock(finallyBody);
+ _block = finallyBody;
- V4IR::BasicBlock *after = _function->newBasicBlock(groupStartBlock());
- _block = finallyBody;
+ int hasException = _block->newTemp();
+ move(_block->TEMP(hasException), _block->CALL(_block->NAME(V4IR::Name::builtin_unwind_exception, /*line*/0, /*column*/0), 0));
- _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_finish_try, 0, 0), finishTryArgs));
+ if (ast->finallyExpression && ast->finallyExpression->statement)
+ statement(ast->finallyExpression->statement);
- if (ast->finallyExpression && ast->finallyExpression->statement)
- statement(ast->finallyExpression->statement);
-
- V4IR::BasicBlock *rethrowBlock = _function->newBasicBlock(groupStartBlock());
- _block->CJUMP(_block->TEMP(hasException), rethrowBlock, after);
- _block = rethrowBlock;
- move(_block->TEMP(_returnAddress), _block->TEMP(exception_to_rethrow));
- _block->JUMP(_throwBlock);
+ V4IR::ExprList *arg = _function->New<V4IR::ExprList>();
+ arg->expr = _block->TEMP(hasException);
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), arg));
+ _block->JUMP(end);
+ }
- _block = after;
+ _function->insertBasicBlock(end);
+ _block = end;
return false;
}
@@ -2420,14 +2695,13 @@ void Codegen::unwindException(Codegen::ScopeAndFinally *outest)
while (_scopeAndFinally != outest) {
switch (_scopeAndFinally->type) {
case ScopeAndFinally::WithScope:
- _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0)));
// fall through
case ScopeAndFinally::CatchScope:
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0)));
_scopeAndFinally = _scopeAndFinally->parent;
--_function->insideWithOrCatch;
break;
case ScopeAndFinally::TryScope: {
- _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_finish_try, 0, 0), _scopeAndFinally->finishTryArgs));
ScopeAndFinally *tc = _scopeAndFinally;
_scopeAndFinally = tc->parent;
if (tc->finally && tc->finally->statement)
@@ -2442,15 +2716,21 @@ void Codegen::unwindException(Codegen::ScopeAndFinally *outest)
bool Codegen::visit(VariableStatement *ast)
{
+ if (hasError)
+ return true;
+
variableDeclarationList(ast->declarations);
return false;
}
bool Codegen::visit(WhileStatement *ast)
{
- V4IR::BasicBlock *whilecond = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *whilebody = _function->newBasicBlock(whilecond);
- V4IR::BasicBlock *whileend = _function->newBasicBlock(groupStartBlock());
+ if (hasError)
+ return true;
+
+ V4IR::BasicBlock *whilecond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *whilebody = _function->newBasicBlock(whilecond, exceptionHandler());
+ V4IR::BasicBlock *whileend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, whilecond, whileend, whilecond);
@@ -2470,9 +2750,22 @@ bool Codegen::visit(WhileStatement *ast)
bool Codegen::visit(WithStatement *ast)
{
+ if (hasError)
+ return true;
+
_function->hasWith = true;
- V4IR::BasicBlock *withBlock = _function->newBasicBlock(groupStartBlock());
+ // need an exception handler for with to cleanup the with scope
+ V4IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
+ if (!exceptionHandler())
+ withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(V4IR::Name::builtin_rethrow, 0, 0), 0));
+ else
+ withExceptionHandler->JUMP(exceptionHandler());
+
+ pushExceptionHandler(withExceptionHandler);
+
+ V4IR::BasicBlock *withBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
_block->JUMP(withBlock);
_block = withBlock;
@@ -2491,8 +2784,9 @@ bool Codegen::visit(WithStatement *ast)
}
--_function->insideWithOrCatch;
_block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
+ popExceptionHandler();
- V4IR::BasicBlock *next = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *next = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
_block->JUMP(next);
_block = next;
@@ -2501,60 +2795,65 @@ bool Codegen::visit(WithStatement *ast)
bool Codegen::visit(UiArrayBinding *)
{
- assert(!"not implemented");
+ Q_ASSERT(!"not implemented");
return false;
}
bool Codegen::visit(UiObjectBinding *)
{
- assert(!"not implemented");
+ Q_ASSERT(!"not implemented");
return false;
}
bool Codegen::visit(UiObjectDefinition *)
{
- assert(!"not implemented");
+ Q_ASSERT(!"not implemented");
return false;
}
bool Codegen::visit(UiPublicMember *)
{
- assert(!"not implemented");
+ Q_ASSERT(!"not implemented");
return false;
}
bool Codegen::visit(UiScriptBinding *)
{
- assert(!"not implemented");
+ Q_ASSERT(!"not implemented");
return false;
}
bool Codegen::visit(UiSourceElement *)
{
- assert(!"not implemented");
+ Q_ASSERT(!"not implemented");
return false;
}
-void Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(V4IR::Expr *expr, const SourceLocation& loc)
+bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(V4IR::Expr *expr, const SourceLocation& loc)
{
if (!_env->isStrict)
- return;
+ return false;
if (V4IR::Name *n = expr->asName()) {
if (*n->id != QLatin1String("eval") && *n->id != QLatin1String("arguments"))
- return;
+ return false;
} else if (V4IR::Temp *t = expr->asTemp()) {
if (!t->isArgumentsOrEval)
- return;
+ return false;
} else {
- return;
+ return false;
}
- throwSyntaxError(loc, QCoreApplication::translate("qv4codegen", "Variable name may not be eval or arguments in strict mode"));
+ throwSyntaxError(loc, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
+ return true;
}
void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
{
+ if (hasError)
+ return;
+
+ hasError = true;
QQmlError error;
- error.setUrl(QUrl::fromLocalFile(_module->fileName));
+ error.setUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
error.setDescription(detail);
error.setLine(loc.startLine);
error.setColumn(loc.startColumn);
@@ -2563,8 +2862,12 @@ void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
{
+ if (hasError)
+ return;
+
+ hasError = true;
QQmlError error;
- error.setUrl(QUrl::fromLocalFile(_module->fileName));
+ error.setUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
error.setDescription(detail);
error.setLine(loc.startLine);
error.setColumn(loc.startColumn);
@@ -2578,10 +2881,16 @@ QList<QQmlError> Codegen::errors() const
void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail)
{
+ if (hasError)
+ return;
+ hasError = true;
context->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn);
}
void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail)
{
+ if (hasError)
+ return;
+ hasError = true;
context->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn);
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 66b80c377b..32f1f1bfd4 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -72,7 +72,10 @@ public:
GlobalCode,
EvalCode,
FunctionCode,
- QmlBinding
+ QmlBinding // This is almost the same as EvalCode, except:
+ // * function declarations are moved to the return address when encountered
+ // * return statements are allowed everywhere (like in FunctionCode)
+ // * variable declarations are treated as true locals (like in FunctionCode)
};
void generateFromProgram(const QString &fileName,
@@ -145,6 +148,7 @@ protected:
bool hasNestedFunctions;
bool isStrict;
bool isNamedFunctionExpression;
+ bool usesThis;
enum UsesArgumentsObject {
ArgumentsObjectUnknown,
ArgumentsObjectNotUsed,
@@ -163,6 +167,7 @@ protected:
, hasNestedFunctions(false)
, isStrict(false)
, isNamedFunctionExpression(false)
+ , usesThis(false)
, usesArgumentsObject(ArgumentsObjectUnknown)
, compilationMode(mode)
{
@@ -238,12 +243,11 @@ protected:
ScopeAndFinally *parent;
AST::Finally *finally;
- V4IR::ExprList *finishTryArgs;
ScopeType type;
- ScopeAndFinally(ScopeAndFinally *parent, ScopeType t = WithScope) : parent(parent), finally(0), finishTryArgs(0), type(t) {}
- ScopeAndFinally(ScopeAndFinally *parent, AST::Finally *finally, V4IR::ExprList *finishTryArgs)
- : parent(parent), finally(finally), finishTryArgs(finishTryArgs), type(TryScope)
+ ScopeAndFinally(ScopeAndFinally *parent, ScopeType t = WithScope) : parent(parent), finally(0), type(t) {}
+ ScopeAndFinally(ScopeAndFinally *parent, AST::Finally *finally)
+ : parent(parent), finally(finally), type(TryScope)
{}
};
@@ -272,6 +276,22 @@ protected:
return it->groupStartBlock;
return 0;
}
+ V4IR::BasicBlock *exceptionHandler() const
+ {
+ if (_exceptionHandlers.isEmpty())
+ return 0;
+ return _exceptionHandlers.top();
+ }
+ void pushExceptionHandler(V4IR::BasicBlock *handler)
+ {
+ handler->isExceptionHandler = true;
+ _exceptionHandlers.push(handler);
+ }
+ void popExceptionHandler()
+ {
+ Q_ASSERT(!_exceptionHandlers.isEmpty());
+ _exceptionHandlers.pop();
+ }
V4IR::Expr *member(V4IR::Expr *base, const QString *name);
V4IR::Expr *subscript(V4IR::Expr *base, V4IR::Expr *index);
@@ -308,6 +328,9 @@ protected:
void variableDeclarationList(AST::VariableDeclarationList *ast);
V4IR::Expr *identifier(const QString &name, int line = 0, int col = 0);
+ // Hook provided to implement QML lookup semantics
+ virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
+ virtual void beginFunctionBodyHook() {}
// nodes
virtual bool visit(AST::ArgumentList *ast);
@@ -413,7 +436,7 @@ protected:
virtual bool visit(AST::UiScriptBinding *ast);
virtual bool visit(AST::UiSourceElement *ast);
- void throwSyntaxErrorOnEvalOrArgumentsInStrictMode(V4IR::Expr* expr, const AST::SourceLocation &loc);
+ bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(V4IR::Expr* expr, const AST::SourceLocation &loc);
virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
@@ -428,7 +451,6 @@ protected:
V4IR::Function *_function;
V4IR::BasicBlock *_block;
V4IR::BasicBlock *_exitBlock;
- V4IR::BasicBlock *_throwBlock;
unsigned _returnAddress;
Environment *_env;
Loop *_loop;
@@ -436,8 +458,11 @@ protected:
ScopeAndFinally *_scopeAndFinally;
QHash<AST::Node *, Environment *> _envMap;
QHash<AST::FunctionExpression *, int> _functionMap;
+ QStack<V4IR::BasicBlock *> _exceptionHandlers;
bool _strictMode;
+ bool _fileNameIsUrl;
+ bool hasError;
QList<QQmlError> _errors;
class ScanFunctions: protected Visitor
@@ -450,6 +475,12 @@ protected:
void enterEnvironment(AST::Node *node, CompilationMode compilationMode);
void leaveEnvironment();
+ void enterQmlScope(AST::Node *ast, const QString &name)
+ { enterFunction(ast, name, /*formals*/0, /*body*/0, /*expr*/0, /*isExpression*/false); }
+
+ void enterQmlFunction(AST::FunctionDeclaration *ast)
+ { enterFunction(ast, false, false); }
+
protected:
using Visitor::visit;
using Visitor::endVisit;
@@ -489,6 +520,7 @@ protected:
virtual bool visit(AST::LocalForStatement *ast);
virtual bool visit(AST::ForEachStatement *ast);
virtual bool visit(AST::LocalForEachStatement *ast);
+ virtual bool visit(AST::ThisExpression *ast);
virtual bool visit(AST::Block *ast);
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index b485dcc240..ce0c7abf9e 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -46,7 +46,6 @@
#include <private/qv4objectproto_p.h>
#include <private/qv4lookup_p.h>
#include <private/qv4regexpobject_p.h>
-#include <private/qv4unwindhelper_p.h>
#include <algorithm>
@@ -56,13 +55,6 @@ namespace QV4 {
namespace CompiledData {
-namespace {
- bool functionSortHelper(QV4::Function *lhs, QV4::Function *rhs)
- {
- return reinterpret_cast<quintptr>(lhs->codePtr) < reinterpret_cast<quintptr>(rhs->codePtr);
- }
-}
-
CompilationUnit::~CompilationUnit()
{
unlink();
@@ -78,13 +70,13 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
runtimeStrings = (QV4::SafeString *)malloc(data->stringTableSize * sizeof(QV4::SafeString));
// 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::SafeString));
- for (int i = 0; i < data->stringTableSize; ++i)
+ for (uint i = 0; i < data->stringTableSize; ++i)
runtimeStrings[i] = engine->newIdentifier(data->stringAt(i));
runtimeRegularExpressions = new QV4::SafeValue[data->regexpTableSize];
// memset the regexps to 0 in case a GC run happens while we're within the loop below
memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::SafeValue));
- for (int i = 0; i < data->regexpTableSize; ++i) {
+ for (uint i = 0; i < data->regexpTableSize; ++i) {
const CompiledData::RegExp *re = data->regexpAt(i);
int flags = 0;
if (re->flags & CompiledData::RegExp::RegExp_Global)
@@ -110,8 +102,8 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_GlobalGetter)
l->globalGetter = QV4::Lookup::globalGetterGeneric;
- for (int i = 0; i < QV4::Lookup::Size; ++i)
- l->classList[i] = 0;
+ for (int j = 0; j < QV4::Lookup::Size; ++j)
+ l->classList[j] = 0;
l->level = -1;
l->index = UINT_MAX;
l->name = runtimeStrings[compiledLookups[i].nameIndex].asString();
@@ -121,7 +113,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
if (data->jsClassTableSize) {
runtimeClasses = (QV4::InternalClass**)malloc(data->jsClassTableSize * sizeof(QV4::InternalClass*));
- for (int i = 0; i < data->jsClassTableSize; ++i) {
+ for (uint i = 0; i < data->jsClassTableSize; ++i) {
int memberCount = 0;
const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount);
QV4::InternalClass *klass = engine->objectClass;
@@ -166,20 +158,20 @@ void CompilationUnit::unlink()
runtimeFunctions.clear();
}
-void CompilationUnit::markObjects()
+void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
{
- for (int i = 0; i < data->stringTableSize; ++i)
- runtimeStrings[i].mark();
+ for (uint i = 0; i < data->stringTableSize; ++i)
+ runtimeStrings[i].mark(e);
if (runtimeRegularExpressions) {
- for (int i = 0; i < data->regexpTableSize; ++i)
- runtimeRegularExpressions[i].mark();
+ for (uint i = 0; i < data->regexpTableSize; ++i)
+ runtimeRegularExpressions[i].mark(e);
}
for (int i = 0; i < runtimeFunctions.count(); ++i)
if (runtimeFunctions[i])
- runtimeFunctions[i]->mark();
+ runtimeFunctions[i]->mark(e);
if (runtimeLookups) {
- for (int i = 0; i < data->lookupTableSize; ++i)
- runtimeLookups[i].name->mark();
+ for (uint i = 0; i < data->lookupTableSize; ++i)
+ runtimeLookups[i].name->mark(e);
}
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 2c0a46f3c5..90f27d5f57 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -160,6 +160,8 @@ struct Unit
uint offsetToLookupTable;
uint regexpTableSize;
uint offsetToRegexpTable;
+ uint constantTableSize;
+ uint offsetToConstantTable;
uint jsClassTableSize;
uint offsetToJSClassTable;
qint32 indexOfRootFunction;
@@ -186,6 +188,9 @@ struct Unit
const RegExp *regexpAt(int index) const {
return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
}
+ const QV4::SafeValue *constants() const {
+ return reinterpret_cast<const QV4::SafeValue*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
+ }
const JSClassMember *jsClassAt(int idx, int *nMembers) const {
const uint *offsetTable = reinterpret_cast<const uint *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
@@ -196,11 +201,12 @@ struct Unit
return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
}
- static int calculateSize(uint headerSize, uint nStrings, uint nFunctions, uint nRegExps,
+ static int calculateSize(uint headerSize, uint nStrings, uint nFunctions, uint nRegExps, uint nConstants,
uint nLookups, uint nClasses) {
return (headerSize
+ (nStrings + nFunctions + nClasses) * sizeof(uint)
+ nRegExps * RegExp::calculateSize()
+ + nConstants * sizeof(QV4::ReturnedValue)
+ nLookups * Lookup::calculateSize()
+ 7) & ~7; }
};
@@ -211,7 +217,8 @@ struct Function
HasDirectEval = 0x1,
UsesArgumentsObject = 0x2,
IsStrict = 0x4,
- IsNamedExpression = 0x8
+ IsNamedExpression = 0x8,
+ HasCatchOrWith = 0x10
};
quint32 index; // in CompilationUnit's function table
@@ -226,6 +233,16 @@ struct Function
quint32 nInnerFunctions;
quint32 innerFunctionsOffset;
Location location;
+
+ // Qml Extensions Begin
+ quint32 nDependingIdObjects;
+ quint32 dependingIdObjectsOffset; // Array of resolved ID objects
+ quint32 nDependingContextProperties;
+ quint32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
+ quint32 nDependingScopeProperties;
+ quint32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
+ // Qml Extensions End
+
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
// quint32 offsetForInnerFunctions[nInnerFunctions]
@@ -234,9 +251,14 @@ struct Function
const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
const quint32 *lineNumberMapping() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + lineNumberMappingOffset); }
+ const quint32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
+ const quint32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
+ const quint32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
+
+ inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; }
- static int calculateSize(int nFormals, int nLocals, int nInnerfunctions, int lineNumberMappings) {
- return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + 2 * lineNumberMappings) * sizeof(quint32) + 7) & ~0x7;
+ static int calculateSize(int nFormals, int nLocals, int nInnerfunctions, int lineNumberMappings, int nIdObjectDependencies, int nPropertyDependencies) {
+ return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + 2 * lineNumberMappings + nIdObjectDependencies + 2 * nPropertyDependencies) * sizeof(quint32) + 7) & ~0x7;
}
};
@@ -484,7 +506,7 @@ struct Q_QML_EXPORT CompilationUnit
// ### runtime data
// pointer to qml data for QML unit
- void markObjects();
+ void markObjects(QV4::ExecutionEngine *e);
protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 7d8c188927..cb17b86702 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -43,6 +43,7 @@
#include <qv4compileddata_p.h>
#include <qv4isel_p.h>
#include <qv4engine_p.h>
+#include <private/qqmlpropertycache_p.h>
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QQmlJS::V4IR::Module *module, int headerSize)
: irModule(module)
@@ -115,6 +116,15 @@ int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::V4IR::RegExp *regexp)
return regexps.size() - 1;
}
+int QV4::Compiler::JSUnitGenerator::registerConstant(QV4::ReturnedValue v)
+{
+ int idx = constants.indexOf(v);
+ if (idx >= 0)
+ return idx;
+ constants.append(v);
+ return constants.size() - 1;
+}
+
void QV4::Compiler::JSUnitGenerator::registerLineNumberMapping(QQmlJS::V4IR::Function *function, const QVector<uint> &mappings)
{
lineNumberMappingsPerFunction.insert(function, mappings);
@@ -160,9 +170,24 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
registerString(*f->formals.at(i));
for (int i = 0; i < f->locals.size(); ++i)
registerString(*f->locals.at(i));
+
+ if (f->hasQmlDependencies()) {
+ QSet<int> idObjectDeps = f->idObjectDependencies;
+ QSet<QQmlPropertyData*> contextPropertyDeps = f->contextObjectDependencies;
+ QSet<QQmlPropertyData*> scopePropertyDeps = f->scopeObjectDependencies;
+
+ if (!idObjectDeps.isEmpty())
+ qmlIdObjectDependenciesPerFunction.insert(f, idObjectDeps);
+ if (!contextPropertyDeps.isEmpty())
+ qmlContextPropertyDependenciesPerFunction.insert(f, contextPropertyDeps);
+ if (!scopePropertyDeps.isEmpty())
+ qmlScopePropertyDependenciesPerFunction.insert(f, scopePropertyDeps);
+ }
+
}
- int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, strings.size(), irModule->functions.size(), regexps.size(), lookups.size(), jsClasses.count());
+ int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, strings.size(), irModule->functions.size(), regexps.size(),
+ constants.size(), lookups.size(), jsClasses.count());
uint functionDataSize = 0;
for (int i = 0; i < irModule->functions.size(); ++i) {
@@ -174,7 +199,24 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd())
lineNumberMappingCount = lineNumberMapping->count() / 2;
- functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount);
+ int qmlIdDepsCount = 0;
+ int qmlPropertyDepsCount = 0;
+
+ if (f->hasQmlDependencies()) {
+ IdDependencyHash::ConstIterator idIt = qmlIdObjectDependenciesPerFunction.find(f);
+ if (idIt != qmlIdObjectDependenciesPerFunction.constEnd())
+ qmlIdDepsCount += idIt->count();
+
+ PropertyDependencyHash::ConstIterator it = qmlContextPropertyDependenciesPerFunction.find(f);
+ if (it != qmlContextPropertyDependenciesPerFunction.constEnd())
+ qmlPropertyDepsCount += it->count();
+
+ it = qmlScopePropertyDependenciesPerFunction.find(f);
+ if (it != qmlScopePropertyDependenciesPerFunction.constEnd())
+ qmlPropertyDepsCount += it->count();
+ }
+
+ functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount, qmlIdDepsCount, qmlPropertyDepsCount);
}
const int totalSize = unitSize + functionDataSize + stringDataSize + jsClassDataSize;
@@ -196,8 +238,10 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
unit->offsetToLookupTable = unit->offsetToFunctionTable + unit->functionTableSize * sizeof(uint);
unit->regexpTableSize = regexps.size();
unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize();
+ unit->constantTableSize = constants.size();
+ unit->offsetToConstantTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
unit->jsClassTableSize = jsClasses.count();
- unit->offsetToJSClassTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
+ unit->offsetToJSClassTable = unit->offsetToConstantTable + unit->constantTableSize * sizeof(ReturnedValue);
unit->indexOfRootFunction = -1;
unit->sourceFileIndex = getStringId(irModule->fileName);
@@ -222,11 +266,11 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
}
uint *functionTable = (uint *)(data + unit->offsetToFunctionTable);
- for (uint i = 0; i < irModule->functions.size(); ++i)
+ for (int i = 0; i < irModule->functions.size(); ++i)
functionTable[i] = functionOffsets.value(irModule->functions.at(i));
char *f = data + unitSize + stringDataSize;
- for (uint i = 0; i < irModule->functions.size(); ++i) {
+ for (int i = 0; i < irModule->functions.size(); ++i) {
QQmlJS::V4IR::Function *function = irModule->functions.at(i);
if (function == irModule->rootFunction)
unit->indexOfRootFunction = i;
@@ -242,6 +286,9 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
CompiledData::RegExp *regexpTable = (CompiledData::RegExp *)(data + unit->offsetToRegexpTable);
memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
+ ReturnedValue *constantTable = (ReturnedValue *)(data + unit->offsetToConstantTable);
+ memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
+
// write js classes and js class lookup table
uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable);
char *jsClass = data + unitSize + stringDataSize + functionDataSize;
@@ -267,7 +314,7 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
- QHash<QQmlJS::V4IR::Function *, QVector<uint> >::ConstIterator lineNumberMapping = lineNumberMappingsPerFunction.find(irFunction);
+ quint32 currentOffset = sizeof(QV4::CompiledData::Function);
function->index = index;
function->nameIndex = getStringId(*irFunction->name);
@@ -280,19 +327,59 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
function->flags |= CompiledData::Function::IsStrict;
if (irFunction->isNamedExpression)
function->flags |= CompiledData::Function::IsNamedExpression;
+ if (irFunction->hasTry || irFunction->hasWith)
+ function->flags |= CompiledData::Function::HasCatchOrWith;
function->nFormals = irFunction->formals.size();
- function->formalsOffset = sizeof(QV4::CompiledData::Function);
+ function->formalsOffset = currentOffset;
+ currentOffset += function->nFormals * sizeof(quint32);
+
function->nLocals = irFunction->locals.size();
- function->localsOffset = function->formalsOffset + function->nFormals * sizeof(quint32);
+ function->localsOffset = currentOffset;
+ currentOffset += function->nLocals * sizeof(quint32);
function->nLineNumberMappingEntries = 0;
+ QHash<QQmlJS::V4IR::Function *, QVector<uint> >::ConstIterator lineNumberMapping = lineNumberMappingsPerFunction.find(irFunction);
if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd()) {
function->nLineNumberMappingEntries = lineNumberMapping->count() / 2;
}
- function->lineNumberMappingOffset = function->localsOffset + function->nLocals * sizeof(quint32);
+ function->lineNumberMappingOffset = currentOffset;
+ currentOffset += function->nLineNumberMappingEntries * 2 * sizeof(quint32);
function->nInnerFunctions = irFunction->nestedFunctions.size();
- function->innerFunctionsOffset = function->lineNumberMappingOffset + function->nLineNumberMappingEntries * 2 * sizeof(quint32);
+ function->innerFunctionsOffset = currentOffset;
+ currentOffset += function->nInnerFunctions * sizeof(quint32);
+
+ function->nDependingIdObjects = 0;
+ function->nDependingContextProperties = 0;
+ function->nDependingScopeProperties = 0;
+
+ QSet<int> qmlIdObjectDeps;
+ QSet<QQmlPropertyData*> qmlContextPropertyDeps;
+ QSet<QQmlPropertyData*> qmlScopePropertyDeps;
+
+ if (irFunction->hasQmlDependencies()) {
+ qmlIdObjectDeps = qmlIdObjectDependenciesPerFunction.value(irFunction);
+ qmlContextPropertyDeps = qmlContextPropertyDependenciesPerFunction.value(irFunction);
+ qmlScopePropertyDeps = qmlScopePropertyDependenciesPerFunction.value(irFunction);
+
+ if (!qmlIdObjectDeps.isEmpty()) {
+ function->nDependingIdObjects = qmlIdObjectDeps.count();
+ function->dependingIdObjectsOffset = currentOffset;
+ currentOffset += function->nDependingIdObjects * sizeof(quint32);
+ }
+
+ if (!qmlContextPropertyDeps.isEmpty()) {
+ function->nDependingContextProperties = qmlContextPropertyDeps.count();
+ function->dependingContextPropertiesOffset = currentOffset;
+ currentOffset += function->nDependingContextProperties * sizeof(quint32) * 2;
+ }
+
+ if (!qmlScopePropertyDeps.isEmpty()) {
+ function->nDependingScopeProperties = qmlScopePropertyDeps.count();
+ function->dependingScopePropertiesOffset = currentOffset;
+ currentOffset += function->nDependingScopeProperties * sizeof(quint32) * 2;
+ }
+ }
function->location.line = irFunction->line;
function->location.column = irFunction->column;
@@ -318,7 +405,25 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
for (int i = 0; i < irFunction->nestedFunctions.size(); ++i)
innerFunctions[i] = functionOffsets.value(irFunction->nestedFunctions.at(i));
- return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries);
+ // write QML dependencies
+ quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
+ foreach (int id, qmlIdObjectDeps)
+ *writtenDeps++ = id;
+
+ writtenDeps = (quint32 *)(f + function->dependingContextPropertiesOffset);
+ foreach (QQmlPropertyData *property, qmlContextPropertyDeps) {
+ *writtenDeps++ = property->coreIndex;
+ *writtenDeps++ = property->notifyIndex;
+ }
+
+ writtenDeps = (quint32 *)(f + function->dependingScopePropertiesOffset);
+ foreach (QQmlPropertyData *property, qmlScopePropertyDeps) {
+ *writtenDeps++ = property->coreIndex;
+ *writtenDeps++ = property->notifyIndex;
+ }
+
+ return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries,
+ function->nDependingIdObjects, function->nDependingContextProperties + function->nDependingScopeProperties);
}
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index b875833463..6338babb5a 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -46,6 +46,8 @@
QT_BEGIN_NAMESPACE
+class QQmlPropertyData;
+
namespace QV4 {
namespace CompiledData {
@@ -71,6 +73,8 @@ struct Q_QML_EXPORT JSUnitGenerator {
int registerRegExp(QQmlJS::V4IR::RegExp *regexp);
+ int registerConstant(ReturnedValue v);
+
void registerLineNumberMapping(QQmlJS::V4IR::Function *function, const QVector<uint> &mappings);
int registerJSClass(QQmlJS::V4IR::ExprList *args);
@@ -85,10 +89,18 @@ struct Q_QML_EXPORT JSUnitGenerator {
QHash<QQmlJS::V4IR::Function *, uint> functionOffsets;
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
+ QVector<ReturnedValue> constants;
QHash<QQmlJS::V4IR::Function *, QVector<uint> > lineNumberMappingsPerFunction;
QList<QList<CompiledData::JSClassMember> > jsClasses;
uint jsClassDataSize;
uint headerSize;
+
+ typedef QHash<QQmlJS::V4IR::Function *, QSet<int> > IdDependencyHash;
+ IdDependencyHash qmlIdObjectDependenciesPerFunction;
+
+ typedef QHash<QQmlJS::V4IR::Function *, QSet<QQmlPropertyData*> > PropertyDependencyHash;
+ PropertyDependencyHash qmlContextPropertyDependenciesPerFunction;
+ PropertyDependencyHash qmlScopePropertyDependenciesPerFunction;
};
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 3c28633491..180391ff33 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -51,26 +51,33 @@ QT_BEGIN_NAMESPACE
#define FOR_EACH_MOTH_INSTR(F) \
F(Ret, ret) \
- F(LoadValue, loadValue) \
F(LoadRuntimeString, loadRuntimeString) \
F(LoadRegExp, loadRegExp) \
F(LoadClosure, loadClosure) \
- F(MoveTemp, moveTemp) \
+ F(Move, move) \
F(SwapTemps, swapTemps) \
F(LoadName, loadName) \
+ F(GetGlobalLookup, getGlobalLookup) \
F(StoreName, storeName) \
F(LoadElement, loadElement) \
F(StoreElement, storeElement) \
F(LoadProperty, loadProperty) \
+ F(GetLookup, getLookup) \
F(StoreProperty, storeProperty) \
+ F(SetLookup, setLookup) \
+ F(StoreQObjectProperty, storeQObjectProperty) \
+ F(LoadQObjectProperty, loadQObjectProperty) \
F(Push, push) \
- F(EnterTry, enterTry) \
F(CallValue, callValue) \
F(CallProperty, callProperty) \
+ F(CallPropertyLookup, callPropertyLookup) \
F(CallElement, callElement) \
F(CallActivationProperty, callActivationProperty) \
+ F(CallGlobalLookup, callGlobalLookup) \
+ F(SetExceptionHandler, setExceptionHandler) \
F(CallBuiltinThrow, callBuiltinThrow) \
- F(CallBuiltinFinishTry, callBuiltinFinishTry) \
+ F(CallBuiltinUnwindException, callBuiltinUnwindException) \
+ F(CallBuiltinPushCatchScope, callBuiltinPushCatchScope) \
F(CallBuiltinPushScope, callBuiltinPushScope) \
F(CallBuiltinPopScope, callBuiltinPopScope) \
F(CallBuiltinForeachIteratorObject, callBuiltinForeachIteratorObject) \
@@ -88,18 +95,42 @@ QT_BEGIN_NAMESPACE
F(CallBuiltinDefineArray, callBuiltinDefineArray) \
F(CallBuiltinDefineObjectLiteral, callBuiltinDefineObjectLiteral) \
F(CallBuiltinSetupArgumentsObject, callBuiltinSetupArgumentsObject) \
+ F(CallBuiltinConvertThisToObject, callBuiltinConvertThisToObject) \
F(CreateValue, createValue) \
F(CreateProperty, createProperty) \
+ F(ConstructPropertyLookup, constructPropertyLookup) \
F(CreateActivationProperty, createActivationProperty) \
+ F(ConstructGlobalLookup, constructGlobalLookup) \
F(Jump, jump) \
F(CJump, cjump) \
- F(Unop, unop) \
+ F(UNot, unot) \
+ F(UNotBool, unotBool) \
+ F(UPlus, uplus) \
+ F(UMinus, uminus) \
+ F(UCompl, ucompl) \
+ F(UComplInt, ucomplInt) \
+ F(Increment, increment) \
+ F(Decrement, decrement) \
F(Binop, binop) \
+ F(Add, add) \
+ F(BitAnd, bitAnd) \
+ F(BitOr, bitOr) \
+ F(BitXor, bitXor) \
+ F(BitAndConst, bitAndConst) \
+ F(BitOrConst, bitOrConst) \
+ F(BitXorConst, bitXorConst) \
+ F(Mul, mul) \
+ F(Sub, sub) \
F(BinopContext, binopContext) \
F(AddNumberParams, addNumberParams) \
F(MulNumberParams, mulNumberParams) \
F(SubNumberParams, subNumberParams) \
- F(LoadThis, loadThis)
+ F(LoadThis, loadThis) \
+ F(LoadQmlIdArray, loadQmlIdArray) \
+ F(LoadQmlImportedScripts, loadQmlImportedScripts) \
+ F(LoadQmlContextObject, loadQmlContextObject) \
+ F(LoadQmlScopeObject, loadQmlScopeObject) \
+ F(LoadQmlSingleton, loadQmlSingleton)
#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
# define MOTH_THREADED_INTERPRETER
@@ -123,38 +154,35 @@ namespace QQmlJS {
namespace Moth {
struct Param {
- enum {
- ValueType = 0,
- ArgumentType = 1,
- LocalType = 2,
- TempType = 3,
- ScopedLocalType = 4
- };
- QV4::Primitive value;
- unsigned type : 3;
- unsigned scope : 29;
+ // Params are looked up as follows:
+ // Constant: 0
+ // Temp: 1
+ // Argument: 2
+ // Local: 3
+ // Arg(outer): 4
+ // Local(outer): 5
+ // ...
+ unsigned scope;
unsigned index;
- bool isValue() const { return type == ValueType; }
- bool isArgument() const { return type == ArgumentType; }
- bool isLocal() const { return type == LocalType; }
- bool isTemp() const { return type == TempType; }
- bool isScopedLocal() const { return type == ScopedLocalType; }
+ bool isConstant() const { return !scope; }
+ bool isArgument() const { return scope >= 2 && !(scope &1); }
+ bool isLocal() const { return scope == 3; }
+ bool isTemp() const { return scope == 1; }
+ bool isScopedLocal() const { return scope >= 3 && (scope & 1); }
- static Param createValue(const QV4::Primitive &v)
+ static Param createConstant(int index)
{
Param p;
- p.type = ValueType;
p.scope = 0;
- p.value = v;
+ p.index = index;
return p;
}
static Param createArgument(unsigned idx, uint scope)
{
Param p;
- p.type = ArgumentType;
- p.scope = scope;
+ p.scope = 2 + 2*scope;
p.index = idx;
return p;
}
@@ -162,8 +190,7 @@ struct Param {
static Param createLocal(unsigned idx)
{
Param p;
- p.type = LocalType;
- p.scope = 0;
+ p.scope = 3;
p.index = idx;
return p;
}
@@ -171,8 +198,7 @@ struct Param {
static Param createTemp(unsigned idx)
{
Param p;
- p.type = TempType;
- p.scope = 0;
+ p.scope = 1;
p.index = idx;
return p;
}
@@ -180,14 +206,13 @@ struct Param {
static Param createScopedLocal(unsigned idx, uint scope)
{
Param p;
- p.type = ScopedLocalType;
- p.scope = scope;
+ p.scope = 3 + 2*scope;
p.index = idx;
return p;
}
inline bool operator==(const Param &other) const
- { return type == other.type && scope == other.scope && index == other.index; }
+ { return scope == other.scope && index == other.index; }
inline bool operator!=(const Param &other) const
{ return !(*this == other); }
@@ -206,11 +231,6 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
- struct instr_loadValue {
- MOTH_INSTR_HEADER
- Param value;
- Param result;
- };
struct instr_loadRuntimeString {
MOTH_INSTR_HEADER
int stringId;
@@ -221,7 +241,7 @@ union Instr
int regExpId;
Param result;
};
- struct instr_moveTemp {
+ struct instr_move {
MOTH_INSTR_HEADER
Param source;
Param result;
@@ -241,6 +261,11 @@ union Instr
int name;
Param result;
};
+ struct instr_getGlobalLookup {
+ MOTH_INSTR_HEADER
+ int index;
+ Param result;
+ };
struct instr_storeName {
MOTH_INSTR_HEADER
int name;
@@ -252,12 +277,37 @@ union Instr
Param base;
Param result;
};
+ struct instr_getLookup {
+ MOTH_INSTR_HEADER
+ int index;
+ Param base;
+ Param result;
+ };
+ struct instr_loadQObjectProperty {
+ MOTH_INSTR_HEADER
+ int propertyIndex;
+ Param base;
+ Param result;
+ bool captureRequired;
+ };
struct instr_storeProperty {
MOTH_INSTR_HEADER
int name;
Param base;
Param source;
};
+ struct instr_setLookup {
+ MOTH_INSTR_HEADER
+ int index;
+ Param base;
+ Param source;
+ };
+ struct instr_storeQObjectProperty {
+ MOTH_INSTR_HEADER
+ Param base;
+ int propertyIndex;
+ Param source;
+ };
struct instr_loadElement {
MOTH_INSTR_HEADER
Param base;
@@ -274,13 +324,6 @@ union Instr
MOTH_INSTR_HEADER
quint32 value;
};
- struct instr_enterTry {
- MOTH_INSTR_HEADER
- ptrdiff_t tryOffset;
- ptrdiff_t catchOffset;
- int exceptionVarName;
- Param exceptionVar;
- };
struct instr_callValue {
MOTH_INSTR_HEADER
quint32 argc;
@@ -296,6 +339,14 @@ union Instr
Param base;
Param result;
};
+ struct instr_callPropertyLookup {
+ MOTH_INSTR_HEADER
+ int lookupIndex;
+ quint32 argc;
+ quint32 callData;
+ Param base;
+ Param result;
+ };
struct instr_callElement {
MOTH_INSTR_HEADER
Param base;
@@ -311,12 +362,28 @@ union Instr
quint32 callData;
Param result;
};
+ struct instr_callGlobalLookup {
+ MOTH_INSTR_HEADER
+ int index;
+ quint32 argc;
+ quint32 callData;
+ Param result;
+ };
+ struct instr_setExceptionHandler {
+ MOTH_INSTR_HEADER
+ qptrdiff offset;
+ };
struct instr_callBuiltinThrow {
MOTH_INSTR_HEADER
Param arg;
};
- struct instr_callBuiltinFinishTry {
+ struct instr_callBuiltinUnwindException {
MOTH_INSTR_HEADER
+ Param result;
+ };
+ struct instr_callBuiltinPushCatchScope {
+ MOTH_INSTR_HEADER
+ int name;
};
struct instr_callBuiltinPushScope {
MOTH_INSTR_HEADER
@@ -408,6 +475,9 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+ struct instr_callBuiltinConvertThisToObject {
+ MOTH_INSTR_HEADER
+ };
struct instr_createValue {
MOTH_INSTR_HEADER
quint32 argc;
@@ -423,6 +493,14 @@ union Instr
Param base;
Param result;
};
+ struct instr_constructPropertyLookup {
+ MOTH_INSTR_HEADER
+ int index;
+ quint32 argc;
+ quint32 callData;
+ Param base;
+ Param result;
+ };
struct instr_createActivationProperty {
MOTH_INSTR_HEADER
int name;
@@ -430,6 +508,13 @@ union Instr
quint32 callData;
Param result;
};
+ struct instr_constructGlobalLookup {
+ MOTH_INSTR_HEADER
+ int index;
+ quint32 argc;
+ quint32 callData;
+ Param result;
+ };
struct instr_jump {
MOTH_INSTR_HEADER
ptrdiff_t offset;
@@ -440,9 +525,43 @@ union Instr
Param condition;
bool invert;
};
- struct instr_unop {
+ struct instr_unot {
+ MOTH_INSTR_HEADER
+ Param source;
+ Param result;
+ };
+ struct instr_unotBool {
+ MOTH_INSTR_HEADER
+ Param source;
+ Param result;
+ };
+ struct instr_uplus {
+ MOTH_INSTR_HEADER
+ Param source;
+ Param result;
+ };
+ struct instr_uminus {
+ MOTH_INSTR_HEADER
+ Param source;
+ Param result;
+ };
+ struct instr_ucompl {
+ MOTH_INSTR_HEADER
+ Param source;
+ Param result;
+ };
+ struct instr_ucomplInt {
+ MOTH_INSTR_HEADER
+ Param source;
+ Param result;
+ };
+ struct instr_increment {
+ MOTH_INSTR_HEADER
+ Param source;
+ Param result;
+ };
+ struct instr_decrement {
MOTH_INSTR_HEADER
- QV4::UnaryOpName alu;
Param source;
Param result;
};
@@ -453,6 +572,60 @@ union Instr
Param rhs;
Param result;
};
+ struct instr_add {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_bitAnd {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_bitOr {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_bitXor {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_bitAndConst {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ int rhs;
+ Param result;
+ };
+ struct instr_bitOrConst {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ int rhs;
+ Param result;
+ };
+ struct instr_bitXorConst {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ int rhs;
+ Param result;
+ };
+ struct instr_mul {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_sub {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
struct instr_binopContext {
MOTH_INSTR_HEADER
QV4::BinOpContext alu;
@@ -482,29 +655,57 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+ struct instr_loadQmlIdArray {
+ MOTH_INSTR_HEADER
+ Param result;
+ };
+ struct instr_loadQmlImportedScripts {
+ MOTH_INSTR_HEADER
+ Param result;
+ };
+ struct instr_loadQmlContextObject {
+ MOTH_INSTR_HEADER
+ Param result;
+ };
+ struct instr_loadQmlScopeObject {
+ MOTH_INSTR_HEADER
+ Param result;
+ };
+ struct instr_loadQmlSingleton {
+ MOTH_INSTR_HEADER
+ Param result;
+ int name;
+ };
instr_common common;
instr_ret ret;
- instr_loadValue loadValue;
instr_loadRuntimeString loadRuntimeString;
instr_loadRegExp loadRegExp;
- instr_moveTemp moveTemp;
+ instr_move move;
instr_swapTemps swapTemps;
instr_loadClosure loadClosure;
instr_loadName loadName;
+ instr_getGlobalLookup getGlobalLookup;
instr_storeName storeName;
instr_loadElement loadElement;
instr_storeElement storeElement;
instr_loadProperty loadProperty;
+ instr_getLookup getLookup;
+ instr_loadQObjectProperty loadQObjectProperty;
instr_storeProperty storeProperty;
+ instr_setLookup setLookup;
+ instr_storeQObjectProperty storeQObjectProperty;
instr_push push;
- instr_enterTry enterTry;
instr_callValue callValue;
instr_callProperty callProperty;
+ instr_callPropertyLookup callPropertyLookup;
instr_callElement callElement;
instr_callActivationProperty callActivationProperty;
+ instr_callGlobalLookup callGlobalLookup;
instr_callBuiltinThrow callBuiltinThrow;
- instr_callBuiltinFinishTry callBuiltinFinishTry;
+ instr_setExceptionHandler setExceptionHandler;
+ instr_callBuiltinUnwindException callBuiltinUnwindException;
+ instr_callBuiltinPushCatchScope callBuiltinPushCatchScope;
instr_callBuiltinPushScope callBuiltinPushScope;
instr_callBuiltinPopScope callBuiltinPopScope;
instr_callBuiltinForeachIteratorObject callBuiltinForeachIteratorObject;
@@ -522,18 +723,42 @@ union Instr
instr_callBuiltinDefineArray callBuiltinDefineArray;
instr_callBuiltinDefineObjectLiteral callBuiltinDefineObjectLiteral;
instr_callBuiltinSetupArgumentsObject callBuiltinSetupArgumentsObject;
+ instr_callBuiltinConvertThisToObject callBuiltinConvertThisToObject;
instr_createValue createValue;
instr_createProperty createProperty;
+ instr_constructPropertyLookup constructPropertyLookup;
instr_createActivationProperty createActivationProperty;
+ instr_constructGlobalLookup constructGlobalLookup;
instr_jump jump;
instr_cjump cjump;
- instr_unop unop;
+ instr_unot unot;
+ instr_unotBool unotBool;
+ instr_uplus uplus;
+ instr_uminus uminus;
+ instr_ucompl ucompl;
+ instr_ucomplInt ucomplInt;
+ instr_increment increment;
+ instr_decrement decrement;
instr_binop binop;
+ instr_add add;
+ instr_bitAnd bitAnd;
+ instr_bitOr bitOr;
+ instr_bitXor bitXor;
+ instr_bitAndConst bitAndConst;
+ instr_bitOrConst bitOrConst;
+ instr_bitXorConst bitXorConst;
+ instr_mul mul;
+ instr_sub sub;
instr_binopContext binopContext;
instr_addNumberParams addNumberParams;
instr_mulNumberParams mulNumberParams;
instr_subNumberParams subNumberParams;
instr_loadThis loadThis;
+ instr_loadQmlIdArray loadQmlIdArray;
+ instr_loadQmlImportedScripts loadQmlImportedScripts;
+ instr_loadQmlContextObject loadQmlContextObject;
+ instr_loadQmlScopeObject loadQmlScopeObject;
+ instr_loadQmlSingleton loadQmlSingleton;
static int size(Type type);
};
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index d5e67d91c3..ed57852cd6 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -44,7 +44,6 @@
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
#include "qv4regexpobject_p.h"
-#include "qv4unwindhelper_p.h"
#include "qv4lookup_p.h"
#include "qv4function_p.h"
#include "qv4ssa_p.h"
@@ -70,7 +69,6 @@ CompilationUnit::~CompilationUnit()
{
foreach (Function *f, runtimeFunctions)
engine->allFunctions.remove(reinterpret_cast<quintptr>(f->codePtr));
- UnwindHelper::deregisterFunctions(runtimeFunctions);
}
void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
@@ -86,8 +84,6 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
runtimeFunctions[i] = runtimeFunction;
}
- UnwindHelper::registerFunctions(runtimeFunctions);
-
foreach (Function *f, runtimeFunctions)
engine->allFunctions.insert(reinterpret_cast<quintptr>(f->codePtr), f);
}
@@ -103,73 +99,6 @@ QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int fu
}
namespace {
-class ConvertTemps: protected V4IR::StmtVisitor, protected V4IR::ExprVisitor
-{
- int _nextFreeStackSlot;
- QHash<V4IR::Temp, int> _stackSlotForTemp;
-
- void renumber(V4IR::Temp *t)
- {
- if (t->kind != V4IR::Temp::VirtualRegister)
- return;
-
- int stackSlot = _stackSlotForTemp.value(*t, -1);
- if (stackSlot == -1) {
- stackSlot = _nextFreeStackSlot++;
- _stackSlotForTemp[*t] = stackSlot;
- }
-
- t->kind = V4IR::Temp::StackSlot;
- t->index = stackSlot;
- }
-
-public:
- ConvertTemps()
- : _nextFreeStackSlot(0)
- {}
-
- void toStackSlots(V4IR::Function *function)
- {
- _stackSlotForTemp.reserve(function->tempCount);
-
- foreach (V4IR::BasicBlock *bb, function->basicBlocks)
- foreach (V4IR::Stmt *s, bb->statements)
- s->accept(this);
-
- function->tempCount = _nextFreeStackSlot;
- }
-
-protected:
- virtual void visitConst(V4IR::Const *) {}
- virtual void visitString(V4IR::String *) {}
- virtual void visitRegExp(V4IR::RegExp *) {}
- virtual void visitName(V4IR::Name *) {}
- virtual void visitTemp(V4IR::Temp *e) { renumber(e); }
- virtual void visitClosure(V4IR::Closure *) {}
- virtual void visitConvert(V4IR::Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(V4IR::Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(V4IR::Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitCall(V4IR::Call *e) {
- e->base->accept(this);
- for (V4IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitNew(V4IR::New *e) {
- e->base->accept(this);
- for (V4IR::ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitSubscript(V4IR::Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(V4IR::Member *e) { e->base->accept(this); }
- virtual void visitExp(V4IR::Exp *s) { s->expr->accept(this); }
- virtual void visitMove(V4IR::Move *s) { s->target->accept(this); s->source->accept(this); }
- virtual void visitJump(V4IR::Jump *) {}
- virtual void visitCJump(V4IR::CJump *s) { s->cond->accept(this); }
- virtual void visitRet(V4IR::Ret *s) { s->expr->accept(this); }
- virtual void visitTry(V4IR::Try *s) { s->exceptionVar->accept(this); }
- virtual void visitPhi(V4IR::Phi *) { Q_UNREACHABLE(); }
-};
-
inline bool isPregOrConst(V4IR::Expr *e)
{
if (V4IR::Temp *t = e->asTemp())
@@ -202,8 +131,6 @@ static const Assembler::RegisterID calleeSavedRegisters[] = {
#if CPU(ARM)
static const Assembler::RegisterID calleeSavedRegisters[] = {
// ### FIXME: remove unused registers.
- // Keep these in reverse order and make sure to also edit the unwind program in
- // qv4unwindhelper_arm_p.h when changing this list.
JSC::ARMRegisters::r12,
JSC::ARMRegisters::r10,
JSC::ARMRegisters::r9,
@@ -236,11 +163,14 @@ Assembler::Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::
void Assembler::registerBlock(V4IR::BasicBlock* block, V4IR::BasicBlock *nextBlock)
{
_addrs[block] = label();
+ catchBlock = block->catchBlock;
_nextBlock = nextBlock;
}
void Assembler::jumpToBlock(V4IR::BasicBlock* current, V4IR::BasicBlock *target)
{
+ Q_UNUSED(current);
+
if (target != _nextBlock)
_patches[target].append(jump());
}
@@ -314,7 +244,7 @@ Assembler::Pointer Assembler::loadTempAddress(RegisterID baseReg, V4IR::Temp *t)
switch (t->kind) {
case V4IR::Temp::Formal:
case V4IR::Temp::ScopedFormal: {
- loadPtr(Address(context, qOffsetOf(CallContext, callData)), baseReg);
+ loadPtr(Address(context, qOffsetOf(ExecutionContext, callData)), baseReg);
offset = sizeof(CallData) + (t->index - 1) * sizeof(SafeValue);
} break;
case V4IR::Temp::Local:
@@ -377,6 +307,8 @@ void Assembler::copyValue(Result result, V4IR::Expr* source)
storeDouble(toDoubleRegister(source), result);
} else if (V4IR::Temp *temp = source->asTemp()) {
#ifdef VALUE_FITS_IN_REGISTER
+ Q_UNUSED(temp);
+
// Use ReturnValueRegister as "scratch" register because loadArgument
// and storeArgument are functions that may need a scratch register themselves.
loadArgumentInRegister(source, ReturnValueRegister, 0);
@@ -507,23 +439,9 @@ static void printDisassembledOutputWithCalls(const char* output, const QHash<voi
}
#endif
-void Assembler::recordLineNumber(int lineNumber)
-{
- CodeLineNumerMapping mapping;
- mapping.location = label();
- mapping.lineNumber = lineNumber;
- codeLineNumberMappings << mapping;
-}
-
-
JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
{
Label endOfCode = label();
-#if defined(Q_PROCESSOR_ARM) && !defined(Q_OS_IOS)
- // Let the ARM exception table follow right after that
- for (int i = 0, nops = UnwindHelper::unwindInfoSize() / 2; i < nops; ++i)
- nop();
-#endif
{
QHashIterator<V4IR::BasicBlock *, QVector<Jump> > it(_patches);
@@ -540,14 +458,6 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
JSC::JSGlobalData dummy(_executableAllocator);
JSC::LinkBuffer linkBuffer(dummy, this, 0);
- QVector<uint> lineNumberMapping(codeLineNumberMappings.count() * 2);
-
- for (int i = 0; i < codeLineNumberMappings.count(); ++i) {
- lineNumberMapping[i * 2] = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
- lineNumberMapping[i * 2 + 1] = codeLineNumberMappings.at(i).lineNumber;
- }
- _isel->jsUnitGenerator()->registerLineNumberMapping(_function, lineNumberMapping);
-
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
linkBuffer.link(ctl.call, ctl.externalFunction);
@@ -557,6 +467,10 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
foreach (const DataLabelPatch &p, _dataLabelPatches)
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
+ // link exception handlers
+ foreach(Jump jump, exceptionPropagationJumps)
+ linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel));
+
{
QHashIterator<V4IR::BasicBlock *, QVector<DataLabelPtr> > it(_labelPatches);
while (it.hasNext()) {
@@ -571,9 +485,6 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
_constTable.finalize(linkBuffer, _isel);
*codeSize = linkBuffer.offsetOf(endOfCode);
-#if defined(Q_PROCESSOR_ARM) && !defined(Q_OS_IOS)
- UnwindHelper::writeARMUnwindInfo(linkBuffer.debugAddress(), *codeSize);
-#endif
JSC::MacroAssemblerCodeRef codeRef;
@@ -628,11 +539,11 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
return codeRef;
}
-InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, Compiler::JSUnitGenerator *jsGenerator)
+InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, Compiler::JSUnitGenerator *jsGenerator)
: EvalInstructionSelection(execAllocator, module, jsGenerator)
, _block(0)
- , _function(0)
, _as(0)
+ , qmlEngine(qmlEngine)
{
compilationUnit = new CompilationUnit;
compilationUnit->codeRefs.resize(module->functions.size());
@@ -648,12 +559,10 @@ void InstructionSelection::run(int functionIndex)
{
V4IR::Function *function = irModule->functions[functionIndex];
QVector<Lookup> lookups;
- QSet<V4IR::BasicBlock*> reentryBlocks;
qSwap(_function, function);
- qSwap(_reentryBlocks, reentryBlocks);
V4IR::Optimizer opt(_function);
- opt.run();
+ opt.run(qmlEngine);
#if (CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX))) || (CPU(X86) && OS(LINUX))
static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty();
@@ -709,34 +618,31 @@ void InstructionSelection::run(int functionIndex)
_as->addPtr(Assembler::TrustedImm32(sizeof(QV4::SafeValue)*locals), Assembler::LocalsRegister);
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
+ int lastLine = -1;
for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
V4IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
_block = _function->basicBlocks[i];
_as->registerBlock(_block, nextBlock);
- if (_reentryBlocks.contains(_block)) {
- _as->enterStandardStackFrame();
-#ifdef ARGUMENTS_IN_REGISTERS
- _as->move(Assembler::registerForArgument(0), Assembler::ContextRegister);
- _as->move(Assembler::registerForArgument(1), Assembler::LocalsRegister);
-#else
- _as->loadPtr(addressForArgument(0), Assembler::ContextRegister);
- _as->loadPtr(addressForArgument(1), Assembler::LocalsRegister);
-#endif
- }
-
foreach (V4IR::Stmt *s, _block->statements) {
- if (s->location.isValid())
- _as->recordLineNumber(s->location.startLine);
+ if (s->location.isValid()) {
+ if (int(s->location.startLine) != lastLine) {
+ Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lineNumber));
+ _as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr);
+ lastLine = s->location.startLine;
+ }
+ }
s->accept(this);
}
}
+ if (!_as->exceptionReturnLabel.isSet())
+ visitRet(0);
+
JSC::MacroAssemblerCodeRef codeRef =_as->link(&compilationUnit->codeSizes[functionIndex]);
compilationUnit->codeRefs[functionIndex] = codeRef;
qSwap(_function, function);
- qSwap(_reentryBlocks, reentryBlocks);
delete _as;
_as = oldAssembler;
qSwap(_removableJumps, removableJumps);
@@ -759,7 +665,7 @@ QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
{
- int argc = prepareCallData(args, 0);
+ prepareCallData(args, 0);
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
@@ -828,64 +734,25 @@ void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
void InstructionSelection::callBuiltinThrow(V4IR::Expr *arg)
{
- generateFunctionCall(Assembler::Void, __qmljs_throw, Assembler::ContextRegister,
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_throw, Assembler::ContextRegister,
Assembler::PointerToValue(arg));
}
-typedef void *(*MiddleOfFunctionEntryPoint(ExecutionContext *, void *localsPtr));
-static void *tryWrapper(ExecutionContext *context, void *localsPtr, MiddleOfFunctionEntryPoint tryBody, MiddleOfFunctionEntryPoint catchBody,
- QV4::StringRef exceptionVarName, ValueRef exceptionVar)
-{
- exceptionVar = Primitive::undefinedValue();
- void *addressToContinueAt = 0;
- SafeValue *jsStackTop = context->engine->jsStackTop;
- bool caughtException = false;
- try {
- addressToContinueAt = tryBody(context, localsPtr);
- } catch (...) {
- context->engine->jsStackTop = jsStackTop;
- exceptionVar = context->catchException();
- caughtException = true;
- }
- // Can't nest try { ... } catch (...) {} due to inability of nesting foreign exceptions
- // with common CXX ABI.
- if (caughtException) {
- try {
- ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, exceptionVar, context);
- addressToContinueAt = catchBody(catchContext, localsPtr);
- context = __qmljs_builtin_pop_scope(catchContext);
- } catch (...) {
- context->engine->jsStackTop = jsStackTop;
- exceptionVar = context->catchException();
- addressToContinueAt = catchBody(context, localsPtr);
- }
- }
- return addressToContinueAt;
+void InstructionSelection::callBuiltinReThrow()
+{
+ _as->jumpToExceptionHandler();
}
-void InstructionSelection::visitTry(V4IR::Try *t)
+void InstructionSelection::callBuiltinUnwindException(V4IR::Temp *result)
{
- // Call tryWrapper, which is going to re-enter the same function at the address of the try block. At then end
- // of the try function the JIT code will return with the address of the sub-sequent instruction, which tryWrapper
- // returns and to which we jump to.
-
- _reentryBlocks.insert(t->tryBlock);
- _reentryBlocks.insert(t->catchBlock);
+ generateFunctionCall(result, __qmljs_builtin_unwind_exception, Assembler::ContextRegister);
- generateFunctionCall(Assembler::ReturnValueRegister, tryWrapper, Assembler::ContextRegister, Assembler::LocalsRegister,
- Assembler::ReentryBlock(t->tryBlock), Assembler::ReentryBlock(t->catchBlock),
- Assembler::PointerToString(*t->exceptionVarName), Assembler::PointerToValue(t->exceptionVar));
- _as->jump(Assembler::ReturnValueRegister);
}
-void InstructionSelection::callBuiltinFinishTry()
+void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
{
- // This assumes that we're in code that was called by tryWrapper, so we return to try wrapper
- // with the address that we'd like to continue at, which is right after the ret below.
- Assembler::DataLabelPtr continuation = _as->moveWithPatch(Assembler::TrustedImmPtr(0), Assembler::ReturnValueRegister);
- _as->leaveStandardStackFrame();
- _as->ret();
- _as->addPatch(continuation, _as->label());
+ Assembler::Pointer s = _as->loadStringAddress(Assembler::ScratchRegister, exceptionName);
+ generateFunctionCall(Assembler::ContextRegister, __qmljs_builtin_push_catch_scope, Assembler::ContextRegister, s);
}
void InstructionSelection::callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result)
@@ -986,11 +853,16 @@ void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result)
generateFunctionCall(result, __qmljs_builtin_setup_arguments_object, Assembler::ContextRegister);
}
+void InstructionSelection::callBuiltinConvertThisToObject()
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_convert_this_to_object, Assembler::ContextRegister);
+}
+
void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
{
Q_ASSERT(value);
- int argc = prepareCallData(args, 0);
+ prepareCallData(args, 0);
generateFunctionCall(result, __qmljs_call_value, Assembler::ContextRegister,
Assembler::Reference(value),
baseAddressForCallData());
@@ -998,7 +870,7 @@ void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4
void InstructionSelection::loadThisObject(V4IR::Temp *temp)
{
- _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(CallContext, callData)), Assembler::ScratchRegister);
+ _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, callData)), Assembler::ScratchRegister);
#if defined(VALUE_FITS_IN_REGISTER)
_as->load64(Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)),
Assembler::ReturnValueRegister);
@@ -1008,6 +880,31 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
#endif
}
+void InstructionSelection::loadQmlIdArray(V4IR::Temp *temp)
+{
+ generateFunctionCall(temp, __qmljs_get_id_array, Assembler::ContextRegister);
+}
+
+void InstructionSelection::loadQmlImportedScripts(V4IR::Temp *temp)
+{
+ generateFunctionCall(temp, __qmljs_get_imported_scripts, Assembler::ContextRegister);
+}
+
+void InstructionSelection::loadQmlContextObject(V4IR::Temp *temp)
+{
+ generateFunctionCall(temp, __qmljs_get_context_object, Assembler::ContextRegister);
+}
+
+void InstructionSelection::loadQmlScopeObject(V4IR::Temp *temp)
+{
+ generateFunctionCall(temp, __qmljs_get_scope_object, Assembler::ContextRegister);
+}
+
+void InstructionSelection::loadQmlSingleton(const QString &name, V4IR::Temp *temp)
+{
+ generateFunctionCall(temp, __qmljs_get_qml_singleton, Assembler::ContextRegister, Assembler::PointerToString(name));
+}
+
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
if (targetTemp->kind == V4IR::Temp::PhysicalRegister) {
@@ -1086,6 +983,12 @@ void InstructionSelection::getProperty(V4IR::Expr *base, const QString &name, V4
}
}
+void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target)
+{
+ generateFunctionCall(target, __qmljs_get_qobject_property, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
+ Assembler::TrustedImm32(captureRequired));
+}
+
void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBase,
const QString &targetName)
{
@@ -1101,6 +1004,12 @@ void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBas
}
}
+void InstructionSelection::setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_set_qobject_property, Assembler::ContextRegister, Assembler::PointerToValue(targetBase),
+ Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+}
+
void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
#if QT_POINTER_SIZE == 8
@@ -1119,13 +1028,16 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR:
_as->and32(Assembler::TrustedImm32(QV4::Managed::SimpleArray), Assembler::ReturnValueRegister);
Assembler::Jump notSimple = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0));
- Assembler::Jump fallback;
+ bool needNegativeCheck = false;
+ Assembler::Jump fallback, fallback2;
if (tindex->kind == V4IR::Temp::PhysicalRegister) {
if (tindex->type == V4IR::SInt32Type) {
+ fallback = _as->branch32(Assembler::LessThan, (Assembler::RegisterID)tindex->index, Assembler::TrustedImm32(0));
_as->move((Assembler::RegisterID) tindex->index, Assembler::ScratchRegister);
+ needNegativeCheck = true;
} else {
// double, convert and check if it's a int
- _as->truncateDoubleToUint32((Assembler::FPRegisterID) tindex->index, Assembler::ScratchRegister);
+ fallback2 = _as->branchTruncateDoubleToUint32((Assembler::FPRegisterID) tindex->index, Assembler::ScratchRegister);
_as->convertInt32ToDouble(Assembler::ScratchRegister, Assembler::FPGpr0);
fallback = _as->branchDouble(Assembler::DoubleNotEqual, Assembler::FPGpr0, (Assembler::FPRegisterID) tindex->index);
}
@@ -1142,19 +1054,23 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR:
_as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ReturnValueRegister);
_as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
_as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0);
- _as->truncateDoubleToUint32(Assembler::FPGpr0, Assembler::ScratchRegister);
+ fallback2 = _as->branchTruncateDoubleToUint32(Assembler::FPGpr0, Assembler::ScratchRegister);
_as->convertInt32ToDouble(Assembler::ScratchRegister, Assembler::FPGpr1);
fallback = _as->branchDouble(Assembler::DoubleNotEqualOrUnordered, Assembler::FPGpr0, Assembler::FPGpr1);
isInteger.link(_as);
_as->or32(Assembler::TrustedImm32(0), Assembler::ScratchRegister);
+ needNegativeCheck = true;
}
// get data, ScratchRegister holds index
addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase);
_as->load64(addr, Assembler::ReturnValueRegister);
Address arrayDataLen(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayDataLen));
- Assembler::Jump outOfRange = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, arrayDataLen);
+ Assembler::Jump outOfRange;
+ if (needNegativeCheck)
+ outOfRange = _as->branch32(Assembler::LessThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0));
+ Assembler::Jump outOfRange2 = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, arrayDataLen);
Address arrayData(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData));
_as->load64(arrayData, Assembler::ReturnValueRegister);
Q_ASSERT(sizeof(Property) == (1<<4));
@@ -1172,9 +1088,13 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR:
Assembler::Jump done = _as->jump();
emptyValue.link(_as);
- outOfRange.link(_as);
+ if (outOfRange.isSet())
+ outOfRange.link(_as);
+ outOfRange2.link(_as);
if (fallback.isSet())
fallback.link(_as);
+ if (fallback2.isSet())
+ fallback2.link(_as);
notSimple.link(_as);
notManaged.link(_as);
@@ -1373,7 +1293,7 @@ void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::
}
}
-static inline Assembler::FPRegisterID getFreeFPReg(V4IR::Expr *shouldNotOverlap, int hint)
+static inline Assembler::FPRegisterID getFreeFPReg(V4IR::Expr *shouldNotOverlap, unsigned hint)
{
if (V4IR::Temp *t = shouldNotOverlap->asTemp())
if (t->type == V4IR::DoubleType)
@@ -1465,7 +1385,7 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp
void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target)
{
- if (oper != V4IR:: OpMod
+ if (oper != V4IR::OpMod
&& leftSource->type == V4IR::DoubleType && rightSource->type == V4IR::DoubleType
&& isPregOrConst(leftSource) && isPregOrConst(rightSource)) {
doubleBinop(oper, leftSource, rightSource, target);
@@ -1481,7 +1401,14 @@ void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR:
done = genInlineBinop(oper, leftSource, rightSource, target);
// TODO: inline var===null and var!==null
- const Assembler::BinaryOperationInfo& info = Assembler::binaryOperation(oper);
+ Assembler::BinaryOperationInfo info = Assembler::binaryOperation(oper);
+
+ if (oper == V4IR::OpAdd &&
+ (leftSource->type == V4IR::StringType || rightSource->type == V4IR::StringType)) {
+ const Assembler::BinaryOperationInfo stringAdd = OPCONTEXT(__qmljs_add_string);
+ info = stringAdd;
+ }
+
if (info.fallbackImplementation) {
_as->generateFunctionCallImp(target, info.name, info.fallbackImplementation,
Assembler::PointerToValue(leftSource),
@@ -1504,7 +1431,7 @@ void InstructionSelection::callProperty(V4IR::Expr *base, const QString &name, V
{
assert(base != 0);
- int argc = prepareCallData(args, base);
+ prepareCallData(args, base);
if (useFastLookups) {
uint index = registerGetterLookup(name);
@@ -1525,7 +1452,7 @@ void InstructionSelection::callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4
{
assert(base != 0);
- int argc = prepareCallData(args, base);
+ prepareCallData(args, base);
generateFunctionCall(result, __qmljs_call_element, Assembler::ContextRegister,
Assembler::PointerToValue(index),
baseAddressForCallData());
@@ -1829,7 +1756,7 @@ void InstructionSelection::convertTypeToUInt32(V4IR::Temp *source, V4IR::Temp *t
void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
{
assert(func != 0);
- int argc = prepareCallData(args, 0);
+ prepareCallData(args, 0);
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
@@ -1848,9 +1775,18 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::E
void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
{
- int argc = prepareCallData(args, 0);
+ prepareCallData(args, base);
+ if (useFastLookups) {
+ uint index = registerGetterLookup(name);
+ generateFunctionCall(result, __qmljs_construct_property_lookup,
+ Assembler::ContextRegister,
+ Assembler::TrustedImm32(index),
+ baseAddressForCallData());
+ return;
+ }
+
generateFunctionCall(result, __qmljs_construct_property, Assembler::ContextRegister,
- Assembler::Reference(base), Assembler::PointerToString(name),
+ Assembler::PointerToString(name),
baseAddressForCallData());
}
@@ -1858,7 +1794,7 @@ void InstructionSelection::constructValue(V4IR::Temp *value, V4IR::ExprList *arg
{
assert(value != 0);
- int argc = prepareCallData(args, 0);
+ prepareCallData(args, 0);
generateFunctionCall(result, __qmljs_construct_value,
Assembler::ContextRegister,
Assembler::Reference(value),
@@ -1917,6 +1853,10 @@ void InstructionSelection::visitCJump(V4IR::CJump *s)
visitCJumpStrict(b, s->iftrue, s->iffalse);
return;
}
+ if (b->op == V4IR::OpEqual || b->op == V4IR::OpNotEqual) {
+ visitCJumpEqual(b, s->iftrue, s->iffalse);
+ return;
+ }
CmpOp op = 0;
CmpOpContext opContext = 0;
@@ -1958,7 +1898,10 @@ void InstructionSelection::visitCJump(V4IR::CJump *s)
void InstructionSelection::visitRet(V4IR::Ret *s)
{
- if (V4IR::Temp *t = s->expr->asTemp()) {
+ if (!s) {
+ // this only happens if the method doesn't have a return statement and can
+ // only exit through an exception
+ } else if (V4IR::Temp *t = s->expr->asTemp()) {
#if CPU(X86) || CPU(ARM)
# if CPU(X86)
@@ -2052,6 +1995,8 @@ void InstructionSelection::visitRet(V4IR::Ret *s)
Q_UNUSED(s);
}
+ _as->exceptionReturnLabel = _as->label();
+
const int locals = _as->stackLayout().calculateJSStackFrameSize();
_as->subPtr(Assembler::TrustedImm32(sizeof(QV4::SafeValue)*locals), Assembler::LocalsRegister);
_as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, engine)), Assembler::ScratchRegister);
@@ -2341,6 +2286,8 @@ bool InstructionSelection::visitCJumpDouble(V4IR::AluOp op, V4IR::Expr *left, V4
void InstructionSelection::visitCJumpStrict(V4IR::Binop *binop, V4IR::BasicBlock *trueBlock,
V4IR::BasicBlock *falseBlock)
{
+ Q_ASSERT(binop->op == V4IR::OpStrictEqual || binop->op == V4IR::OpStrictNotEqual);
+
if (visitCJumpStrictNullUndefined(V4IR::NullType, binop, trueBlock, falseBlock))
return;
if (visitCJumpStrictNullUndefined(V4IR::UndefinedType, binop, trueBlock, falseBlock))
@@ -2348,22 +2295,14 @@ void InstructionSelection::visitCJumpStrict(V4IR::Binop *binop, V4IR::BasicBlock
if (visitCJumpStrictBool(binop, trueBlock, falseBlock))
return;
- QV4::BinOp op;
- const char *opName;
- if (binop->op == V4IR::OpStrictEqual) {
- op = __qmljs_se;
- opName = "__qmljs_se";
- } else {
- op = __qmljs_sne;
- opName = "__qmljs_sne";
- }
-
V4IR::Expr *left = binop->left;
V4IR::Expr *right = binop->right;
- _as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, op,
+ _as->generateFunctionCallImp(Assembler::ReturnValueRegister, "__qmljs_cmp_se", __qmljs_cmp_se,
Assembler::PointerToValue(left), Assembler::PointerToValue(right));
- _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, trueBlock, falseBlock);
+ _as->generateCJumpOnCompare(binop->op == V4IR::OpStrictEqual ? Assembler::NotEqual : Assembler::Equal,
+ Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
+ _block, trueBlock, falseBlock);
}
// Only load the non-null temp.
@@ -2465,6 +2404,72 @@ bool InstructionSelection::visitCJumpStrictBool(V4IR::Binop *binop, V4IR::BasicB
return true;
}
+bool InstructionSelection::visitCJumpNullUndefined(V4IR::Type nullOrUndef, V4IR::Binop *binop,
+ V4IR::BasicBlock *trueBlock,
+ V4IR::BasicBlock *falseBlock)
+{
+ Q_ASSERT(nullOrUndef == V4IR::NullType || nullOrUndef == V4IR::UndefinedType);
+
+ V4IR::Expr *varSrc = 0;
+ if (binop->left->type == V4IR::VarType && binop->right->type == nullOrUndef)
+ varSrc = binop->left;
+ else if (binop->left->type == nullOrUndef && binop->right->type == V4IR::VarType)
+ varSrc = binop->right;
+ if (!varSrc)
+ return false;
+
+ if (varSrc->asTemp() && varSrc->asTemp()->kind == V4IR::Temp::PhysicalRegister) {
+ _as->jumpToBlock(_block, falseBlock);
+ return true;
+ }
+
+ if (V4IR::Const *c = varSrc->asConst()) {
+ if (c->type == nullOrUndef)
+ _as->jumpToBlock(_block, trueBlock);
+ else
+ _as->jumpToBlock(_block, falseBlock);
+ return true;
+ }
+
+ V4IR::Temp *t = varSrc->asTemp();
+ Q_ASSERT(t);
+
+ Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, t);
+ tagAddr.offset += 4;
+ const Assembler::RegisterID tagReg = Assembler::ScratchRegister;
+ _as->load32(tagAddr, tagReg);
+
+ if (binop->op == V4IR::OpNotEqual)
+ qSwap(trueBlock, falseBlock);
+ Assembler::Jump isNull = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::_Null_Type)));
+ Assembler::Jump isUndefined = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Undefined_Type)));
+ _as->addPatch(trueBlock, isNull);
+ _as->addPatch(trueBlock, isUndefined);
+ _as->jumpToBlock(_block, falseBlock);
+
+ return true;
+}
+
+
+void InstructionSelection::visitCJumpEqual(V4IR::Binop *binop, V4IR::BasicBlock *trueBlock,
+ V4IR::BasicBlock *falseBlock)
+{
+ Q_ASSERT(binop->op == V4IR::OpEqual || binop->op == V4IR::OpNotEqual);
+
+ if (visitCJumpNullUndefined(V4IR::NullType, binop, trueBlock, falseBlock))
+ return;
+
+ V4IR::Expr *left = binop->left;
+ V4IR::Expr *right = binop->right;
+
+ _as->generateFunctionCallImp(Assembler::ReturnValueRegister, "__qmljs_cmp_eq", __qmljs_cmp_eq,
+ Assembler::PointerToValue(left), Assembler::PointerToValue(right));
+ _as->generateCJumpOnCompare(binop->op == V4IR::OpEqual ? Assembler::NotEqual : Assembler::Equal,
+ Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
+ _block, trueBlock, falseBlock);
+}
+
+
bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
V4IR::Expr *rightSource, V4IR::Temp *target)
{
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index bd4c564ab9..4b0d19df07 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -49,6 +49,7 @@
#include "private/qv4lookup_p.h"
#include <QtCore/QHash>
+#include <QtCore/QStack>
#include <config.h>
#include <wtf/Vector.h>
@@ -62,6 +63,7 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace MASM {
+
class InstructionSelection;
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
@@ -88,6 +90,37 @@ struct RelativeCall {
{}
};
+
+template <typename T>
+struct ExceptionCheck {
+ enum { NeedsCheck = 1 };
+};
+// push_catch and pop context methods shouldn't check for exceptions
+template <>
+struct ExceptionCheck<QV4::ExecutionContext *(*)(QV4::ExecutionContext *)> {
+ enum { NeedsCheck = 0 };
+};
+template <typename A>
+struct ExceptionCheck<QV4::ExecutionContext *(*)(QV4::ExecutionContext *, A)> {
+ enum { NeedsCheck = 0 };
+};
+template <>
+struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowContext *)> {
+ enum { NeedsCheck = 0 };
+};
+template <typename A>
+struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowContext *, A)> {
+ enum { NeedsCheck = 0 };
+};
+template <typename A, typename B>
+struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowContext *, A, B)> {
+ enum { NeedsCheck = 0 };
+};
+template <typename A, typename B, typename C>
+struct ExceptionCheck<void (*)(QV4::NoThrowContext *, A, B, C)> {
+ enum { NeedsCheck = 0 };
+};
+
class Assembler : public JSC::MacroAssembler
{
public:
@@ -433,25 +466,7 @@ public:
V4IR::BasicBlock *block;
};
- void saveInstructionPointer(RegisterID freeScratchRegister) {
- Address ipAddr(ContextRegister, qOffsetOf(QV4::ExecutionContext, jitInstructionPointer));
- RegisterID sourceRegister = freeScratchRegister;
-
-#if CPU(X86_64) || CPU(X86)
- callToRetrieveIP();
- peek(sourceRegister);
- pop();
-#elif CPU(ARM)
- move(JSC::ARMRegisters::pc, sourceRegister);
-#else
-#error "Port me!"
-#endif
-
- storePtr(sourceRegister, ipAddr);
- }
-
void callAbsolute(const char* functionName, FunctionPtr function) {
- saveInstructionPointer(ScratchRegister);
CallToLink ctl;
ctl.call = call();
ctl.externalFunction = function;
@@ -460,13 +475,11 @@ public:
}
void callAbsolute(const char* /*functionName*/, Address addr) {
- saveInstructionPointer(ScratchRegister);
call(addr);
}
void callAbsolute(const char* /*functionName*/, const RelativeCall &relativeCall)
{
- saveInstructionPointer(ScratchRegister);
call(relativeCall.addr);
}
@@ -874,6 +887,23 @@ public:
void enterStandardStackFrame();
void leaveStandardStackFrame();
+ void checkException() {
+ loadPtr(Address(ContextRegister, qOffsetOf(QV4::ExecutionContext, engine)), ScratchRegister);
+ load32(Address(ScratchRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister);
+ Jump exceptionThrown = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
+ if (catchBlock)
+ addPatch(catchBlock, exceptionThrown);
+ else
+ exceptionPropagationJumps.append(exceptionThrown);
+ }
+ void jumpToExceptionHandler() {
+ Jump exceptionThrown = jump();
+ if (catchBlock)
+ addPatch(catchBlock, exceptionThrown);
+ else
+ exceptionPropagationJumps.append(exceptionThrown);
+ }
+
template <int argumentNumber, typename T>
void loadArgumentOnStackOrRegister(const T &value)
{
@@ -917,7 +947,6 @@ public:
enum { Size = 0 };
};
-
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
{
@@ -954,10 +983,15 @@ public:
callAbsolute(functionName, function);
- storeReturnValue(r);
-
if (stackSpaceNeeded)
add32(TrustedImm32(stackSpaceNeeded), StackPointerRegister);
+
+ if (ExceptionCheck<Callable>::NeedsCheck) {
+ checkException();
+ }
+
+ storeReturnValue(r);
+
}
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
@@ -1346,11 +1380,12 @@ public:
JSC::MacroAssemblerCodeRef link(int *codeSize);
- void recordLineNumber(int lineNumber);
-
const StackLayout stackLayout() const { return _stackLayout; }
ConstantTable &constantTable() { return _constTable; }
+ Label exceptionReturnLabel;
+ V4IR::BasicBlock * catchBlock;
+ QVector<Jump> exceptionPropagationJumps;
private:
const StackLayout _stackLayout;
ConstantTable _constTable;
@@ -1370,13 +1405,6 @@ private:
QV4::ExecutableAllocator *_executableAllocator;
InstructionSelection *_isel;
-
- struct CodeLineNumerMapping
- {
- Assembler::Label location;
- int lineNumber;
- };
- QVector<CodeLineNumerMapping> codeLineNumberMappings;
};
template <typename T> inline void prepareRelativeCall(const T &, Assembler *){}
@@ -1391,7 +1419,7 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
~InstructionSelection();
virtual void run(int functionIndex);
@@ -1410,7 +1438,9 @@ protected:
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinDeleteValue(V4IR::Temp *result);
virtual void callBuiltinThrow(V4IR::Expr *arg);
- virtual void callBuiltinFinishTry();
+ virtual void callBuiltinReThrow();
+ virtual void callBuiltinUnwindException(V4IR::Temp *);
+ virtual void callBuiltinPushCatchScope(const QString &exceptionName);
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinPushWithScope(V4IR::Temp *arg);
@@ -1421,11 +1451,17 @@ protected:
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result);
+ virtual void callBuiltinConvertThisToObject();
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result);
virtual void convertType(V4IR::Temp *source, V4IR::Temp *target);
virtual void loadThisObject(V4IR::Temp *temp);
+ virtual void loadQmlIdArray(V4IR::Temp *temp);
+ virtual void loadQmlImportedScripts(V4IR::Temp *temp);
+ virtual void loadQmlContextObject(V4IR::Temp *temp);
+ virtual void loadQmlScopeObject(V4IR::Temp *temp);
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp);
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
@@ -1434,6 +1470,8 @@ protected:
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target);
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName);
+ virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex);
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target);
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target);
virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex);
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
@@ -1469,7 +1507,6 @@ protected:
virtual void visitJump(V4IR::Jump *);
virtual void visitCJump(V4IR::CJump *);
virtual void visitRet(V4IR::Ret *);
- virtual void visitTry(V4IR::Try *);
Assembler::Jump genTryDoubleConversion(V4IR::Expr *src, Assembler::FPRegisterID dest);
Assembler::Jump genInlineBinop(V4IR::AluOp oper, V4IR::Expr *leftSource,
@@ -1483,6 +1520,9 @@ protected:
bool visitCJumpStrictNullUndefined(V4IR::Type nullOrUndef, V4IR::Binop *binop,
V4IR::BasicBlock *trueBlock, V4IR::BasicBlock *falseBlock);
bool visitCJumpStrictBool(V4IR::Binop *binop, V4IR::BasicBlock *trueBlock, V4IR::BasicBlock *falseBlock);
+ bool visitCJumpNullUndefined(V4IR::Type nullOrUndef, V4IR::Binop *binop,
+ V4IR::BasicBlock *trueBlock, V4IR::BasicBlock *falseBlock);
+ void visitCJumpEqual(V4IR::Binop *binop, V4IR::BasicBlock *trueBlock, V4IR::BasicBlock *falseBlock);
bool int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource,
V4IR::Temp *target);
@@ -1586,20 +1626,19 @@ private:
}
V4IR::BasicBlock *_block;
- V4IR::Function* _function;
QSet<V4IR::Jump *> _removableJumps;
Assembler* _as;
- QSet<V4IR::BasicBlock*> _reentryBlocks;
CompilationUnit *compilationUnit;
+ QQmlEnginePrivate *qmlEngine;
};
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- { return new InstructionSelection(execAllocator, module, jsGenerator); }
+ virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+ { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
virtual bool jitCompileRegexps() const
{ return true; }
};
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index c610ca6f02..ee7e8ce2e8 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -134,85 +134,31 @@ inline bool isNumberType(V4IR::Expr *e)
}
}
-} // anonymous namespace
-
-// TODO: extend to optimize out temp-to-temp moves, where the lifetime of one temp ends at that statement.
-// To handle that, add a hint when such a move will occur, and add a stmt for the hint.
-// Then when asked for a register, check if the active statement is the terminating statement, and if so, apply the hint.
-// This generalises the hint usage for Phi removal too, when the phi is passed in there as the current statement.
-class QQmlJS::Moth::StackSlotAllocator
+inline bool isIntegerType(V4IR::Expr *e)
{
- QHash<V4IR::Temp, int> _slotForTemp;
- QHash<V4IR::Temp, int> _hints;
- QVector<int> _activeSlots;
-
- QHash<V4IR::Temp, V4IR::LifeTimeInterval> _intervals;
-
-public:
- StackSlotAllocator(const QVector<V4IR::LifeTimeInterval> &ranges, int maxTempCount)
- : _activeSlots(maxTempCount)
- {
- _intervals.reserve(ranges.size());
- foreach (const V4IR::LifeTimeInterval &r, ranges)
- _intervals[r.temp()] = r;
- }
-
- void addHint(const V4IR::Temp &hintedSlotOfTemp, const V4IR::Temp &newTemp)
- {
- if (hintedSlotOfTemp.kind != V4IR::Temp::VirtualRegister
- || newTemp.kind != V4IR::Temp::VirtualRegister)
- return;
-
- if (_slotForTemp.contains(newTemp) || _hints.contains(newTemp))
- return;
-
- int hintedSlot = _slotForTemp.value(hintedSlotOfTemp, -1);
- Q_ASSERT(hintedSlot >= 0);
- _hints[newTemp] = hintedSlot;
- }
-
- int stackSlotFor(V4IR::Temp *t, V4IR::Stmt *currentStmt) {
- Q_ASSERT(t->kind == V4IR::Temp::VirtualRegister);
- Q_ASSERT(t->scope == 0);
- int idx = _slotForTemp.value(*t, -1);
- if (idx == -1)
- idx = allocateSlot(t, currentStmt);
- Q_ASSERT(idx >= 0);
- return idx;
+ switch (e->type) {
+ case V4IR::SInt32Type:
+ case V4IR::UInt32Type:
+ return true;
+ default:
+ return false;
}
+}
-private:
- int allocateSlot(V4IR::Temp *t, V4IR::Stmt *currentStmt) {
- Q_ASSERT(currentStmt->id > 0);
-
- const V4IR::LifeTimeInterval &interval = _intervals[*t];
- int idx = _hints.value(*t, -1);
- if (idx != -1 && _activeSlots[idx] == currentStmt->id) {
- _slotForTemp[*t] = idx;
- _activeSlots[idx] = interval.end();
- return idx;
- }
-
- for (int i = 0, ei = _activeSlots.size(); i != ei; ++i) {
- if (_activeSlots[i] < currentStmt->id) {
- _slotForTemp[*t] = i;
- _activeSlots[i] = interval.end();
- return i;
- }
- }
+inline bool isBoolType(V4IR::Expr *e)
+{
+ return (e->type == V4IR::BoolType);
+}
- return -1;
- }
-};
+} // anonymous namespace
-InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
: EvalInstructionSelection(execAllocator, module, jsGenerator)
- , _function(0)
+ , qmlEngine(qmlEngine)
, _block(0)
, _codeStart(0)
, _codeNext(0)
, _codeEnd(0)
- , _stackSlotAllocator(0)
, _currentStatement(0)
{
compilationUnit = new CompilationUnit;
@@ -246,14 +192,13 @@ void InstructionSelection::run(int functionIndex)
qSwap(codeEnd, _codeEnd);
V4IR::Optimizer opt(_function);
- opt.run();
- StackSlotAllocator *stackSlotAllocator = 0;
+ opt.run(qmlEngine);
if (opt.isInSSA()) {
- stackSlotAllocator = new StackSlotAllocator(opt.lifeRanges(), _function->tempCount);
opt.convertOutOfSSA();
+ opt.showMeTheCode(_function);
}
+ ConvertTemps().toStackSlots(_function);
- qSwap(_stackSlotAllocator, stackSlotAllocator);
QSet<V4IR::Jump *> removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
@@ -263,6 +208,8 @@ void InstructionSelection::run(int functionIndex)
int locals = frameSize();
assert(locals >= 0);
+ V4IR::BasicBlock *exceptionHandler = 0;
+
Instruction::Push push;
push.value = quint32(locals);
addInstruction(push);
@@ -275,6 +222,18 @@ void InstructionSelection::run(int functionIndex)
_nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
_addrs.insert(_block, _codeNext - _codeStart);
+ if (_block->catchBlock != exceptionHandler) {
+ Instruction::SetExceptionHandler set;
+ set.offset = 0;
+ if (_block->catchBlock) {
+ ptrdiff_t loc = addInstruction(set) + (((const char *)&set.offset) - ((const char *)&set));
+ _patches[_block->catchBlock].append(loc);
+ } else {
+ addInstruction(set);
+ }
+ exceptionHandler = _block->catchBlock;
+ }
+
foreach (V4IR::Stmt *s, _block->statements) {
_currentStatement = s;
@@ -294,8 +253,6 @@ void InstructionSelection::run(int functionIndex)
qSwap(_currentStatement, cs);
qSwap(_removableJumps, removableJumps);
- qSwap(_stackSlotAllocator, stackSlotAllocator);
- delete stackSlotAllocator;
qSwap(_function, function);
qSwap(block, _block);
qSwap(nextBlock, _nextBlock);
@@ -330,14 +287,24 @@ void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4
void InstructionSelection::callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args,
V4IR::Temp *result)
{
- // call the property on the loaded base
- Instruction::CallProperty call;
- call.base = getParam(base);
- call.name = registerString(name);
- prepareCallArgs(args, call.argc);
- call.callData = callDataStart();
- call.result = getResultParam(result);
- addInstruction(call);
+ if (useFastLookups) {
+ Instruction::CallPropertyLookup call;
+ call.base = getParam(base);
+ call.lookupIndex = registerGetterLookup(name);
+ prepareCallArgs(args, call.argc);
+ call.callData = callDataStart();
+ call.result = getResultParam(result);
+ addInstruction(call);
+ } else {
+ // call the property on the loaded base
+ Instruction::CallProperty call;
+ call.base = getParam(base);
+ call.name = registerString(name);
+ prepareCallArgs(args, call.argc);
+ call.callData = callDataStart();
+ call.result = getResultParam(result);
+ addInstruction(call);
+ }
}
void InstructionSelection::callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args,
@@ -355,9 +322,6 @@ void InstructionSelection::callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4
void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target)
{
- if (_stackSlotAllocator)
- _stackSlotAllocator->addHint(*source, *target);
-
// FIXME: do something more useful with this info
if (target->type & V4IR::NumberType)
unop(V4IR::OpUPlus, source, target);
@@ -369,6 +333,15 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func,
V4IR::ExprList *args,
V4IR::Temp *result)
{
+ if (useFastLookups && func->global) {
+ Instruction::ConstructGlobalLookup call;
+ call.index = registerGlobalGetterLookup(*func->id);
+ prepareCallArgs(args, call.argc);
+ call.callData = callDataStart();
+ call.result = getResultParam(result);
+ addInstruction(call);
+ return;
+ }
Instruction::CreateActivationProperty create;
create.name = registerString(*func->id);
prepareCallArgs(args, create.argc);
@@ -379,6 +352,16 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func,
void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
{
+ if (useFastLookups) {
+ Instruction::ConstructPropertyLookup call;
+ call.base = getParam(base);
+ call.index = registerGetterLookup(name);
+ prepareCallArgs(args, call.argc);
+ call.callData = callDataStart();
+ call.result = getResultParam(result);
+ addInstruction(call);
+ return;
+ }
Instruction::CreateProperty create;
create.base = getParam(base);
create.name = registerString(name);
@@ -405,14 +388,50 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
addInstruction(load);
}
+void InstructionSelection::loadQmlIdArray(V4IR::Temp *temp)
+{
+ Instruction::LoadQmlIdArray load;
+ load.result = getResultParam(temp);
+ addInstruction(load);
+}
+
+void InstructionSelection::loadQmlImportedScripts(V4IR::Temp *temp)
+{
+ Instruction::LoadQmlImportedScripts load;
+ load.result = getResultParam(temp);
+ addInstruction(load);
+}
+
+void InstructionSelection::loadQmlContextObject(V4IR::Temp *temp)
+{
+ Instruction::LoadQmlContextObject load;
+ load.result = getResultParam(temp);
+ addInstruction(load);
+}
+
+void InstructionSelection::loadQmlScopeObject(V4IR::Temp *temp)
+{
+ Instruction::LoadQmlScopeObject load;
+ load.result = getResultParam(temp);
+ addInstruction(load);
+}
+
+void InstructionSelection::loadQmlSingleton(const QString &name, V4IR::Temp *temp)
+{
+ Instruction::LoadQmlSingleton load;
+ load.result = getResultParam(temp);
+ load.name = registerString(name);
+ addInstruction(load);
+}
+
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
assert(sourceConst);
- Instruction::LoadValue load;
- load.value = getParam(sourceConst);
- load.result = getResultParam(targetTemp);
- addInstruction(load);
+ Instruction::Move move;
+ move.source = getParam(sourceConst);
+ move.result = getResultParam(targetTemp);
+ addInstruction(move);
}
void InstructionSelection::loadString(const QString &str, V4IR::Temp *targetTemp)
@@ -433,6 +452,13 @@ void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *ta
void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp)
{
+ if (useFastLookups && name->global) {
+ Instruction::GetGlobalLookup load;
+ load.index = registerGlobalGetterLookup(*name->id);
+ load.result = getResultParam(temp);
+ addInstruction(load);
+ return;
+ }
Instruction::LoadName load;
load.name = registerString(*name->id);
load.result = getResultParam(temp);
@@ -458,6 +484,14 @@ void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *targe
void InstructionSelection::getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target)
{
+ if (useFastLookups) {
+ Instruction::GetLookup load;
+ load.base = getParam(base);
+ load.index = registerGetterLookup(name);
+ load.result = getResultParam(target);
+ addInstruction(load);
+ return;
+ }
Instruction::LoadProperty load;
load.base = getParam(base);
load.name = registerString(name);
@@ -468,6 +502,14 @@ void InstructionSelection::getProperty(V4IR::Expr *base, const QString &name, V4
void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBase,
const QString &targetName)
{
+ if (useFastLookups) {
+ Instruction::SetLookup store;
+ store.base = getParam(targetBase);
+ store.index = registerSetterLookup(targetName);
+ store.source = getParam(source);
+ addInstruction(store);
+ return;
+ }
Instruction::StoreProperty store;
store.base = getParam(targetBase);
store.name = registerString(targetName);
@@ -475,6 +517,25 @@ void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBas
addInstruction(store);
}
+void InstructionSelection::setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex)
+{
+ Instruction::StoreQObjectProperty store;
+ store.base = getParam(targetBase);
+ store.propertyIndex = propertyIndex;
+ store.source = getParam(source);
+ addInstruction(store);
+}
+
+void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target)
+{
+ Instruction::LoadQObjectProperty load;
+ load.base = getParam(base);
+ load.propertyIndex = propertyIndex;
+ load.result = getResultParam(target);
+ load.captureRequired = captureRequired;
+ addInstruction(load);
+}
+
void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
Instruction::LoadElement load;
@@ -496,10 +557,7 @@ void InstructionSelection::setElement(V4IR::Expr *source, V4IR::Expr *targetBase
void InstructionSelection::copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
{
- if (_stackSlotAllocator)
- _stackSlotAllocator->addHint(*sourceTemp, *targetTemp);
-
- Instruction::MoveTemp move;
+ Instruction::Move move;
move.source = getParam(sourceTemp);
move.result = getResultParam(targetTemp);
if (move.source != move.result)
@@ -516,30 +574,79 @@ void InstructionSelection::swapValues(V4IR::Temp *sourceTemp, V4IR::Temp *target
void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
{
- if (_stackSlotAllocator)
- _stackSlotAllocator->addHint(*sourceTemp, *targetTemp);
-
- QV4::UnaryOpName op = 0;
switch (oper) {
- case V4IR::OpIfTrue: assert(!"unreachable"); break;
- case V4IR::OpNot: op = QV4::__qmljs_not; break;
- case V4IR::OpUMinus: op = QV4::__qmljs_uminus; break;
- case V4IR::OpUPlus: op = QV4::__qmljs_uplus; break;
- case V4IR::OpCompl: op = QV4::__qmljs_compl; break;
- case V4IR::OpIncrement: op = QV4::__qmljs_increment; break;
- case V4IR::OpDecrement: op = QV4::__qmljs_decrement; break;
- default: assert(!"unreachable"); break;
+ case V4IR::OpIfTrue:
+ Q_ASSERT(!"unreachable"); break;
+ case V4IR::OpNot: {
+ // ### enabling this fails in some cases, where apparently the value is not a bool at runtime
+ if (0 && isBoolType(sourceTemp)) {
+ Instruction::UNotBool unot;
+ unot.source = getParam(sourceTemp);
+ unot.result = getResultParam(targetTemp);
+ addInstruction(unot);
+ return;
+ }
+ Instruction::UNot unot;
+ unot.source = getParam(sourceTemp);
+ unot.result = getResultParam(targetTemp);
+ addInstruction(unot);
+ return;
+ }
+ case V4IR::OpUMinus: {
+ Instruction::UMinus uminus;
+ uminus.source = getParam(sourceTemp);
+ uminus.result = getResultParam(targetTemp);
+ addInstruction(uminus);
+ return;
+ }
+ case V4IR::OpUPlus: {
+ if (isNumberType(sourceTemp)) {
+ // use a move
+ Instruction::Move move;
+ move.source = getParam(sourceTemp);
+ move.result = getResultParam(targetTemp);
+ addInstruction(move);
+ return;
+ }
+ Instruction::UPlus uplus;
+ uplus.source = getParam(sourceTemp);
+ uplus.result = getResultParam(targetTemp);
+ addInstruction(uplus);
+ return;
+ }
+ case V4IR::OpCompl: {
+ // ### enabling this fails in some cases, where apparently the value is not a int at runtime
+ if (0 && isIntegerType(sourceTemp)) {
+ Instruction::UComplInt unot;
+ unot.source = getParam(sourceTemp);
+ unot.result = getResultParam(targetTemp);
+ addInstruction(unot);
+ return;
+ }
+ Instruction::UCompl ucompl;
+ ucompl.source = getParam(sourceTemp);
+ ucompl.result = getResultParam(targetTemp);
+ addInstruction(ucompl);
+ return;
+ }
+ case V4IR::OpIncrement: {
+ Instruction::Increment inc;
+ inc.source = getParam(sourceTemp);
+ inc.result = getResultParam(targetTemp);
+ addInstruction(inc);
+ return;
+ }
+ case V4IR::OpDecrement: {
+ Instruction::Decrement dec;
+ dec.source = getParam(sourceTemp);
+ dec.result = getResultParam(targetTemp);
+ addInstruction(dec);
+ return;
+ }
+ default: break;
} // switch
- if (op) {
- Instruction::Unop unop;
- unop.alu = op;
- unop.source = getParam(sourceTemp);
- unop.result = getResultParam(targetTemp);
- addInstruction(unop);
- } else {
- qWarning(" UNOP1");
- }
+ Q_ASSERT(!"unreachable");
}
void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target)
@@ -580,8 +687,84 @@ Param InstructionSelection::binopHelper(V4IR::AluOp oper, V4IR::Expr *leftSource
}
}
- if (_stackSlotAllocator && target && leftSource->asTemp())
- _stackSlotAllocator->addHint(*leftSource->asTemp(), *target);
+ if (oper == V4IR::OpAdd) {
+ Instruction::Add add;
+ add.lhs = getParam(leftSource);
+ add.rhs = getParam(rightSource);
+ add.result = getResultParam(target);
+ addInstruction(add);
+ return add.result;
+ }
+ if (oper == V4IR::OpSub) {
+ Instruction::Sub sub;
+ sub.lhs = getParam(leftSource);
+ sub.rhs = getParam(rightSource);
+ sub.result = getResultParam(target);
+ addInstruction(sub);
+ return sub.result;
+ }
+ if (oper == V4IR::OpMul) {
+ Instruction::Mul mul;
+ mul.lhs = getParam(leftSource);
+ mul.rhs = getParam(rightSource);
+ mul.result = getResultParam(target);
+ addInstruction(mul);
+ return mul.result;
+ }
+ if (oper == V4IR::OpBitAnd) {
+ if (leftSource->asConst())
+ qSwap(leftSource, rightSource);
+ if (V4IR::Const *c = rightSource->asConst()) {
+ Instruction::BitAndConst bitAnd;
+ bitAnd.lhs = getParam(leftSource);
+ bitAnd.rhs = convertToValue(c).Value::toInt32();
+ bitAnd.result = getResultParam(target);
+ addInstruction(bitAnd);
+ return bitAnd.result;
+ }
+ Instruction::BitAnd bitAnd;
+ bitAnd.lhs = getParam(leftSource);
+ bitAnd.rhs = getParam(rightSource);
+ bitAnd.result = getResultParam(target);
+ addInstruction(bitAnd);
+ return bitAnd.result;
+ }
+ if (oper == V4IR::OpBitOr) {
+ if (leftSource->asConst())
+ qSwap(leftSource, rightSource);
+ if (V4IR::Const *c = rightSource->asConst()) {
+ Instruction::BitOrConst bitOr;
+ bitOr.lhs = getParam(leftSource);
+ bitOr.rhs = convertToValue(c).Value::toInt32();
+ bitOr.result = getResultParam(target);
+ addInstruction(bitOr);
+ return bitOr.result;
+ }
+ Instruction::BitOr bitOr;
+ bitOr.lhs = getParam(leftSource);
+ bitOr.rhs = getParam(rightSource);
+ bitOr.result = getResultParam(target);
+ addInstruction(bitOr);
+ return bitOr.result;
+ }
+ if (oper == V4IR::OpBitXor) {
+ if (leftSource->asConst())
+ qSwap(leftSource, rightSource);
+ if (V4IR::Const *c = rightSource->asConst()) {
+ Instruction::BitXorConst bitXor;
+ bitXor.lhs = getParam(leftSource);
+ bitXor.rhs = convertToValue(c).Value::toInt32();
+ bitXor.result = getResultParam(target);
+ addInstruction(bitXor);
+ return bitXor.result;
+ }
+ Instruction::BitXor bitXor;
+ bitXor.lhs = getParam(leftSource);
+ bitXor.rhs = getParam(rightSource);
+ bitXor.result = getResultParam(target);
+ addInstruction(bitXor);
+ return bitXor.result;
+ }
if (oper == V4IR::OpInstanceof || oper == V4IR::OpIn || oper == V4IR::OpAdd) {
Instruction::BinopContext binop;
@@ -619,7 +802,7 @@ void InstructionSelection::prepareCallArgs(V4IR::ExprList *e, quint32 &argc, qui
// We need to move all the temps into the function arg array
assert(argLocation >= 0);
while (e) {
- Instruction::MoveTemp move;
+ Instruction::Move move;
move.source = getParam(e->expr);
move.result = Param::createTemp(argLocation);
addInstruction(move);
@@ -684,24 +867,17 @@ void InstructionSelection::visitRet(V4IR::Ret *s)
addInstruction(ret);
}
-void InstructionSelection::visitTry(V4IR::Try *t)
-{
- Instruction::EnterTry enterTry;
- enterTry.tryOffset = 0;
- enterTry.catchOffset = 0;
- enterTry.exceptionVarName = registerString(*t->exceptionVarName);
- enterTry.exceptionVar = getParam(t->exceptionVar);
- ptrdiff_t enterTryLoc = addInstruction(enterTry);
-
- ptrdiff_t tryLoc = enterTryLoc + (((const char *)&enterTry.tryOffset) - ((const char *)&enterTry));
- _patches[t->tryBlock].append(tryLoc);
-
- ptrdiff_t catchLoc = enterTryLoc + (((const char *)&enterTry.catchOffset) - ((const char *)&enterTry));
- _patches[t->catchBlock].append(catchLoc);
-}
-
void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
{
+ if (useFastLookups && func->global) {
+ Instruction::CallGlobalLookup call;
+ call.index = registerGlobalGetterLookup(*func->id);
+ prepareCallArgs(args, call.argc);
+ call.callData = callDataStart();
+ call.result = getResultParam(result);
+ addInstruction(call);
+ return;
+ }
Instruction::CallActivationProperty call;
call.name = registerString(*func->id);
prepareCallArgs(args, call.argc);
@@ -775,10 +951,11 @@ void InstructionSelection::callBuiltinDeleteName(const QString &name, V4IR::Temp
void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
{
- Instruction::LoadValue load;
- load.value = Param::createValue(QV4::Primitive::fromBoolean(false));
- load.result = getResultParam(result);
- addInstruction(load);
+ Instruction::Move move;
+ int idx = jsUnitGenerator()->registerConstant(QV4::Encode(false));
+ move.source = Param::createConstant(idx);
+ move.result = getResultParam(result);
+ addInstruction(move);
}
void InstructionSelection::callBuiltinThrow(V4IR::Expr *arg)
@@ -788,9 +965,35 @@ void InstructionSelection::callBuiltinThrow(V4IR::Expr *arg)
addInstruction(call);
}
-void InstructionSelection::callBuiltinFinishTry()
+void InstructionSelection::callBuiltinReThrow()
+{
+ if (_block->catchBlock) {
+ // jump to exception handler
+ Instruction::Jump jump;
+ jump.offset = 0;
+ ptrdiff_t loc = addInstruction(jump) + (((const char *)&jump.offset) - ((const char *)&jump));
+
+ _patches[_block->catchBlock].append(loc);
+ } else {
+ Instruction::Ret ret;
+ int idx = jsUnitGenerator()->registerConstant(QV4::Encode::undefined());
+ ret.result = Param::createConstant(idx);
+ addInstruction(ret);
+ }
+}
+
+void InstructionSelection::callBuiltinUnwindException(V4IR::Temp *result)
{
- Instruction::CallBuiltinFinishTry call;
+ Instruction::CallBuiltinUnwindException call;
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+
+void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
+{
+ Instruction::CallBuiltinPushCatchScope call;
+ call.name = registerString(exceptionName);
addInstruction(call);
}
@@ -871,7 +1074,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
bool isData = it->expr->asConst()->value;
it = it->next;
- Instruction::MoveTemp move;
+ Instruction::Move move;
move.source = getParam(it->expr);
move.result = Param::createTemp(argLocation);
addInstruction(move);
@@ -880,7 +1083,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
if (!isData) {
it = it->next;
- Instruction::MoveTemp move;
+ Instruction::Move move;
move.source = getParam(it->expr);
move.result = Param::createTemp(argLocation);
addInstruction(move);
@@ -904,6 +1107,13 @@ void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result)
addInstruction(call);
}
+
+void QQmlJS::Moth::InstructionSelection::callBuiltinConvertThisToObject()
+{
+ Instruction::CallBuiltinConvertThisToObject call;
+ addInstruction(call);
+}
+
ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
{
#ifdef MOTH_THREADED_INTERPRETER
@@ -961,22 +1171,21 @@ QByteArray InstructionSelection::squeezeCode() const
}
Param InstructionSelection::getParam(V4IR::Expr *e) {
- typedef Param Param;
assert(e);
if (V4IR::Const *c = e->asConst()) {
- return Param::createValue(convertToValue(c));
+ int idx = jsUnitGenerator()->registerConstant(convertToValue(c).asReturnedValue());
+ return Param::createConstant(idx);
} else if (V4IR::Temp *t = e->asTemp()) {
switch (t->kind) {
case V4IR::Temp::Formal:
case V4IR::Temp::ScopedFormal: return Param::createArgument(t->index, t->scope);
case V4IR::Temp::Local: return Param::createLocal(t->index);
case V4IR::Temp::ScopedLocal: return Param::createScopedLocal(t->index, t->scope);
- case V4IR::Temp::VirtualRegister:
- return Param::createTemp(_stackSlotAllocator ?
- _stackSlotAllocator->stackSlotFor(t, _currentStatement) : t->index);
+ case V4IR::Temp::StackSlot:
+ return Param::createTemp(t->index);
default:
- Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
return Param();
}
} else {
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index 725dd264aa..031c2d838a 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -54,8 +54,6 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Moth {
-class StackSlotAllocator;
-
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
@@ -65,13 +63,12 @@ struct CompilationUnit : public QV4::CompiledData::CompilationUnit
};
-
class Q_QML_EXPORT InstructionSelection:
public V4IR::IRDecoder,
public EvalInstructionSelection
{
public:
- InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
~InstructionSelection();
virtual void run(int functionIndex);
@@ -82,7 +79,6 @@ protected:
virtual void visitJump(V4IR::Jump *);
virtual void visitCJump(V4IR::CJump *);
virtual void visitRet(V4IR::Ret *);
- virtual void visitTry(V4IR::Try *);
virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callBuiltinTypeofMember(V4IR::Expr *base, const QString &name, V4IR::Temp *result);
@@ -94,7 +90,9 @@ protected:
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinDeleteValue(V4IR::Temp *result);
virtual void callBuiltinThrow(V4IR::Expr *arg);
- virtual void callBuiltinFinishTry();
+ virtual void callBuiltinReThrow();
+ virtual void callBuiltinUnwindException(V4IR::Temp *);
+ virtual void callBuiltinPushCatchScope(const QString &exceptionName);
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinPushWithScope(V4IR::Temp *arg);
@@ -105,6 +103,7 @@ protected:
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result);
+ virtual void callBuiltinConvertThisToObject();
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result);
@@ -113,6 +112,11 @@ protected:
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
virtual void loadThisObject(V4IR::Temp *temp);
+ virtual void loadQmlIdArray(V4IR::Temp *temp);
+ virtual void loadQmlImportedScripts(V4IR::Temp *temp);
+ virtual void loadQmlContextObject(V4IR::Temp *temp);
+ virtual void loadQmlScopeObject(V4IR::Temp *temp);
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp);
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
@@ -121,6 +125,8 @@ protected:
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target);
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName);
+ virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex);
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target);
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target);
virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex);
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
@@ -163,7 +169,8 @@ private:
void patchJumpAddresses();
QByteArray squeezeCode() const;
- V4IR::Function *_function;
+ QQmlEnginePrivate *qmlEngine;
+
V4IR::BasicBlock *_block;
V4IR::BasicBlock *_nextBlock;
@@ -174,7 +181,6 @@ private:
uchar *_codeNext;
uchar *_codeEnd;
- StackSlotAllocator *_stackSlotAllocator;
QSet<V4IR::Jump *> _removableJumps;
V4IR::Stmt *_currentStatement;
@@ -186,8 +192,8 @@ class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- { return new InstructionSelection(execAllocator, module, jsGenerator); }
+ virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+ { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
virtual bool jitCompileRegexps() const
{ return false; }
};
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 483cb8e6f9..96a3370903 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -46,6 +46,7 @@
#include "qv4isel_util_p.h"
#include "qv4functionobject_p.h"
#include "qv4function_p.h"
+#include <private/qqmlpropertycache_p.h>
#include <QString>
@@ -100,8 +101,18 @@ void IRDecoder::visitMove(V4IR::Move *s)
}
} else if (V4IR::Temp *t = s->target->asTemp()) {
if (V4IR::Name *n = s->source->asName()) {
- if (*n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
+ if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
loadThisObject(t);
+ else if (n->builtin == V4IR::Name::builtin_qml_id_array)
+ loadQmlIdArray(t);
+ else if (n->builtin == V4IR::Name::builtin_qml_context_object)
+ loadQmlContextObject(t);
+ else if (n->builtin == V4IR::Name::builtin_qml_scope_object)
+ loadQmlScopeObject(t);
+ else if (n->builtin == V4IR::Name::builtin_qml_imported_scripts_object)
+ loadQmlImportedScripts(t);
+ else if (n->qmlSingleton)
+ loadQmlSingleton(*n->id, t);
else
getActivationProperty(n, t);
return;
@@ -135,7 +146,15 @@ void IRDecoder::visitMove(V4IR::Move *s)
return;
}
} else if (V4IR::Member *m = s->source->asMember()) {
- if (m->base->asTemp() || m->base->asConst()) {
+ if (m->property) {
+ bool captureRequired = true;
+ if (_function) {
+ captureRequired = !_function->contextObjectDependencies.contains(m->property)
+ && !_function->scopeObjectDependencies.contains(m->property);
+ }
+ getQObjectProperty(m->base, m->property->coreIndex, captureRequired, t);
+ return;
+ } else if (m->base->asTemp() || m->base->asConst()) {
getProperty(m->base, *m->name, t);
return;
}
@@ -172,8 +191,13 @@ void IRDecoder::visitMove(V4IR::Move *s)
} else if (V4IR::Member *m = s->target->asMember()) {
if (m->base->asTemp() || m->base->asConst()) {
if (s->source->asTemp() || s->source->asConst()) {
- setProperty(s->source, m->base, *m->name);
- return;
+ if (m->property) {
+ setQObjectProperty(s->source, m->base, m->property->coreIndex);
+ return;
+ } else {
+ setProperty(s->source, m->base, *m->name);
+ return;
+ }
}
}
} else if (V4IR::Subscript *ss = s->target->asSubscript()) {
@@ -266,9 +290,19 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
callBuiltinThrow(arg);
} return;
- case V4IR::Name::builtin_finish_try:
- callBuiltinFinishTry();
- return;
+ case V4IR::Name::builtin_rethrow: {
+ callBuiltinReThrow();
+ } return;
+
+ case V4IR::Name::builtin_unwind_exception: {
+ callBuiltinUnwindException(result);
+ } return;
+
+ case V4IR::Name::builtin_push_catch_scope: {
+ V4IR::String *s = call->args->expr->asString();
+ Q_ASSERT(s);
+ callBuiltinPushCatchScope(*s->value);
+ } return;
case V4IR::Name::builtin_foreach_iterator_object: {
V4IR::Temp *arg = call->args->expr->asTemp();
@@ -350,6 +384,10 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
callBuiltinSetupArgumentObject(result);
return;
+ case V4IR::Name::builtin_convert_this_to_object:
+ callBuiltinConvertThisToObject();
+ return;
+
default:
break;
}
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 8fd59b609c..7ee5cbba4e 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -52,6 +52,8 @@
QT_BEGIN_NAMESPACE
+class QQmlEnginePrivate;
+
namespace QV4 {
class ExecutableAllocator;
struct Function;
@@ -92,7 +94,7 @@ class Q_QML_EXPORT EvalISelFactory
{
public:
virtual ~EvalISelFactory() = 0;
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0;
+ virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0;
virtual bool jitCompileRegexps() const = 0;
};
@@ -100,6 +102,7 @@ namespace V4IR {
class Q_QML_EXPORT IRDecoder: protected V4IR::StmtVisitor
{
public:
+ IRDecoder() : _function(0) {}
virtual ~IRDecoder() = 0;
virtual void visitPhi(V4IR::Phi *) {}
@@ -119,7 +122,9 @@ public: // to implement by subclasses:
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result) = 0;
virtual void callBuiltinDeleteValue(V4IR::Temp *result) = 0;
virtual void callBuiltinThrow(V4IR::Expr *arg) = 0;
- virtual void callBuiltinFinishTry() = 0;
+ virtual void callBuiltinReThrow() = 0;
+ virtual void callBuiltinUnwindException(V4IR::Temp *) = 0;
+ virtual void callBuiltinPushCatchScope(const QString &exceptionName) = 0;
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result) = 0;
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result) = 0;
virtual void callBuiltinPushWithScope(V4IR::Temp *arg) = 0;
@@ -130,6 +135,7 @@ public: // to implement by subclasses:
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args) = 0;
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args) = 0;
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result) = 0;
+ virtual void callBuiltinConvertThisToObject() = 0;
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result) = 0;
@@ -138,6 +144,11 @@ public: // to implement by subclasses:
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void loadThisObject(V4IR::Temp *temp) = 0;
+ virtual void loadQmlIdArray(V4IR::Temp *temp) = 0;
+ virtual void loadQmlImportedScripts(V4IR::Temp *temp) = 0;
+ virtual void loadQmlContextObject(V4IR::Temp *temp) = 0;
+ virtual void loadQmlScopeObject(V4IR::Temp *temp) = 0;
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp) = 0;
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) = 0;
virtual void loadString(const QString &str, V4IR::Temp *targetTemp) = 0;
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp) = 0;
@@ -145,7 +156,9 @@ public: // to implement by subclasses:
virtual void setActivationProperty(V4IR::Expr *source, const QString &targetName) = 0;
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target) = 0;
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target) = 0;
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *targetTemp) = 0;
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName) = 0;
+ virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex) = 0;
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) = 0;
virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex) = 0;
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp) = 0;
@@ -155,6 +168,8 @@ public: // to implement by subclasses:
protected:
virtual void callBuiltin(V4IR::Call *c, V4IR::Temp *result);
+
+ V4IR::Function *_function; // subclass needs to set
};
} // namespace IR
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index 5084de8ec9..38ea682d3b 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -95,6 +95,71 @@ inline QV4::Primitive convertToValue(V4IR::Const *c)
return QV4::Primitive::undefinedValue();
}
+class ConvertTemps: protected V4IR::StmtVisitor, protected V4IR::ExprVisitor
+{
+ int _nextFreeStackSlot;
+ QHash<V4IR::Temp, int> _stackSlotForTemp;
+
+ void renumber(V4IR::Temp *t)
+ {
+ if (t->kind != V4IR::Temp::VirtualRegister)
+ return;
+
+ int stackSlot = _stackSlotForTemp.value(*t, -1);
+ if (stackSlot == -1) {
+ stackSlot = _nextFreeStackSlot++;
+ _stackSlotForTemp[*t] = stackSlot;
+ }
+
+ t->kind = V4IR::Temp::StackSlot;
+ t->index = stackSlot;
+ }
+
+public:
+ ConvertTemps()
+ : _nextFreeStackSlot(0)
+ {}
+
+ void toStackSlots(V4IR::Function *function)
+ {
+ _stackSlotForTemp.reserve(function->tempCount);
+
+ foreach (V4IR::BasicBlock *bb, function->basicBlocks)
+ foreach (V4IR::Stmt *s, bb->statements)
+ s->accept(this);
+
+ function->tempCount = _nextFreeStackSlot;
+ }
+
+protected:
+ virtual void visitConst(V4IR::Const *) {}
+ virtual void visitString(V4IR::String *) {}
+ virtual void visitRegExp(V4IR::RegExp *) {}
+ virtual void visitName(V4IR::Name *) {}
+ virtual void visitTemp(V4IR::Temp *e) { renumber(e); }
+ virtual void visitClosure(V4IR::Closure *) {}
+ virtual void visitConvert(V4IR::Convert *e) { e->expr->accept(this); }
+ virtual void visitUnop(V4IR::Unop *e) { e->expr->accept(this); }
+ virtual void visitBinop(V4IR::Binop *e) { e->left->accept(this); e->right->accept(this); }
+ virtual void visitCall(V4IR::Call *e) {
+ e->base->accept(this);
+ for (V4IR::ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitNew(V4IR::New *e) {
+ e->base->accept(this);
+ for (V4IR::ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitSubscript(V4IR::Subscript *e) { e->base->accept(this); e->index->accept(this); }
+ virtual void visitMember(V4IR::Member *e) { e->base->accept(this); }
+ virtual void visitExp(V4IR::Exp *s) { s->expr->accept(this); }
+ virtual void visitMove(V4IR::Move *s) { s->target->accept(this); s->source->accept(this); }
+ virtual void visitJump(V4IR::Jump *) {}
+ virtual void visitCJump(V4IR::CJump *s) { s->cond->accept(this); }
+ virtual void visitRet(V4IR::Ret *s) { s->expr->accept(this); }
+ virtual void visitPhi(V4IR::Phi *) { Q_UNREACHABLE(); }
+};
} // namespace QQmlJS
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 50afcf29c2..41502dbd4f 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -42,6 +42,7 @@
#include "qv4jsir_p.h"
#include <private/qqmljsast_p.h>
+#include <private/qqmlpropertycache_p.h>
#include <QtCore/qtextstream.h>
#include <QtCore/qdebug.h>
#include <QtCore/qset.h>
@@ -71,6 +72,7 @@ QString typeName(Type t)
case NumberType: return QStringLiteral("number");
case StringType: return QStringLiteral("string");
case VarType: return QStringLiteral("var");
+ case QObjectType: return QStringLiteral("qobject");
default: return QStringLiteral("multiple");
}
}
@@ -217,11 +219,6 @@ struct RemoveSharedExpressions: V4IR::StmtVisitor, V4IR::ExprVisitor
s->expr = cleanup(s->expr);
}
- virtual void visitTry(Try *)
- {
- // nothing to do for Try statements
- }
-
virtual void visitPhi(V4IR::Phi *) { Q_UNIMPLEMENTED(); }
// expressions
@@ -278,8 +275,16 @@ static QString dumpStart(const Expr *e) {
if (e->type == UnknownType)
// return QStringLiteral("**UNKNOWN**");
return QString();
- else
- return typeName(e->type) + QStringLiteral("{");
+
+ QString result = typeName(e->type);
+ const Temp *temp = const_cast<Expr*>(e)->asTemp();
+ if (e->type == QObjectType && temp && temp->memberResolver.data) {
+ result += QLatin1Char('<');
+ result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
+ result += QLatin1Char('>');
+ }
+ result += QLatin1Char('{');
+ return result;
}
static const char *dumpEnd(const Expr *e) {
@@ -367,6 +372,8 @@ void Name::initGlobal(const QString *id, quint32 line, quint32 column)
this->id = id;
this->builtin = builtin_invalid;
this->global = true;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
@@ -376,6 +383,8 @@ void Name::init(const QString *id, quint32 line, quint32 column)
this->id = id;
this->builtin = builtin_invalid;
this->global = false;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
@@ -385,6 +394,8 @@ void Name::init(Builtin builtin, quint32 line, quint32 column)
this->id = 0;
this->builtin = builtin;
this->global = false;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
@@ -400,8 +411,12 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_delete";
case Name::builtin_throw:
return "builtin_throw";
- case Name::builtin_finish_try:
- return "builtin_finish_try";
+ case Name::builtin_rethrow:
+ return "builtin_rethrow";
+ case Name::builtin_unwind_exception:
+ return "builtin_unwind_exception";
+ case Name::builtin_push_catch_scope:
+ return "builtin_push_catch_scope";
case V4IR::Name::builtin_foreach_iterator_object:
return "builtin_foreach_iterator_object";
case V4IR::Name::builtin_foreach_next_property_name:
@@ -422,6 +437,16 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_define_object_literal";
case V4IR::Name::builtin_setup_argument_object:
return "builtin_setup_argument_object";
+ case V4IR::Name::builtin_convert_this_to_object:
+ return "builtin_convert_this_to_object";
+ case V4IR::Name::builtin_qml_id_array:
+ return "builtin_qml_id_array";
+ case V4IR::Name::builtin_qml_imported_scripts_object:
+ return "builtin_qml_imported_scripts_object";
+ case V4IR::Name::builtin_qml_scope_object:
+ return "builtin_qml_scope_object";
+ case V4IR::Name::builtin_qml_context_object:
+ return "builtin_qml_context_object";
}
return "builtin_(###FIXME)";
};
@@ -466,7 +491,7 @@ void Closure::dump(QTextStream &out) const
{
QString name = functionName ? *functionName : QString();
if (name.isEmpty())
- name.sprintf("%p", value);
+ name.sprintf("%x", value);
out << "closure(" << name << ')';
}
@@ -531,6 +556,8 @@ void Member::dump(QTextStream &out) const
{
base->dump(out);
out << '.' << *name;
+ if (property)
+ out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)";
}
void Exp::dump(QTextStream &out, Mode)
@@ -585,15 +612,10 @@ void Ret::dump(QTextStream &out, Mode)
out << ';';
}
-void Try::dump(QTextStream &out, Stmt::Mode mode)
-{
- out << "try L" << tryBlock->index << "; catch exception in ";
- exceptionVar->dump(out);
- out << " with the name " << exceptionVarName << " and go to L" << catchBlock->index << ';';
-}
-
void Phi::dump(QTextStream &out, Stmt::Mode mode)
{
+ Q_UNUSED(mode);
+
targetTemp->dump(out);
out << " = phi(";
for (int i = 0, ei = d->incoming.size(); i < ei; ++i) {
@@ -653,9 +675,9 @@ const QString *Function::newString(const QString &text)
return &*strings.insert(text);
}
-BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlockInsertMode mode)
+BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode)
{
- BasicBlock *block = new BasicBlock(this, containingLoop);
+ BasicBlock *block = new BasicBlock(this, containingLoop, catchBlock);
return mode == InsertBlock ? insertBasicBlock(block) : block;
}
@@ -818,10 +840,10 @@ Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
return e;
}
-Expr *BasicBlock::MEMBER(Expr *base, const QString *name)
+Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property)
{
Member*e = function->New<Member>();
- e->init(base, name);
+ e->init(base, name, property);
return e;
}
@@ -905,33 +927,12 @@ Stmt *BasicBlock::RET(Temp *expr)
return s;
}
-Stmt *BasicBlock::TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString *exceptionVarName, Temp *exceptionVar)
-{
- if (isTerminated())
- return 0;
-
- Try *t = function->New<Try>();
- t->init(tryBlock, catchBlock, exceptionVarName, exceptionVar);
- appendStatement(t);
-
- assert(! out.contains(tryBlock));
- out.append(tryBlock);
-
- assert(! out.contains(catchBlock));
- out.append(catchBlock);
-
- assert(! tryBlock->in.contains(this));
- tryBlock->in.append(this);
-
- assert(! catchBlock->in.contains(this));
- catchBlock->in.append(this);
-
- return t;
-}
-
void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
{
- out << 'L' << index << ':' << endl;
+ out << 'L' << index << ':';
+ if (catchBlock)
+ out << " (catchBlock L" << catchBlock->index << ")";
+ out << endl;
foreach (Stmt *s, statements) {
out << '\t';
s->dump(out, mode);
@@ -1032,7 +1033,7 @@ void CloneExpr::visitSubscript(Subscript *e)
void CloneExpr::visitMember(Member *e)
{
- cloned = block->MEMBER(clone(e->base), e->name);
+ cloned = block->MEMBER(clone(e->base), e->name, e->property);
}
} // end of namespace IR
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 7b0ee52737..aa85c4cf3c 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -55,6 +55,7 @@
#include "private/qv4global_p.h"
#include <private/qqmljsmemorypool_p.h>
#include <private/qqmljsastfwd_p.h>
+#include <private/qflagpointer_p.h>
#include <QtCore/QVector>
#include <QtCore/QString>
@@ -72,6 +73,9 @@ QT_BEGIN_NAMESPACE
class QTextStream;
class QQmlType;
+class QQmlPropertyData;
+class QQmlPropertyCache;
+class QQmlEnginePrivate;
namespace QV4 {
struct ExecutionContext;
@@ -119,9 +123,16 @@ struct Move;
struct Jump;
struct CJump;
struct Ret;
-struct Try;
struct Phi;
+// Flag pointer:
+// * The first flag indicates whether the meta object is final.
+// If final, then none of its properties themselves need to
+// be final when considering for lookups in QML.
+// * The second flag indicates whether enums should be included
+// in the lookup of properties or not. The default is false.
+typedef QFlagPointer<QQmlPropertyCache> IRMetaObject;
+
enum AluOp {
OpInvalid = 0,
@@ -181,7 +192,8 @@ enum Type {
NumberType = SInt32Type | UInt32Type | DoubleType,
StringType = 1 << 7,
- VarType = 1 << 8
+ QObjectType = 1 << 8,
+ VarType = 1 << 9
};
inline bool strictlyEqualTypes(Type t1, Type t2)
@@ -215,10 +227,25 @@ struct StmtVisitor {
virtual void visitJump(Jump *) = 0;
virtual void visitCJump(CJump *) = 0;
virtual void visitRet(Ret *) = 0;
- virtual void visitTry(Try *) = 0;
virtual void visitPhi(Phi *) = 0;
};
+
+struct MemberExpressionResolver
+{
+ typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member);
+
+ MemberExpressionResolver()
+ : resolveMember(0), data(0), flags(0) {}
+
+ bool isValid() const { return !!resolveMember; }
+ void clear() { *this = MemberExpressionResolver(); }
+
+ ResolveFunction resolveMember;
+ void *data; // Could be pointer to meta object, QQmlTypeNameCache, etc. - depends on resolveMember implementation
+ int flags;
+};
+
struct Expr {
Type type;
@@ -312,7 +339,9 @@ struct Name: Expr {
builtin_typeof,
builtin_delete,
builtin_throw,
- builtin_finish_try,
+ builtin_rethrow,
+ builtin_unwind_exception,
+ builtin_push_catch_scope,
builtin_foreach_iterator_object,
builtin_foreach_next_property_name,
builtin_push_with_scope,
@@ -322,12 +351,19 @@ struct Name: Expr {
builtin_define_array,
builtin_define_getter_setter,
builtin_define_object_literal,
- builtin_setup_argument_object
+ builtin_setup_argument_object,
+ builtin_convert_this_to_object,
+ builtin_qml_id_array,
+ builtin_qml_imported_scripts_object,
+ builtin_qml_context_object,
+ builtin_qml_scope_object
};
const QString *id;
Builtin builtin;
- bool global;
+ bool global : 1;
+ bool qmlSingleton : 1;
+ bool freeOfSideEffects : 1;
quint32 line;
quint32 column;
@@ -354,9 +390,12 @@ struct Temp: Expr {
};
unsigned index;
- unsigned scope : 28; // how many scopes outside the current one?
+ unsigned scope : 27; // how many scopes outside the current one?
unsigned kind : 3;
unsigned isArgumentsOrEval : 1;
+ unsigned isReadOnly : 1;
+ // Used when temp is used as base in member expression
+ MemberExpressionResolver memberResolver;
void init(unsigned kind, unsigned index, unsigned scope)
{
@@ -368,10 +407,11 @@ struct Temp: Expr {
this->index = index;
this->scope = scope;
this->isArgumentsOrEval = false;
+ this->isReadOnly = false;
}
virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
- virtual bool isLValue() { return true; }
+ virtual bool isLValue() { return !isReadOnly; }
virtual Temp *asTemp() { return this; }
virtual void dump(QTextStream &out) const;
@@ -514,11 +554,16 @@ struct Subscript: Expr {
struct Member: Expr {
Expr *base;
const QString *name;
+ QQmlPropertyData *property;
+ int enumValue;
+ bool memberIsEnum;
- void init(Expr *base, const QString *name)
+ void init(Expr *base, const QString *name, QQmlPropertyData *property = 0)
{
this->base = base;
this->name = name;
+ this->property = property;
+ this->memberIsEnum = false;
}
virtual void accept(ExprVisitor *v) { v->visitMember(this); }
@@ -543,7 +588,14 @@ struct Stmt {
AST::SourceLocation location;
Stmt(): d(0), id(-1) {}
- virtual ~Stmt() { Q_UNREACHABLE(); }
+ virtual ~Stmt()
+ {
+#ifdef Q_CC_MSVC
+ // MSVC complains about potential memory leaks if a destructor never returns.
+#else
+ Q_UNREACHABLE();
+#endif
+ }
virtual Stmt *asTerminator() { return 0; }
virtual void accept(StmtVisitor *) = 0;
@@ -552,7 +604,6 @@ struct Stmt {
virtual Jump *asJump() { return 0; }
virtual CJump *asCJump() { return 0; }
virtual Ret *asRet() { return 0; }
- virtual Try *asTry() { return 0; }
virtual Phi *asPhi() { return 0; }
virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
@@ -646,28 +697,6 @@ struct Ret: Stmt {
virtual void dump(QTextStream &out, Mode);
};
-struct Try: Stmt {
- BasicBlock *tryBlock;
- BasicBlock *catchBlock;
- const QString *exceptionVarName;
- Temp *exceptionVar; // place to store the caught exception, for use when re-throwing
-
- void init(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString *exceptionVarName, Temp *exceptionVar)
- {
- this->tryBlock = tryBlock;
- this->catchBlock = catchBlock;
- this->exceptionVarName = exceptionVarName;
- this->exceptionVar = exceptionVar;
- }
-
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitTry(this); }
- virtual Try *asTry() { return this; }
-
- virtual void dump(QTextStream &out, Mode mode);
-};
-
struct Phi: Stmt {
Temp *targetTemp;
@@ -683,12 +712,14 @@ struct Q_QML_EXPORT Module {
Function *rootFunction;
QString fileName;
bool isQmlModule; // implies rootFunction is always 0
+ bool debugMode;
Function *newFunction(const QString &name, Function *outer);
- Module()
+ Module(bool debugMode)
: rootFunction(0)
, isQmlModule(false)
+ , debugMode(debugMode)
{}
~Module();
@@ -712,16 +743,24 @@ struct Function {
uint hasDirectEval: 1;
uint usesArgumentsObject : 1;
+ uint usesThis : 1;
uint isStrict: 1;
uint isNamedExpression : 1;
uint hasTry: 1;
uint hasWith: 1;
- uint unused : 26;
+ uint unused : 25;
// Location of declaration in source code (-1 if not specified)
int line;
int column;
+ // Qml extension:
+ QSet<int> idObjectDependencies;
+ QSet<QQmlPropertyData*> contextObjectDependencies;
+ QSet<QQmlPropertyData*> scopeObjectDependencies;
+
+ bool hasQmlDependencies() const { return !idObjectDependencies.isEmpty() || !contextObjectDependencies.isEmpty() || !scopeObjectDependencies.isEmpty(); }
+
template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
Function(Module *module, Function *outer, const QString &name)
@@ -749,7 +788,7 @@ struct Function {
DontInsertBlock
};
- BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlockInsertMode mode = InsertBlock);
+ BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
const QString *newString(const QString &text);
void RECEIVE(const QString &name) { formals.append(newString(name)); }
@@ -764,22 +803,26 @@ struct Function {
int indexOfArgument(const QStringRef &string) const;
bool variablesCanEscape() const
- { return hasDirectEval || !nestedFunctions.isEmpty(); }
+ { return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
};
struct BasicBlock {
Function *function;
+ BasicBlock *catchBlock;
QVector<Stmt *> statements;
QVector<BasicBlock *> in;
QVector<BasicBlock *> out;
QBitArray liveIn;
QBitArray liveOut;
int index;
+ bool isExceptionHandler;
AST::SourceLocation nextLocation;
- BasicBlock(Function *function, BasicBlock *containingLoop)
+ BasicBlock(Function *function, BasicBlock *containingLoop, BasicBlock *catcher)
: function(function)
+ , catchBlock(catcher)
, index(-1)
+ , isExceptionHandler(false)
, _containingGroup(containingLoop)
, _groupStart(false)
{}
@@ -826,7 +869,7 @@ struct BasicBlock {
Expr *CALL(Expr *base, ExprList *args = 0);
Expr *NEW(Expr *base, ExprList *args = 0);
Expr *SUBSCRIPT(Expr *base, Expr *index);
- Expr *MEMBER(Expr *base, const QString *name);
+ Expr *MEMBER(Expr *base, const QString *name, QQmlPropertyData *property = 0);
Stmt *EXP(Expr *expr);
@@ -835,7 +878,6 @@ struct BasicBlock {
Stmt *JUMP(BasicBlock *target);
Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
Stmt *RET(Temp *expr);
- Stmt *TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString *exceptionVarName, Temp *exceptionVar);
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
@@ -892,6 +934,8 @@ public:
newName->id = n->id;
newName->builtin = n->builtin;
newName->global = n->global;
+ newName->qmlSingleton = n->qmlSingleton;
+ newName->freeOfSideEffects = n->freeOfSideEffects;
newName->line = n->line;
newName->column = n->column;
return newName;
@@ -902,6 +946,7 @@ public:
Temp *newTemp = f->New<Temp>();
newTemp->init(t->kind, t->index, t->scope);
newTemp->type = t->type;
+ newTemp->memberResolver = t->memberResolver;
return newTemp;
}
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index c35ee860f7..5d1dc14500 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qv4regalloc_p.h"
+#include <private/qv4value_p.h>
#include <algorithm>
@@ -51,7 +52,7 @@ struct Use {
unsigned flag : 1;
unsigned pos : 31;
- Use(): pos(0), flag(MustHaveRegister) {}
+ Use(): flag(MustHaveRegister), pos(0) {}
Use(int pos, RegisterFlag flag): flag(flag), pos(pos) {}
bool mustHaveRegister() const { return flag == MustHaveRegister; }
@@ -193,7 +194,9 @@ protected: // IRDecoder
virtual void callBuiltinDeleteName(const QString &, V4IR::Temp *) {}
virtual void callBuiltinDeleteValue(V4IR::Temp *) {}
virtual void callBuiltinThrow(V4IR::Expr *) {}
- virtual void callBuiltinFinishTry() {}
+ virtual void callBuiltinReThrow() {}
+ virtual void callBuiltinUnwindException(V4IR::Temp *) {}
+ virtual void callBuiltinPushCatchScope(const QString &) {};
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *, V4IR::Temp *) {}
virtual void callBuiltinForeachNextProperty(V4IR::Temp *, V4IR::Temp *) {}
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *, V4IR::Temp *) {}
@@ -205,6 +208,7 @@ protected: // IRDecoder
virtual void callBuiltinDefineArray(V4IR::Temp *, V4IR::ExprList *) {}
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *, V4IR::ExprList *) {}
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *) {}
+ virtual void callBuiltinConvertThisToObject() {}
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
{
@@ -217,6 +221,8 @@ protected: // IRDecoder
virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args,
V4IR::Temp *result)
{
+ Q_UNUSED(name)
+
addDef(result);
addUses(base->asTemp(), Use::CouldHaveRegister);
addUses(args, Use::CouldHaveRegister);
@@ -332,18 +338,58 @@ protected: // IRDecoder
addDef(temp);
}
+ virtual void loadQmlIdArray(V4IR::Temp *temp)
+ {
+ addDef(temp);
+ addCall();
+ }
+
+ virtual void loadQmlImportedScripts(V4IR::Temp *temp)
+ {
+ addDef(temp);
+ addCall();
+ }
+
+ virtual void loadQmlContextObject(Temp *temp)
+ {
+ addDef(temp);
+ addCall();
+ }
+
+ virtual void loadQmlScopeObject(Temp *temp)
+ {
+ Q_UNUSED(temp);
+
+ addDef(temp);
+ addCall();
+ }
+
+ virtual void loadQmlSingleton(const QString &/*name*/, Temp *temp)
+ {
+ Q_UNUSED(temp);
+
+ addDef(temp);
+ addCall();
+ }
+
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
+ Q_UNUSED(sourceConst);
+
addDef(targetTemp);
}
virtual void loadString(const QString &str, V4IR::Temp *targetTemp)
{
+ Q_UNUSED(str);
+
addDef(targetTemp);
}
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp)
{
+ Q_UNUSED(sourceRegexp);
+
addDef(targetTemp);
addCall();
}
@@ -362,6 +408,8 @@ protected: // IRDecoder
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target)
{
+ Q_UNUSED(closure);
+
addDef(target);
addCall();
}
@@ -380,6 +428,20 @@ protected: // IRDecoder
addCall();
}
+ virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int /*propertyIndex*/)
+ {
+ addUses(source->asTemp(), Use::CouldHaveRegister);
+ addUses(targetBase->asTemp(), Use::CouldHaveRegister);
+ addCall();
+ }
+
+ virtual void getQObjectProperty(V4IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, V4IR::Temp *target)
+ {
+ addDef(target);
+ addUses(base->asTemp(), Use::CouldHaveRegister);
+ addCall();
+ }
+
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
addDef(target);
@@ -494,7 +556,7 @@ protected: // IRDecoder
#endif
} else if (Binop *b = s->cond->asBinop()) {
binop(b->op, b->left, b->right, 0);
- } else if (Const *c = s->cond->asConst()) {
+ } else if (s->cond->asConst()) {
// TODO: SSA optimization for constant condition evaluation should remove this.
// See also visitCJump() in masm.
addCall();
@@ -506,9 +568,6 @@ protected: // IRDecoder
virtual void visitRet(V4IR::Ret *s)
{ addUses(s->expr->asTemp(), Use::CouldHaveRegister); }
- virtual void visitTry(V4IR::Try *)
- { Q_UNREACHABLE(); } // this should never happen, we do not optimize when there is a try in the function
-
virtual void visitPhi(V4IR::Phi *s)
{
addDef(s->targetTemp, true);
@@ -537,6 +596,7 @@ private:
Q_ASSERT(!_defs.contains(*t));
bool canHaveReg = true;
switch (t->type) {
+ case QObjectType:
case VarType:
case StringType:
case UndefinedType:
@@ -593,7 +653,9 @@ namespace {
class ResolutionPhase: protected StmtVisitor, protected ExprVisitor {
QVector<LifeTimeInterval> _intervals;
Function *_function;
+#if !defined(QT_NO_DEBUG)
RegAllocInfo *_info;
+#endif
const QHash<V4IR::Temp, int> &_assignedSpillSlots;
QHash<V4IR::Temp, LifeTimeInterval> _intervalForTemp;
const QVector<int> &_intRegs;
@@ -612,11 +674,16 @@ public:
const QVector<int> &intRegs, const QVector<int> &fpRegs)
: _intervals(intervals)
, _function(function)
+#if !defined(QT_NO_DEBUG)
, _info(info)
+#endif
, _assignedSpillSlots(assignedSpillSlots)
, _intRegs(intRegs)
, _fpRegs(fpRegs)
{
+#if defined(QT_NO_DEBUG)
+ Q_UNUSED(info)
+#endif
}
void run() {
@@ -835,8 +902,28 @@ private:
#if !defined(QT_NO_DEBUG)
if (_info->def(it.temp()) != successorStart && !it.isSplitFromInterval()) {
const int successorEnd = successor->statements.last()->id;
- foreach (const Use &use, _info->uses(it.temp()))
- Q_ASSERT(use.pos < successorStart || use.pos > successorEnd);
+ 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) {
+ if (Phi *phi = s->asPhi()) {
+ Q_ASSERT(it.temp().index != phi->targetTemp->index);
+ Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0
+ || it.temp().index != phi->d->incoming[idx]->asTemp()->index);
+ } else {
+ // TODO: check that the first non-phi statement does not use
+ // the temp.
+ break;
+ }
+ }
+ } else {
+ Q_ASSERT(use.pos < static_cast<unsigned>(successorStart) ||
+ use.pos > static_cast<unsigned>(successorEnd));
+ }
+ }
}
#endif
@@ -917,7 +1004,6 @@ protected:
int pReg = platformRegister(i);
t->kind = Temp::PhysicalRegister;
t->index = pReg;
- Q_ASSERT(t->index >= 0);
} else {
int stackSlot = _assignedSpillSlots.value(*t, -1);
Q_ASSERT(stackSlot >= 0);
@@ -954,7 +1040,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *) { Q_UNREACHABLE(); }
virtual void visitPhi(Phi *) {}
};
} // anonymous namespace
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index c9ff6ad53c..f9acf99a65 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -51,6 +51,8 @@
#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>
@@ -118,6 +120,11 @@ void showMeTheCode(Function *function)
str.append('L');
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(')');
+ }
for (int i = 66 - str.length(); i; --i)
str.append(' ');
qout << str;
@@ -218,26 +225,65 @@ class DominatorTree {
QHash<BasicBlock *, BasicBlock *> samedom;
QHash<BasicBlock *, QSet<BasicBlock *> > bucket;
- void DFS(BasicBlock *p, BasicBlock *n) {
- if (dfnum[n] == 0) {
- dfnum[n] = N;
- vertex[N] = n;
- parent[n] = p;
- ++N;
- foreach (BasicBlock *w, n->out)
- DFS(n, w);
+ struct DFSTodo {
+ BasicBlock *node, *parent;
+
+ DFSTodo():node(0),parent(0){}
+ DFSTodo(BasicBlock *node, BasicBlock *parent):node(node),parent(parent){}
+ };
+
+ void DFS(BasicBlock *node) {
+ QVector<DFSTodo> worklist;
+ worklist.reserve(vertex.capacity());
+ DFSTodo todo(node, 0);
+
+ while (true) {
+ BasicBlock *n = todo.node;
+
+ if (dfnum[n] == 0) {
+ dfnum[n] = N;
+ vertex[N] = n;
+ parent[n] = todo.parent;
+ ++N;
+ for (int i = n->out.size() - 1; i > 0; --i)
+ worklist.append(DFSTodo(n->out[i], n));
+
+ if (n->out.size() > 0) {
+ todo.node = n->out.first();
+ todo.parent = n;
+ continue;
+ }
+ }
+
+ if (worklist.isEmpty())
+ break;
+
+ todo = worklist.last();
+ worklist.removeLast();
}
}
BasicBlock *ancestorWithLowestSemi(BasicBlock *v) {
- BasicBlock *a = ancestor[v];
- if (ancestor[a]) {
- BasicBlock *b = ancestorWithLowestSemi(a);
- ancestor[v] = ancestor[a];
- if (dfnum[semi[b]] < dfnum[semi[best[v]]])
- best[v] = b;
+ QVector<BasicBlock *> worklist;
+ worklist.reserve(vertex.capacity());
+ for (BasicBlock *it = v; it; it = ancestor[it])
+ worklist.append(it);
+
+ if (worklist.size() < 2)
+ return best[v];
+
+ BasicBlock *b = 0;
+ BasicBlock *last = worklist.last();
+ for (int it = worklist.size() - 2; it >= 0; --it) {
+ BasicBlock *bbIt = worklist[it];
+ ancestor[bbIt] = last;
+ BasicBlock *&best_it = best[bbIt];
+ if (b && dfnum[semi[b]] < dfnum[semi[best_it]])
+ best_it = b;
+ else
+ b = best_it;
}
- return best[v];
+ return b;
}
void link(BasicBlock *p, BasicBlock *n) {
@@ -256,8 +302,8 @@ class DominatorTree {
samedom[n] = 0;
}
- DFS(0, nodes.first());
- Q_ASSERT(N == nodes.size()); // fails with unreachable nodes...
+ DFS(nodes.first());
+ Q_ASSERT(N == nodes.size()); // fails with unreachable nodes, but those should have been removed before.
for (int i = N - 1; i > 0; --i) {
BasicBlock *n = vertex[i];
@@ -278,9 +324,9 @@ class DominatorTree {
link(p, n);
foreach (BasicBlock *v, bucket[p]) {
BasicBlock *y = ancestorWithLowestSemi(v);
- Q_ASSERT(semi[y] == p);
- if (semi[y] == semi[v])
- idom[v] = p;
+ BasicBlock *semi_v = semi[v];
+ if (semi[y] == semi_v)
+ idom[v] = semi_v;
else
samedom[v] = y;
}
@@ -316,52 +362,88 @@ class DominatorTree {
return false;
}
- void computeDF(BasicBlock *n) {
- if (DF.contains(n))
- return; // TODO: verify this!
+ struct NodeProgress {
+ QSet<BasicBlock *> children;
+ QSet<BasicBlock *> todo;
+ };
- QSet<BasicBlock *> S;
- foreach (BasicBlock *y, n->out)
- if (idom[y] != n)
- S.insert(y);
+ void computeDF(const QVector<BasicBlock *> &nodes) {
+ QHash<BasicBlock *, NodeProgress> nodeStatus;
+ nodeStatus.reserve(nodes.size());
+ QVector<BasicBlock *> worklist;
+ worklist.reserve(nodes.size() * 2);
+ for (int i = 0, ei = nodes.size(); i != ei; ++i) {
+ BasicBlock *node = nodes[i];
+ worklist.append(node);
+ NodeProgress &np = nodeStatus[node];
+ np.children = children[node];
+ np.todo = children[node];
+ }
- /*
- * foreach child c of n in the dominator tree
- * computeDF[c]
- * foreach element w of DF[c]
- * if n does not dominate w or if n = w
- * S.insert(w)
- * DF[n] = S;
- */
- foreach (BasicBlock *c, children[n]) {
- computeDF(c);
- foreach (BasicBlock *w, DF[c])
- if (!dominates(n, w) || n == w)
- S.insert(w);
+ while (!worklist.isEmpty()) {
+ BasicBlock *node = worklist.last();
+
+ if (DF.contains(node)) {
+ worklist.removeLast();
+ continue;
+ }
+
+ NodeProgress &np = nodeStatus[node];
+ QSet<BasicBlock *>::iterator it = np.todo.begin();
+ while (it != np.todo.end()) {
+ if (DF.contains(*it)) {
+ it = np.todo.erase(it);
+ } else {
+ worklist.append(*it);
+ break;
+ }
+ }
+
+ if (np.todo.isEmpty()) {
+ QSet<BasicBlock *> S;
+ foreach (BasicBlock *y, node->out)
+ if (idom[y] != node)
+ if (!S.contains(y))
+ S.insert(y);
+ foreach (BasicBlock *child, np.children)
+ foreach (BasicBlock *w, DF[child])
+ if (!dominates(node, w) || node == w)
+ if (!S.contains(w))
+ S.insert(w);
+ DF.insert(node, S);
+ worklist.removeLast();
+ }
}
- DF[n] = S;
-#ifdef SHOW_SSA
- qout << "\tDF[" << n->index << "]: {";
- QList<BasicBlock *> SList = S.values();
- for (int i = 0; i < SList.size(); ++i) {
- if (i > 0)
- qout << ", ";
- qout << SList[i]->index;
+#if defined(SHOW_SSA)
+ qout << "Dominator Frontiers:" << endl;
+ foreach (BasicBlock *n, nodes) {
+ qout << "\tDF[" << n->index << "]: {";
+ QList<BasicBlock *> SList = DF[n].values();
+ for (int i = 0; i < SList.size(); ++i) {
+ if (i > 0)
+ qout << ", ";
+ qout << SList[i]->index;
+ }
+ qout << "}" << endl;
}
- qout << "}" << endl;
#endif // SHOW_SSA
-#ifndef QT_NO_DEBUG
- foreach (BasicBlock *fBlock, S) {
- Q_ASSERT(!dominates(n, fBlock) || fBlock == n);
- bool hasDominatedSucc = false;
- foreach (BasicBlock *succ, fBlock->in)
- if (dominates(n, succ))
- hasDominatedSucc = true;
- if (!hasDominatedSucc) {
- qout << fBlock->index << " in DF[" << n->index << "] has no dominated predecessors" << endl;
+#if !defined(QT_NO_DEBUG) && defined(CAN_TAKE_LOSTS_OF_TIME)
+ foreach (BasicBlock *n, nodes) {
+ foreach (BasicBlock *fBlock, DF[n]) {
+ Q_ASSERT(!dominates(n, fBlock) || fBlock == n);
+ bool hasDominatedSucc = false;
+ foreach (BasicBlock *succ, fBlock->in) {
+ if (dominates(n, succ)) {
+ hasDominatedSucc = true;
+ break;
+ }
+ }
+ if (!hasDominatedSucc) {
+ qout << fBlock->index << " in DF[" << n->index << "] has no dominated predecessors" << endl;
+ }
+ Q_ASSERT(hasDominatedSucc);
}
- Q_ASSERT(hasDominatedSucc);
}
#endif // !QT_NO_DEBUG
}
@@ -376,14 +458,13 @@ public:
calculateIDoms(nodes);
// compute children of n
- foreach (BasicBlock *n, nodes)
- children[idom[n]].insert(n);
+ foreach (BasicBlock *n, nodes) {
+ QSet<BasicBlock *> &c = children[idom[n]];
+ if (!c.contains(n))
+ c.insert(n);
+ }
-#ifdef SHOW_SSA
- qout << "Dominator Frontiers:" << endl;
-#endif // SHOW_SSA
- foreach (BasicBlock *n, nodes)
- computeDF(n);
+ computeDF(nodes);
}
QSet<BasicBlock *> operator[](BasicBlock *n) const {
@@ -481,8 +562,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *) { // ### TODO
- }
virtual void visitCall(Call *e) {
e->base->accept(this);
@@ -725,7 +804,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *s) { /* this should never happen */ }
virtual void visitConst(Const *) {}
virtual void visitString(String *) {}
@@ -959,7 +1037,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *) {}
virtual void visitPhi(Phi *s) {
addDef(s->targetTemp);
@@ -1112,6 +1189,8 @@ protected:
virtual void visitName(Name *e)
{
+ if (e->freeOfSideEffects)
+ return;
// TODO: maybe we can distinguish between built-ins of which we know that they do not have
// a side-effect.
if (e->builtin == Name::builtin_invalid || (e->id && *e->id != QStringLiteral("this")))
@@ -1133,6 +1212,7 @@ protected:
e->expr->accept(this);
switch (e->expr->type) {
+ case QObjectType:
case StringType:
case VarType:
markAsSideEffect();
@@ -1151,7 +1231,7 @@ protected:
case OpNot:
case OpIncrement:
case OpDecrement:
- if (e->expr->type == VarType || e->expr->type == StringType)
+ if (e->expr->type == VarType || e->expr->type == StringType || e->expr->type == QObjectType)
markAsSideEffect();
break;
@@ -1167,8 +1247,8 @@ protected:
_sideEffect = checkForSideEffects(e->left);
_sideEffect |= checkForSideEffects(e->right);
- if (e->left->type == VarType || e->left->type == StringType
- || e->right->type == VarType || e->right->type == StringType)
+ if (e->left->type == VarType || e->left->type == StringType || e->left->type == QObjectType
+ || e->right->type == VarType || e->right->type == StringType || e->right->type == QObjectType)
markAsSideEffect();
}
@@ -1199,22 +1279,42 @@ protected:
};
class TypeInference: public StmtVisitor, public ExprVisitor {
+ struct DiscoveredType {
+ int type;
+ MemberExpressionResolver memberResolver;
+
+ DiscoveredType() : type(UnknownType) {}
+ DiscoveredType(Type t) : type(t) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(int t) : type(t) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(MemberExpressionResolver memberResolver) : type(QObjectType), memberResolver(memberResolver) {}
+
+ bool test(Type t) const { return type & t; }
+ bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); }
+
+ bool operator!=(Type other) const { return type != other; }
+ bool operator==(Type other) const { return type == other; }
+ bool operator==(const DiscoveredType &other) const { return type == other.type; }
+ bool operator!=(const DiscoveredType &other) const { return type != other.type; }
+ };
+
+ QQmlEnginePrivate *qmlEngine;
bool _variablesCanEscape;
const DefUsesCalculator &_defUses;
- QHash<Temp, int> _tempTypes;
+ QHash<Temp, DiscoveredType> _tempTypes;
QSet<Stmt *> _worklist;
struct TypingResult {
- int type;
+ DiscoveredType type;
bool fullyTyped;
- TypingResult(int type, bool fullyTyped): type(type), fullyTyped(fullyTyped) {}
- explicit TypingResult(int type = UnknownType): type(type), fullyTyped(type != UnknownType) {}
+ TypingResult(const DiscoveredType &type = DiscoveredType()) : type(type), fullyTyped(type.type != UnknownType) {}
+ explicit TypingResult(MemberExpressionResolver memberResolver): type(memberResolver), fullyTyped(true) {}
};
TypingResult _ty;
public:
- TypeInference(const DefUsesCalculator &defUses)
- : _defUses(defUses)
+ TypeInference(QQmlEnginePrivate *qmlEngine, const DefUsesCalculator &defUses)
+ : qmlEngine(qmlEngine)
+ , _defUses(defUses)
, _ty(UnknownType)
{}
@@ -1260,7 +1360,7 @@ private:
class PropagateTempTypes: public StmtVisitor, ExprVisitor
{
public:
- PropagateTempTypes(const QHash<Temp, int> &tempTypes)
+ PropagateTempTypes(const QHash<Temp, DiscoveredType> &tempTypes)
: _tempTypes(tempTypes)
{}
@@ -1272,11 +1372,15 @@ private:
}
protected:
- virtual void visitConst(Const *e) {}
+ virtual void visitConst(Const *) {}
virtual void visitString(String *) {}
virtual void visitRegExp(RegExp *) {}
virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *e) { e->type = (Type) _tempTypes[*e]; }
+ virtual void visitTemp(Temp *e) {
+ DiscoveredType t = _tempTypes[*e];
+ e->type = (Type) t.type;
+ e->memberResolver = t.memberResolver;
+ }
virtual void visitClosure(Closure *) {}
virtual void visitConvert(Convert *e) { e->expr->accept(this); }
virtual void visitUnop(Unop *e) { e->expr->accept(this); }
@@ -1310,7 +1414,6 @@ private:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *s) { s->exceptionVar->accept(this); }
virtual void visitPhi(Phi *s) {
s->targetTemp->accept(this);
foreach (Expr *e, s->d->incoming)
@@ -1318,7 +1421,7 @@ private:
}
private:
- QHash<Temp, int> _tempTypes;
+ QHash<Temp, DiscoveredType> _tempTypes;
};
private:
@@ -1354,13 +1457,13 @@ private:
}
}
- void setType(Expr *e, int ty) {
+ void setType(Expr *e, DiscoveredType ty) {
if (Temp *t = e->asTemp()) {
#if defined(SHOW_SSA)
qout<<"Setting type for "<< (t->scope?"scoped temp ":"temp ") <<t->index<< " to "<<typeName(Type(ty)) << " (" << ty << ")" << endl;
#endif
if (isAlwaysAnObject(t))
- ty = VarType;
+ ty = DiscoveredType(VarType);
if (_tempTypes[*t] != ty) {
_tempTypes[*t] = ty;
@@ -1375,7 +1478,7 @@ private:
_worklist += QSet<Stmt *>::fromList(_defUses.uses(*t));
}
} else {
- e->type = (Type) ty;
+ e->type = (Type) ty.type;
}
}
@@ -1397,8 +1500,10 @@ protected:
virtual void visitTemp(Temp *e) {
if (isAlwaysAnObject(e))
_ty = TypingResult(VarType);
+ else if (e->memberResolver.isValid())
+ _ty = TypingResult(e->memberResolver);
else
- _ty = TypingResult(_tempTypes.value(*e, UnknownType));
+ _ty = TypingResult(_tempTypes.value(*e));
setType(e, _ty.type);
}
virtual void visitClosure(Closure *) { _ty = TypingResult(VarType); }
@@ -1430,9 +1535,9 @@ protected:
switch (e->op) {
case OpAdd:
- if (leftTy.type & VarType || rightTy.type & VarType)
+ if (leftTy.type.test(VarType) || leftTy.type.test(QObjectType) || rightTy.type.test(VarType) || rightTy.type.test(QObjectType))
_ty.type = VarType;
- else if (leftTy.type & StringType || rightTy.type & StringType)
+ else if (leftTy.type.test(StringType) || rightTy.type.test(StringType))
_ty.type = StringType;
else if (leftTy.type != UnknownType && rightTy.type != UnknownType)
_ty.type = DoubleType;
@@ -1499,9 +1604,13 @@ protected:
}
virtual void visitMember(Member *e) {
- // TODO: for QML, try to do a static lookup
_ty = run(e->base);
- _ty.type = VarType;
+
+ if (_ty.fullyTyped && _ty.type.memberResolver.isValid()) {
+ MemberExpressionResolver &resolver = _ty.type.memberResolver;
+ _ty.type.type = resolver.resolveMember(qmlEngine, &resolver, e);
+ } else
+ _ty.type = VarType;
}
virtual void visitExp(Exp *s) { _ty = run(s->expr); }
@@ -1520,7 +1629,6 @@ protected:
virtual void visitJump(Jump *) { _ty = TypingResult(MissingType); }
virtual void visitCJump(CJump *s) { _ty = run(s->cond); }
virtual void visitRet(Ret *s) { _ty = run(s->expr); }
- virtual void visitTry(Try *s) { setType(s->exceptionVar, VarType); _ty = TypingResult(MissingType); }
virtual void visitPhi(Phi *s) {
_ty = run(s->d->incoming[0]);
for (int i = 1, ei = s->d->incoming.size(); i != ei; ++i) {
@@ -1532,11 +1640,13 @@ protected:
_ty.fullyTyped = false;
break;
}
- _ty.type |= ty.type;
+ _ty.type.type |= ty.type.type;
_ty.fullyTyped &= ty.fullyTyped;
+ if (_ty.type.test(QObjectType))
+ _ty.type.memberResolver.clear(); // ### TODO: find common ancestor meta-object
}
- switch (_ty.type) {
+ switch (_ty.type.type) {
case UnknownType:
case UndefinedType:
case NullType:
@@ -1545,13 +1655,14 @@ protected:
case UInt32Type:
case DoubleType:
case StringType:
+ case QObjectType:
case VarType:
// The type is not a combination of two or more types, so we're done.
break;
default:
// There are multiple types involved, so:
- if ((_ty.type & NumberType) && !(_ty.type & ~NumberType))
+ if (_ty.type.isNumber())
// The type is any combination of double/int32/uint32, but nothing else. So we can
// type it as double.
_ty.type = DoubleType;
@@ -1651,7 +1762,11 @@ public:
}
foreach (const Conversion &conversion, _conversions) {
- if (conversion.stmt->asMove() && conversion.stmt->asMove()->source->asTemp()) {
+ V4IR::Move *move = conversion.stmt->asMove();
+
+ // Note: isel only supports move into member when source is a temp, so convert
+ // is not a supported source.
+ if (move && move->source->asTemp() && !move->target->asMember()) {
*conversion.expr = bb->CONVERT(*conversion.expr, conversion.targetType);
} else if (Const *c = (*conversion.expr)->asConst()) {
convertConst(c, conversion.targetType);
@@ -1789,14 +1904,20 @@ protected:
}
}
- run(s->source, s->target->type);
+ // Don't convert when writing to QObject properties. All sorts of extra behavior
+ // is defined when writing to them, for example resettable properties are reset
+ // when writing undefined to them, and an exception is thrown when they're missing
+ // a reset function.
+ const Member *targetMember = s->target->asMember();
+ const bool inhibitConversion = targetMember && targetMember->property;
+
+ run(s->source, s->target->type, !inhibitConversion);
}
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) {
run(s->cond, BoolType);
}
virtual void visitRet(Ret *s) { run(s->expr); }
- virtual void visitTry(Try *) {}
virtual void visitPhi(Phi *s) {
Type ty = s->targetTemp->type;
for (int i = 0, ei = s->d->incoming.size(); i != ei; ++i)
@@ -1818,7 +1939,7 @@ void splitCriticalEdges(Function *f)
#endif
// create the basic block:
- BasicBlock *newBB = new BasicBlock(f, bb->containingGroup());
+ BasicBlock *newBB = new BasicBlock(f, bb->containingGroup(), bb->catchBlock);
newBB->index = f->basicBlocks.last()->index + 1;
f->basicBlocks.append(newBB);
Jump *s = f->New<Jump>();
@@ -1868,8 +1989,8 @@ QHash<BasicBlock *, BasicBlock *> scheduleBlocks(Function *function, const Domin
I(const DominatorTree &df, QVector<BasicBlock *> &sequence,
QHash<BasicBlock *, BasicBlock *> &startEndLoops)
: df(df)
- , sequence(sequence)
, startEndLoops(startEndLoops)
+ , sequence(sequence)
, currentGroup(0)
{}
@@ -1934,6 +2055,7 @@ QHash<BasicBlock *, BasicBlock *> scheduleBlocks(Function *function, const Domin
return startEndLoops;
}
+#ifndef QT_NO_DEBUG
void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
foreach (BasicBlock *bb, basicBlocks) {
if (bb && bb->out.size() > 1) {
@@ -1947,34 +2069,61 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
}
}
}
+#endif
-void cleanupBasicBlocks(Function *function)
+void cleanupBasicBlocks(Function *function, bool renumber)
{
-// showMeTheCode(function);
+ showMeTheCode(function);
- // remove all basic blocks that have no incoming edges, but skip the entry block
- QVector<BasicBlock *> W = function->basicBlocks;
- W.removeFirst();
+ // 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);
+ }
- while (!W.isEmpty()) {
- BasicBlock *bb = W.first();
- W.removeFirst();
- if (toRemove.contains(bb))
- continue;
- if (bb->in.isEmpty()) {
- foreach (BasicBlock *outBB, bb->out) {
- int idx = outBB->in.indexOf(bb);
- if (idx != -1) {
- outBB->in.remove(idx);
- W.append(outBB);
- }
+ while (!postponed.isEmpty()) {
+ QSet<BasicBlock *>::iterator it = postponed.begin();
+ BasicBlock *bb = *it;
+ postponed.erase(it);
+ done.insert(bb);
+
+ foreach (BasicBlock *outBB, bb->out) {
+ if (!done.contains(outBB)) {
+ postponed.insert(outBB);
+ toRemove.remove(outBB);
}
- toRemove.insert(bb);
}
}
foreach (BasicBlock *bb, toRemove) {
+ foreach (BasicBlock *outBB, bb->out) {
+ if (toRemove.contains(outBB))
+ 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) {
+ if (Phi *phi = s->asPhi())
+ phi->d->incoming.remove(idx);
+ else
+ break;
+ }
+ }
+ }
+
foreach (Stmt *s, bb->statements)
s->destroyData();
int idx = function->basicBlocks.indexOf(bb);
@@ -1983,9 +2132,11 @@ void cleanupBasicBlocks(Function *function)
delete bb;
}
- // re-number all basic blocks:
- for (int i = 0; i < function->basicBlocks.size(); ++i)
- function->basicBlocks[i]->index = i;
+ if (renumber)
+ for (int i = 0; i < function->basicBlocks.size(); ++i)
+ function->basicBlocks[i]->index = i;
+
+ showMeTheCode(function);
}
inline Const *isConstPhi(Phi *phi)
@@ -2009,20 +2160,6 @@ inline Const *isConstPhi(Phi *phi)
return 0;
}
-inline Temp *isSameTempPhi(Phi *phi)
-{
- if (Temp *t = phi->d->incoming[0]->asTemp()) {
- for (int i = 1, ei = phi->d->incoming.size(); i != ei; ++i) {
- if (Temp *tt = phi->d->incoming[i]->asTemp())
- if (t->index == tt->index)
- continue;
- return 0;
- }
- return t;
- }
- return 0;
-}
-
static Expr *clone(Expr *e, Function *function) {
if (Temp *t = e->asTemp()) {
return CloneExpr::cloneTemp(t, function);
@@ -2103,7 +2240,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { check(s->cond); }
virtual void visitRet(Ret *s) { check(s->expr); }
- virtual void visitTry(Try *) { Q_UNREACHABLE(); }
virtual void visitPhi(Phi *s) {
for (int i = 0, ei = s->d->incoming.size(); i != ei; ++i)
check(s->d->incoming[i]);
@@ -2166,6 +2302,11 @@ namespace {
/// Important: this assumes that there are no critical edges in the control-flow graph!
void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector<Stmt *> &W)
{
+ // don't purge blocks that are entry points for catch statements. They might not be directly
+ // connected, but are required anyway
+ if (bb->isExceptionHandler)
+ return;
+
QVector<BasicBlock *> toPurge;
toPurge.append(bb);
@@ -2235,10 +2376,10 @@ bool tryOptimizingComparison(Expr *&expr)
if (!b)
return false;
Const *leftConst = b->left->asConst();
- if (!leftConst || leftConst->type == StringType || leftConst->type == VarType)
+ if (!leftConst || leftConst->type == StringType || leftConst->type == VarType || leftConst->type == QObjectType)
return false;
Const *rightConst = b->right->asConst();
- if (!rightConst || rightConst->type == StringType || rightConst->type == VarType)
+ if (!rightConst || rightConst->type == StringType || rightConst->type == VarType || rightConst->type == QObjectType)
return false;
QV4::Primitive l = convertToValue(leftConst);
@@ -2373,6 +2514,17 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
}
continue;
}
+ if (Member *potentialEnumMember = m->source->asMember()) {
+ if (potentialEnumMember->memberIsEnum) {
+ Const *c = function->New<Const>();
+ c->init(SInt32Type, potentialEnumMember->enumValue);
+ W += replaceUses(targetTemp, c);
+ defUses.removeDef(*targetTemp);
+ *ref[s] = 0;
+ defUses.removeUse(s, *potentialEnumMember->base->asTemp());
+ continue;
+ }
+ }
// copy propagation:
if (Temp *sourceTemp = unescapableTemp(m->source, variablesCanEscape)) {
@@ -2449,10 +2601,10 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
// TODO: If the result of the move is only used in one single cjump, then
// inline the binop into the cjump.
Const *leftConst = binop->left->asConst();
- if (!leftConst || leftConst->type == StringType || leftConst->type == VarType)
+ if (!leftConst || leftConst->type == StringType || leftConst->type == VarType || leftConst->type == QObjectType)
continue;
Const *rightConst = binop->right->asConst();
- if (!rightConst || rightConst->type == StringType || rightConst->type == VarType)
+ if (!rightConst || rightConst->type == StringType || rightConst->type == VarType || rightConst->type == QObjectType)
continue;
QV4::Primitive lc = convertToValue(leftConst);
@@ -2603,8 +2755,7 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *) {}
- virtual void visitPhi(Phi *s) {
+ virtual void visitPhi(Phi *) {
// Handled separately
}
};
@@ -2837,7 +2988,7 @@ bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTim
return r1.temp() < r2.temp();
}
-void Optimizer::run()
+void Optimizer::run(QQmlEnginePrivate *qmlEngine)
{
#if defined(SHOW_SSA)
qout << "##### NOW IN FUNCTION " << (function->name ? qPrintable(*function->name) : "anonymous!")
@@ -2849,7 +3000,7 @@ void Optimizer::run()
function->basicBlocks[i]->index = i;
// showMeTheCode(function);
- cleanupBasicBlocks(function);
+ cleanupBasicBlocks(function, true);
function->removeSharedExpressions();
@@ -2858,7 +3009,7 @@ void Optimizer::run()
static bool doSSA = qgetenv("QV4_NO_SSA").isEmpty();
static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty();
- if (!function->hasTry && !function->hasWith && doSSA) {
+ if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA) {
// qout << "SSA for " << *function->name << endl;
// qout << "Starting edge splitting..." << endl;
splitCriticalEdges(function);
@@ -2879,7 +3030,7 @@ void Optimizer::run()
// showMeTheCode(function);
// qout << "Running type inference..." << endl;
- TypeInference(defUses).run(function);
+ TypeInference(qmlEngine, defUses).run(function);
// showMeTheCode(function);
// qout << "Doing type propagation..." << endl;
@@ -2896,6 +3047,13 @@ void Optimizer::run()
// mergeBasicBlocks(function);
// showMeTheCode(function);
+ // Basic-block cycles that are unreachable (i.e. for loops in a then-part where the
+ // condition is calculated to be always false) are not yet removed. This will choke the
+ // block scheduling, so remove those now.
+// qout << "Cleaning up unreachable basic blocks..." << endl;
+ cleanupBasicBlocks(function, false);
+// showMeTheCode(function);
+
// qout << "Doing block scheduling..." << endl;
startEndLoops = scheduleBlocks(function, df);
// showMeTheCode(function);
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index fc84ffd551..dcbc83ae65 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -46,6 +46,7 @@
QT_BEGIN_NAMESPACE
class QTextStream;
+class QQmlEnginePrivate;
namespace QQmlJS {
namespace V4IR {
@@ -98,9 +99,7 @@ public:
bool covers(int position) const
{
foreach (const Range &r, _ranges) {
- if (position < r.start)
- return false;
- if (position <= r.end)
+ if (r.covers(position))
return true;
}
return false;
@@ -131,7 +130,7 @@ public:
, inSSA(false)
{}
- void run();
+ void run(QQmlEnginePrivate *qmlEngine);
void convertOutOfSSA();
bool isInSSA() const
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
index 5286d3e694..0523762971 100644
--- a/src/qml/debugger/qqmldebugserver.cpp
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -514,8 +514,6 @@ void QQmlDebugServerPrivate::_q_changeServiceState(const QString &serviceName,
if (service && (service->d_func()->state != newState)) {
service->stateAboutToBeChanged(newState);
service->d_func()->state = newState;
- if (newState == QQmlDebugService::NotConnected)
- service->d_func()->server = 0;
service->stateChanged(newState);
}
diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp
index f036dd9d69..d8fc2f2bb2 100644
--- a/src/qml/debugger/qqmldebugservice.cpp
+++ b/src/qml/debugger/qqmldebugservice.cpp
@@ -52,20 +52,18 @@
QT_BEGIN_NAMESPACE
QQmlDebugServicePrivate::QQmlDebugServicePrivate()
- : server(0)
{
}
QQmlDebugService::QQmlDebugService(const QString &name, float version, QObject *parent)
: QObject(*(new QQmlDebugServicePrivate), parent)
{
+ QQmlDebugServer::instance(); // create it when it isn't there yet.
+
Q_D(QQmlDebugService);
d->name = name;
d->version = version;
- d->server = QQmlDebugServer::instance();
d->state = QQmlDebugService::NotConnected;
-
-
}
QQmlDebugService::QQmlDebugService(QQmlDebugServicePrivate &dd,
@@ -75,7 +73,6 @@ QQmlDebugService::QQmlDebugService(QQmlDebugServicePrivate &dd,
Q_D(QQmlDebugService);
d->name = name;
d->version = version;
- d->server = QQmlDebugServer::instance();
d->state = QQmlDebugService::NotConnected;
}
@@ -86,24 +83,23 @@ QQmlDebugService::QQmlDebugService(QQmlDebugServicePrivate &dd,
QQmlDebugService::State QQmlDebugService::registerService()
{
Q_D(QQmlDebugService);
- if (!d->server)
+ QQmlDebugServer *server = QQmlDebugServer::instance();
+
+ if (!server)
return NotConnected;
- if (d->server->serviceNames().contains(d->name)) {
+ if (server->serviceNames().contains(d->name)) {
qWarning() << "QQmlDebugService: Conflicting plugin name" << d->name;
- d->server = 0;
} else {
- d->server->addService(this);
+ server->addService(this);
}
return state();
}
QQmlDebugService::~QQmlDebugService()
{
- Q_D(const QQmlDebugService);
- if (d->server) {
- d->server->removeService(this);
- }
+ if (QQmlDebugServer *inst = QQmlDebugServer::instance())
+ inst->removeService(this);
}
QString QQmlDebugService::name() const
@@ -303,12 +299,11 @@ void QQmlDebugService::sendMessage(const QByteArray &message)
void QQmlDebugService::sendMessages(const QList<QByteArray> &messages)
{
- Q_D(QQmlDebugService);
-
if (state() != Enabled)
return;
- d->server->sendMessages(this, messages);
+ if (QQmlDebugServer *inst = QQmlDebugServer::instance())
+ inst->sendMessages(this, messages);
}
void QQmlDebugService::stateAboutToBeChanged(State)
diff --git a/src/qml/debugger/qqmldebugservice_p_p.h b/src/qml/debugger/qqmldebugservice_p_p.h
index 940990f628..70cf8ef73a 100644
--- a/src/qml/debugger/qqmldebugservice_p_p.h
+++ b/src/qml/debugger/qqmldebugservice_p_p.h
@@ -69,7 +69,6 @@ public:
QString name;
float version;
- QQmlDebugServer *server;
QQmlDebugService::State state;
};
diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp
index ac239f31be..400bb18edd 100644
--- a/src/qml/debugger/qv4debugservice.cpp
+++ b/src/qml/debugger/qv4debugservice.cpp
@@ -45,10 +45,17 @@
#include "qv4debugging_p.h"
#include "qv4engine_p.h"
#include "qv4function_p.h"
+#include "qqmldebugserver_p.h"
#include <private/qv8engine_p.h>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonValue>
+
const char *V4_CONNECT = "connect";
+const char *V4_DISCONNECT = "disconnect";
const char *V4_BREAK_ON_SIGNAL = "breakonsignal";
const char *V4_ADD_BREAKPOINT = "addBreakpoint";
const char *V4_REMOVE_BREAKPOINT = "removeBreakpoint";
@@ -59,14 +66,296 @@ const char *V4_BREAK = "break";
const char *V4_FILENAME = "filename";
const char *V4_LINENUMBER = "linenumber";
+#define NO_PROTOCOL_TRACING
+#ifdef NO_PROTOCOL_TRACING
+# define TRACE_PROTOCOL(x)
+#else
+# define TRACE_PROTOCOL(x) x
+static QTextStream debug(stderr, QIODevice::WriteOnly);
+#endif
+
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QV4DebugService, v4ServiceInstance)
+class QV4DebugServicePrivate;
+
class QV4DebuggerAgent : public QV4::Debugging::DebuggerAgent
{
+public:
+ QV4DebuggerAgent(QV4DebugServicePrivate *debugServicePrivate)
+ : debugServicePrivate(debugServicePrivate)
+ {}
+
+ QV4::Debugging::Debugger *firstDebugger() const
+ {
+ // Currently only 1 single engine is supported, so:
+ if (m_debuggers.isEmpty())
+ return 0;
+ else
+ return m_debuggers.first();
+ }
+
+ bool isRunning() const
+ {
+ // Currently only 1 single engine is supported, so:
+ if (QV4::Debugging::Debugger *debugger = firstDebugger())
+ return debugger->state() == QV4::Debugging::Debugger::Running;
+ else
+ return false;
+ }
+
public slots:
- virtual void debuggerPaused(QV4::Debugging::Debugger *debugger);
+ virtual void debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason);
+ virtual void sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, int requestSequenceNr);
+
+private:
+ QV4DebugServicePrivate *debugServicePrivate;
+};
+
+class V8CommandHandler;
+class UnknownV8CommandHandler;
+
+class VariableCollector: public QV4::Debugging::Debugger::Collector
+{
+public:
+ VariableCollector(QV4::ExecutionEngine *engine)
+ : Collector(engine)
+ , destination(0)
+ {}
+
+ virtual ~VariableCollector() {}
+
+ void collectScope(QJsonArray *dest, QV4::Debugging::Debugger *debugger, int frameNr, int scopeNr)
+ {
+ qSwap(destination, dest);
+ bool oldIsProp = isProperty();
+ setIsProperty(true);
+ debugger->collectArgumentsInContext(this, frameNr, scopeNr);
+ debugger->collectLocalsInContext(this, frameNr, scopeNr);
+ setIsProperty(oldIsProp);
+ qSwap(destination, dest);
+ }
+
+ void setDestination(QJsonArray *dest)
+ { destination = dest; }
+
+ QJsonArray retrieveRefsToInclude()
+ {
+ QJsonArray result;
+ qSwap(refsToInclude, result);
+ return result;
+ }
+
+ QJsonValue lookup(int handle, bool addRefs = true)
+ {
+ if (handle < 0)
+ handle = -handle;
+
+ if (addRefs)
+ foreach (int ref, refsByHandle[handle])
+ refsToInclude.append(lookup(ref, false));
+ return refs[handle];
+ }
+
+ QJsonObject makeRef(int refId)
+ {
+ QJsonObject ref;
+ ref[QLatin1String("ref")] = refId;
+ return ref;
+ }
+
+ QJsonObject addFunctionRef(const QString &name)
+ {
+ const int refId = newRefId();
+
+ QJsonObject func;
+ func[QLatin1String("handle")] = refId;
+ func[QLatin1String("type")] = QStringLiteral("function");
+ func[QLatin1String("className")] = QStringLiteral("Function");
+ func[QLatin1String("name")] = name;
+ insertRef(func, refId);
+
+ return makeRef(refId);
+ }
+
+ QJsonObject addScriptRef(const QString &name)
+ {
+ const int refId = newRefId();
+
+ QJsonObject func;
+ func[QLatin1String("handle")] = refId;
+ func[QLatin1String("type")] = QStringLiteral("script");
+ func[QLatin1String("name")] = name;
+ insertRef(func, refId);
+
+ return makeRef(refId);
+ }
+
+ QJsonObject addObjectRef(QJsonObject obj, bool anonymous)
+ {
+ int ref = newRefId();
+
+ if (anonymous)
+ ref = -ref;
+ obj[QLatin1String("handle")] = ref;
+ obj[QLatin1String("type")] = QStringLiteral("object");
+ insertRef(obj, ref);
+ QSet<int> used;
+ qSwap(usedRefs, used);
+ refsByHandle.insert(ref, used);
+
+ return makeRef(ref);
+ }
+
+protected:
+ virtual void addUndefined(const QString &name)
+ {
+ QJsonObject o;
+ addHandle(name, o, QStringLiteral("undefined"));
+ }
+
+ virtual void addNull(const QString &name)
+ {
+ QJsonObject o;
+ addHandle(name, o, QStringLiteral("null"));
+ }
+
+ virtual void addBoolean(const QString &name, bool value)
+ {
+ QJsonObject o;
+ o[QLatin1String("value")] = value;
+ addHandle(name, o, QStringLiteral("boolean"));
+ }
+
+ virtual void addString(const QString &name, const QString &value)
+ {
+ QJsonObject o;
+ o[QLatin1String("value")] = value;
+ addHandle(name, o, QStringLiteral("string"));
+ }
+
+ virtual void addObject(const QString &name, QV4::ValueRef value)
+ {
+ QV4::Scope scope(engine());
+ QV4::ScopedObject obj(scope, value->asObject());
+
+ int ref = cachedObjectRef(obj.getPointer());
+ if (ref != -1) {
+ addNameRefPair(name, ref);
+ } else {
+ int ref = newRefId();
+ cacheObjectRef(obj.getPointer(), ref);
+
+ QJsonArray properties, *prev = &properties;
+ QSet<int> used;
+ qSwap(usedRefs, used);
+ qSwap(destination, prev);
+ collect(obj);
+ qSwap(destination, prev);
+ qSwap(usedRefs, used);
+
+ QJsonObject o;
+ o[QLatin1String("properties")] = properties;
+ addHandle(name, o, QStringLiteral("object"), ref);
+ refsByHandle.insert(ref, used);
+ }
+ }
+
+ virtual void addInteger(const QString &name, int value)
+ {
+ QJsonObject o;
+ o[QLatin1String("value")] = value;
+ addHandle(name, o, QStringLiteral("number"));
+ }
+
+ virtual void addDouble(const QString &name, double value)
+ {
+ QJsonObject o;
+ o[QLatin1String("value")] = value;
+ addHandle(name, o, QStringLiteral("number"));
+ }
+
+private:
+ int addHandle(const QString &name, QJsonObject object, const QString &type, int suppliedRef = -1)
+ {
+ Q_ASSERT(destination);
+
+ object[QLatin1String("type")] = type;
+
+ QJsonDocument tmp;
+ tmp.setObject(object);
+ QByteArray key = tmp.toJson(QJsonDocument::Compact);
+
+ int ref;
+ if (suppliedRef == -1) {
+ ref = refCache.value(key, -1);
+ if (ref == -1) {
+ ref = newRefId();
+ object[QLatin1String("handle")] = ref;
+ insertRef(object, ref);
+ refCache.insert(key, ref);
+ }
+ } else {
+ ref = suppliedRef;
+ object[QLatin1String("handle")] = ref;
+ insertRef(object, ref);
+ refCache.insert(key, ref);
+ }
+
+ addNameRefPair(name, ref);
+ return ref;
+ }
+
+ void addNameRefPair(const QString &name, int ref)
+ {
+ QJsonObject nameValuePair;
+ nameValuePair[QLatin1String("name")] = name;
+ if (isProperty()) {
+ nameValuePair[QLatin1String("ref")] = ref;
+ } else {
+ QJsonObject refObj;
+ refObj[QLatin1String("ref")] = ref;
+ nameValuePair[QLatin1String("value")] = refObj;
+ }
+ destination->append(nameValuePair);
+ usedRefs.insert(ref);
+ }
+
+ int newRefId()
+ {
+ int ref = refs.count();
+ refs.insert(ref, QJsonValue());
+ return ref;
+ }
+
+ void insertRef(const QJsonValue &value, int refId)
+ {
+ if (refId < 0)
+ refId = -refId;
+
+ refs.insert(refId, value);
+ refsToInclude.append(value);
+ }
+
+ void cacheObjectRef(QV4::Object *obj, int ref)
+ {
+ objectRefs.insert(obj, ref);
+ }
+
+ int cachedObjectRef(QV4::Object *obj) const
+ {
+ return objectRefs.value(obj, -1);
+ }
+
+private:
+ QJsonArray refsToInclude;
+ QHash<int, QJsonValue> refs;
+ QHash<QByteArray, int> refCache;
+ QJsonArray *destination;
+ QSet<int> usedRefs;
+ QHash<int, QSet<int> > refsByHandle;
+ QHash<QV4::Object *, int> objectRefs;
};
class QV4DebugServicePrivate : public QQmlDebugServicePrivate
@@ -74,20 +363,35 @@ class QV4DebugServicePrivate : public QQmlDebugServicePrivate
Q_DECLARE_PUBLIC(QV4DebugService)
public:
- QV4DebugServicePrivate() : version(1) {}
+ QV4DebugServicePrivate();
+ ~QV4DebugServicePrivate() { qDeleteAll(handlers.values()); }
- static QByteArray packMessage(const QByteArray &command, int querySequence, const QByteArray &message = QByteArray())
+ static QByteArray packMessage(const QByteArray &command, const QByteArray &message = QByteArray())
{
QByteArray reply;
QQmlDebugStream rs(&reply, QIODevice::WriteOnly);
- const QByteArray cmd("V4DEBUG");
- rs << cmd << QByteArray::number(++sequence) << QByteArray::number(querySequence) << command << message;
+ static const QByteArray cmd("V8DEBUG");
+ rs << cmd << command << message;
return reply;
}
+ void send(QJsonObject v8Payload)
+ {
+ v8Payload[QLatin1String("seq")] = sequence++;
+ QJsonDocument doc;
+ doc.setObject(v8Payload);
+#ifdef NO_PROTOCOL_TRACING
+ QByteArray responseData = doc.toJson(QJsonDocument::Compact);
+#else
+ QByteArray responseData = doc.toJson(QJsonDocument::Indented);
+#endif
+
+ TRACE_PROTOCOL(debug << "sending response for: " << responseData << endl);
+
+ q_func()->sendMessage(packMessage("v8message", responseData));
+ }
+
void processCommand(const QByteArray &command, const QByteArray &data);
- void addBreakpoint(const QByteArray &data);
- void removeBreakpoint(const QByteArray &data);
QMutex initializeMutex;
QWaitCondition initializeCondition;
@@ -98,14 +402,605 @@ public:
static int debuggerIndex;
static int sequence;
const int version;
+
+ V8CommandHandler *v8CommandHandler(const QString &command) const;
+
+ void clearHandles(QV4::ExecutionEngine *engine)
+ {
+ collector.reset(new VariableCollector(engine));
+ }
+
+ QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
+ QV4::Debugging::Debugger *debugger)
+ {
+ QJsonObject frame;
+ frame[QLatin1String("index")] = frameNr;
+ frame[QLatin1String("debuggerFrame")] = false;
+ frame[QLatin1String("func")] = collector->addFunctionRef(stackFrame.function);
+ frame[QLatin1String("script")] = collector->addScriptRef(stackFrame.source);
+ frame[QLatin1String("line")] = stackFrame.line - 1;
+ if (stackFrame.column >= 0)
+ frame[QLatin1String("column")] = stackFrame.column;
+
+ QJsonArray properties;
+ collector->setDestination(&properties);
+ if (debugger->collectThisInContext(collector.data(), frameNr)) {
+ QJsonObject obj;
+ obj[QLatin1String("properties")] = properties;
+ frame[QLatin1String("receiver")] = collector->addObjectRef(obj, false);
+ }
+
+ QJsonArray scopes;
+ // Only type and index are used by Qt Creator, so we keep it easy:
+ QVector<QV4::ExecutionContext::Type> scopeTypes = debugger->getScopeTypes(frameNr);
+ for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) {
+ int type = encodeScopeType(scopeTypes[i]);
+ if (type == -1)
+ continue;
+
+ QJsonObject scope;
+ scope[QLatin1String("index")] = i;
+ scope[QLatin1String("type")] = type;
+ scopes.push_back(scope);
+ }
+ frame[QLatin1String("scopes")] = scopes;
+
+ return frame;
+ }
+
+ int encodeScopeType(QV4::ExecutionContext::Type scopeType)
+ {
+ switch (scopeType) {
+ case QV4::ExecutionContext::Type_GlobalContext:
+ return 0;
+ break;
+ case QV4::ExecutionContext::Type_CatchContext:
+ return 4;
+ break;
+ case QV4::ExecutionContext::Type_WithContext:
+ return 2;
+ break;
+ case QV4::ExecutionContext::Type_SimpleCallContext:
+ case QV4::ExecutionContext::Type_CallContext:
+ return 1;
+ break;
+ case QV4::ExecutionContext::Type_QmlContext:
+ default:
+ return -1;
+ }
+ }
+
+ QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::Debugger *debugger)
+ {
+ QJsonObject scope;
+
+ QJsonArray properties;
+ collector->collectScope(&properties, debugger, frameNr, scopeNr);
+
+ QJsonObject anonymous;
+ anonymous[QLatin1String("properties")] = properties;
+
+ QVector<QV4::ExecutionContext::Type> scopeTypes = debugger->getScopeTypes(frameNr);
+ scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
+ scope[QLatin1String("index")] = scopeNr;
+ scope[QLatin1String("frameIndex")] = frameNr;
+ scope[QLatin1String("object")] = collector->addObjectRef(anonymous, true);
+
+ return scope;
+ }
+
+ QJsonValue lookup(int refId) const { return collector->lookup(refId); }
+
+ QJsonArray buildRefs()
+ {
+ return collector->retrieveRefsToInclude();
+ }
+
+ void selectFrame(int frameNr)
+ { theSelectedFrame = frameNr; }
+
+ int selectedFrame() const
+ { return theSelectedFrame; }
+
+private:
+ QScopedPointer<VariableCollector> collector;
+ int theSelectedFrame;
+
+ void addHandler(V8CommandHandler* handler);
+ QHash<QString, V8CommandHandler*> handlers;
+ QScopedPointer<UnknownV8CommandHandler> unknownV8CommandHandler;
};
int QV4DebugServicePrivate::debuggerIndex = 0;
int QV4DebugServicePrivate::sequence = 0;
+class V8CommandHandler
+{
+public:
+ V8CommandHandler(const QString &command)
+ : cmd(command)
+ {}
+
+ virtual ~V8CommandHandler()
+ {}
+
+ QString command() const { return cmd; }
+
+ void handle(const QJsonObject &request, QQmlDebugService *s, QV4DebugServicePrivate *p)
+ {
+ TRACE_PROTOCOL(debug << "handling command " << command() << "..." << endl);
+
+ req = request;
+ seq = req.value(QStringLiteral("seq"));
+ debugService = s;
+ debugServicePrivate = p;
+
+ handleRequest();
+ if (!response.isEmpty()) {
+ response[QLatin1String("type")] = QStringLiteral("response");
+ debugServicePrivate->send(response);
+ }
+
+ debugServicePrivate = 0;
+ debugService = 0;
+ seq = QJsonValue();
+ req = QJsonObject();
+ response = QJsonObject();
+ }
+
+ virtual void handleRequest() = 0;
+
+protected:
+ void addCommand() { response.insert(QStringLiteral("command"), cmd); }
+ void addRequestSequence() { response.insert(QStringLiteral("request_seq"), seq); }
+ void addSuccess(bool success) { response.insert(QStringLiteral("success"), success); }
+ void addBody(const QJsonObject &body)
+ {
+ response.insert(QStringLiteral("body"), body);
+ }
+
+ void addRunning()
+ {
+ response.insert(QStringLiteral("running"), debugServicePrivate->debuggerAgent.isRunning());
+ }
+
+ void addRefs()
+ {
+ response.insert(QStringLiteral("refs"), debugServicePrivate->buildRefs());
+ }
+
+ void createErrorResponse(const QString &msg)
+ {
+ QJsonValue command = req.value(QStringLiteral("command"));
+ response.insert(QStringLiteral("command"), command);
+ addRequestSequence();
+ addSuccess(false);
+ addRunning();
+ response.insert(QStringLiteral("message"), msg);
+ }
+
+ int requestSequenceNr() const
+ { return seq.toInt(-1); }
+
+protected:
+ QString cmd;
+ QJsonObject req;
+ QJsonValue seq;
+ QQmlDebugService *debugService;
+ QV4DebugServicePrivate *debugServicePrivate;
+ QJsonObject response;
+};
+
+class UnknownV8CommandHandler: public V8CommandHandler
+{
+public:
+ UnknownV8CommandHandler(): V8CommandHandler(QString()) {}
+
+ virtual void handleRequest()
+ {
+ QString msg = QStringLiteral("unimplemented command \"");
+ msg += req.value(QStringLiteral("command")).toString();
+ msg += QStringLiteral("\"");
+ createErrorResponse(msg);
+ }
+};
+
+namespace {
+class V8VersionRequest: public V8CommandHandler
+{
+public:
+ V8VersionRequest(): V8CommandHandler(QStringLiteral("version")) {}
+
+ virtual void handleRequest()
+ {
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ QJsonObject body;
+ body.insert(QStringLiteral("V8Version"),
+ QStringLiteral("this is not V8, this is V4 in Qt %1").arg(QLatin1String(QT_VERSION_STR)));
+ addBody(body);
+ }
+};
+
+class V8SetBreakPointRequest: public V8CommandHandler
+{
+public:
+ V8SetBreakPointRequest(): V8CommandHandler(QStringLiteral("setbreakpoint")) {}
+
+ virtual void handleRequest()
+ {
+ // decypher the payload:
+ QJsonObject args = req.value(QStringLiteral("arguments")).toObject();
+ if (args.isEmpty())
+ return;
+
+ QString type = args.value(QStringLiteral("type")).toString();
+ if (type != QStringLiteral("scriptRegExp")) {
+ createErrorResponse(QStringLiteral("breakpoint type \"%1\" is not implemented").arg(type));
+ return;
+ }
+
+ QString fileName = args.value(QStringLiteral("target")).toString();
+ if (fileName.isEmpty()) {
+ createErrorResponse(QStringLiteral("breakpoint has no file name"));
+ return;
+ }
+
+ int line = args.value(QStringLiteral("line")).toInt(-1);
+ if (line < 0) {
+ createErrorResponse(QStringLiteral("breakpoint has an invalid line number"));
+ return;
+ }
+
+ bool enabled = args.value(QStringLiteral("enabled")).toBool(true);
+ QString condition = args.value(QStringLiteral("condition")).toString();
+
+ // set the break point:
+ int id = debugServicePrivate->debuggerAgent.addBreakPoint(fileName, line + 1, enabled, condition);
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ QJsonObject body;
+ body.insert(QStringLiteral("type"), type);
+ body.insert(QStringLiteral("breakpoint"), id);
+ // It's undocumented, but V8 sends back an actual_locations array too. However, our
+ // Debugger currently doesn't tell us when it resolved a breakpoint, so we'll leave them
+ // pending until the breakpoint is hit for the first time.
+ addBody(body);
+ }
+};
+
+class V8ClearBreakPointRequest: public V8CommandHandler
+{
+public:
+ V8ClearBreakPointRequest(): V8CommandHandler(QStringLiteral("clearbreakpoint")) {}
+
+ virtual void handleRequest()
+ {
+ // decypher the payload:
+ QJsonObject args = req.value(QStringLiteral("arguments")).toObject();
+ if (args.isEmpty())
+ return;
+
+ int id = args.value(QStringLiteral("breakpoint")).toInt(-1);
+ if (id < 0) {
+ createErrorResponse(QStringLiteral("breakpoint has an invalid number"));
+ return;
+ }
+
+ // remove the break point:
+ debugServicePrivate->debuggerAgent.removeBreakPoint(id);
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ QJsonObject body;
+ body.insert(QStringLiteral("type"), QStringLiteral("scriptRegExp"));
+ body.insert(QStringLiteral("breakpoint"), id);
+ addBody(body);
+ }
+};
+
+class V8BacktraceRequest: public V8CommandHandler
+{
+public:
+ V8BacktraceRequest(): V8CommandHandler(QStringLiteral("backtrace")) {}
+
+ virtual void handleRequest()
+ {
+ // decypher the payload:
+
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ int fromFrame = arguments.value(QStringLiteral("fromFrame")).toInt(0);
+ int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10);
+ // no idea what the bottom property is for, so we'll ignore it.
+
+ QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
+
+ QJsonArray frameArray;
+ QVector<QV4::StackFrame> frames = debugger->stackTrace(toFrame);
+ for (int i = fromFrame; i < toFrame && i < frames.size(); ++i)
+ frameArray.push_back(debugServicePrivate->buildFrame(frames[i], i, debugger));
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ QJsonObject body;
+ if (frameArray.isEmpty()) {
+ body.insert(QStringLiteral("totalFrames"), 0);
+ } else {
+ body.insert(QStringLiteral("fromFrame"), fromFrame);
+ body.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size());
+ body.insert(QStringLiteral("frames"), frameArray);
+ }
+ addBody(body);
+ addRefs();
+ }
+};
+
+class V8FrameRequest: public V8CommandHandler
+{
+public:
+ V8FrameRequest(): V8CommandHandler(QStringLiteral("frame")) {}
+
+ virtual void handleRequest()
+ {
+ // decypher the payload:
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ const int frameNr = arguments.value(QStringLiteral("number")).toInt(debugServicePrivate->selectedFrame());
+
+ QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
+ QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
+ if (frameNr < 0 || frameNr >= frames.size()) {
+ createErrorResponse(QStringLiteral("frame command has invalid frame number"));
+ return;
+ }
+
+ debugServicePrivate->selectFrame(frameNr);
+ QJsonObject frame = debugServicePrivate->buildFrame(frames[frameNr], frameNr, debugger);
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(frame);
+ addRefs();
+ }
+};
+
+class V8ScopeRequest: public V8CommandHandler
+{
+public:
+ V8ScopeRequest(): V8CommandHandler(QStringLiteral("scope")) {}
+
+ virtual void handleRequest()
+ {
+ // decypher the payload:
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ const int frameNr = arguments.value(QStringLiteral("frameNumber")).toInt(debugServicePrivate->selectedFrame());
+ const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0);
+
+ QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
+ QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
+ if (frameNr < 0 || frameNr >= frames.size()) {
+ createErrorResponse(QStringLiteral("scope command has invalid frame number"));
+ return;
+ }
+ if (scopeNr < 0) {
+ createErrorResponse(QStringLiteral("scope command has invalid scope number"));
+ return;
+ }
+
+ QJsonObject scope = debugServicePrivate->buildScope(frameNr, scopeNr, debugger);
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(scope);
+ addRefs();
+ }
+};
+
+class V8LookupRequest: public V8CommandHandler
+{
+public:
+ V8LookupRequest(): V8CommandHandler(QStringLiteral("lookup")) {}
+
+ virtual void handleRequest()
+ {
+ // decypher the payload:
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray();
+
+ QJsonObject body;
+ foreach (QJsonValue handle, handles)
+ body[QString::number(handle.toInt())] = debugServicePrivate->lookup(handle.toInt());
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(body);
+ addRefs();
+ }
+};
+
+class V8ContinueRequest: public V8CommandHandler
+{
+public:
+ V8ContinueRequest(): V8CommandHandler(QStringLiteral("continue")) {}
+
+ virtual void handleRequest()
+ {
+ // decypher the payload:
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+
+ QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
+
+ if (arguments.empty()) {
+ debugger->resume(QV4::Debugging::Debugger::FullThrottle);
+ } else {
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ QString stepAction = arguments.value(QStringLiteral("stepaction")).toString();
+ const int stepcount = arguments.value(QStringLiteral("stepcount")).toInt(1);
+ if (stepcount != 1)
+ qWarning() << "Step count other than 1 is not supported.";
+
+ if (stepAction == QStringLiteral("in")) {
+ debugger->resume(QV4::Debugging::Debugger::StepIn);
+ } else if (stepAction == QStringLiteral("out")) {
+ debugger->resume(QV4::Debugging::Debugger::StepOut);
+ } else if (stepAction == QStringLiteral("next")) {
+ debugger->resume(QV4::Debugging::Debugger::StepOver);
+ } else {
+ createErrorResponse(QStringLiteral("continue command has invalid stepaction"));
+ return;
+ }
+ }
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ }
+};
+
+class V8DisconnectRequest: public V8CommandHandler
+{
+public:
+ V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {}
+
+ virtual void handleRequest()
+ {
+ debugServicePrivate->debuggerAgent.removeAllBreakPoints();
+ debugServicePrivate->debuggerAgent.resumeAll();
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ }
+};
+
+class V8SetExceptionBreakRequest: public V8CommandHandler
+{
+public:
+ V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {}
+
+ virtual void handleRequest()
+ {
+ bool wasEnabled = debugServicePrivate->debuggerAgent.breakOnThrow();
+
+ //decypher the payload:
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ QString type = arguments.value(QStringLiteral("type")).toString();
+ bool enabled = arguments.value(QStringLiteral("number")).toBool(!wasEnabled);
+
+ if (type == QStringLiteral("all")) {
+ // that's fine
+ } else if (type == QStringLiteral("uncaught")) {
+ createErrorResponse(QStringLiteral("breaking only on uncaught exceptions is not supported yet"));
+ return;
+ } else {
+ createErrorResponse(QStringLiteral("invalid type for break on exception"));
+ return;
+ }
+
+ // do it:
+ debugServicePrivate->debuggerAgent.setBreakOnThrow(enabled);
+
+ QJsonObject body;
+ body[QLatin1String("type")] = type;
+ body[QLatin1String("enabled")] = debugServicePrivate->debuggerAgent.breakOnThrow();
+
+ // response:
+ addBody(body);
+ addRunning();
+ addSuccess(true);
+ addRequestSequence();
+ addCommand();
+ }
+};
+
+class V8ScriptsRequest: public V8CommandHandler
+{
+public:
+ V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {}
+
+ virtual void handleRequest()
+ {
+ //decypher the payload:
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ int types = arguments.value(QStringLiteral("types")).toInt(-1);
+ if (types < 0 || types > 7) {
+ createErrorResponse(QStringLiteral("invalid types value in scripts command"));
+ return;
+ } else if (types != 4) {
+ createErrorResponse(QStringLiteral("unsupported types value in scripts command"));
+ return;
+ }
+
+ // do it:
+ debugServicePrivate->debuggerAgent.firstDebugger()->gatherSources(requestSequenceNr());
+
+ // response will be send by
+ }
+};
+} // anonymous namespace
+
+QV4DebugServicePrivate::QV4DebugServicePrivate()
+ : debuggerAgent(this)
+ , version(1)
+ , theSelectedFrame(0)
+ , unknownV8CommandHandler(new UnknownV8CommandHandler)
+{
+ addHandler(new V8VersionRequest);
+ addHandler(new V8SetBreakPointRequest);
+ addHandler(new V8ClearBreakPointRequest);
+ addHandler(new V8BacktraceRequest);
+ addHandler(new V8FrameRequest);
+ addHandler(new V8ScopeRequest);
+ addHandler(new V8LookupRequest);
+ addHandler(new V8ContinueRequest);
+ addHandler(new V8DisconnectRequest);
+ addHandler(new V8SetExceptionBreakRequest);
+ addHandler(new V8ScriptsRequest);
+
+ // TODO: evaluate
+}
+
+void QV4DebugServicePrivate::addHandler(V8CommandHandler* handler)
+{
+ handlers[handler->command()] = handler;
+}
+
+V8CommandHandler *QV4DebugServicePrivate::v8CommandHandler(const QString &command) const
+{
+ V8CommandHandler *handler = handlers.value(command, 0);
+ if (handler)
+ return handler;
+ else
+ return unknownV8CommandHandler.data();
+}
+
QV4DebugService::QV4DebugService(QObject *parent)
: QQmlDebugService(*(new QV4DebugServicePrivate()),
- QStringLiteral("V4Debugger"), 1, parent)
+ QStringLiteral("V8Debugger"), 1, parent)
{
Q_D(QV4DebugService);
@@ -130,13 +1025,18 @@ QV4DebugService *QV4DebugService::instance()
void QV4DebugService::addEngine(const QQmlEngine *engine)
{
Q_D(QV4DebugService);
+
if (engine) {
QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
- if (ee) {
- ee->enableDebugger();
- QV4::Debugging::Debugger *debugger = ee->debugger;
- d->debuggerMap.insert(d->debuggerIndex++, debugger);
- d->debuggerAgent.addDebugger(debugger);
+ if (QQmlDebugServer *server = QQmlDebugServer::instance()) {
+ if (ee) {
+ ee->enableDebugger();
+ QV4::Debugging::Debugger *debugger = ee->debugger;
+ d->debuggerMap.insert(d->debuggerIndex++, debugger);
+ d->debuggerAgent.addDebugger(debugger);
+ d->debuggerAgent.moveToThread(server->thread());
+ moveToThread(server->thread());
+ }
}
}
}
@@ -201,125 +1101,129 @@ void QV4DebugService::messageReceived(const QByteArray &message)
QByteArray header;
ms >> header;
- if (header == "V4DEBUG") {
- QByteArray sequenceValue;
- QByteArray command;
- QByteArray data;
- ms >> sequenceValue >> command >> data;
+ TRACE_PROTOCOL(debug << "received message with header " << header << endl);
- QQmlDebugStream ds(data);
+ if (header == "V8DEBUG") {
+ QByteArray type;
+ QByteArray payload;
+ ms >> type >> payload;
+ TRACE_PROTOCOL(debug << "... type: "<<type << endl);
- QByteArray versionValue;
- QByteArray debuggerValue;
- ds >> versionValue >> debuggerValue; // unused for now
-
- int querySequence = sequenceValue.toInt();
- if (command == V4_BREAK_ON_SIGNAL) {
+ if (type == V4_CONNECT) {
+ sendMessage(d->packMessage(type));
+ d->initializeCondition.wakeAll();
+ } else if (type == V4_PAUSE) {
+ d->debuggerAgent.pauseAll();
+ sendSomethingToSomebody(type);
+ } else if (type == V4_BREAK_ON_SIGNAL) {
QByteArray signal;
bool enabled;
- ds >> signal >> enabled;
+ ms >> signal >> enabled;
//Normalize to lower case.
QString signalName(QString::fromUtf8(signal).toLower());
if (enabled)
d->breakOnSignals.append(signalName);
else
d->breakOnSignals.removeOne(signalName);
- } else if (command == V4_ADD_BREAKPOINT) {
- QMetaObject::invokeMethod(this, "addBreakpoint", Qt::QueuedConnection,
- Q_ARG(QByteArray, data), Q_ARG(int, querySequence));
- } else if (command == V4_REMOVE_BREAKPOINT) {
- QMetaObject::invokeMethod(this, "removeBreakpoint", Qt::QueuedConnection,
- Q_ARG(QByteArray, data), Q_ARG(int, querySequence));
- } else if (command == V4_PAUSE) {
- int id = ds.atEnd() ? debuggerValue.toInt() : -1;
- QMetaObject::invokeMethod(this, "pause", Qt::QueuedConnection, Q_ARG(int, id),
- Q_ARG(int, querySequence));
- } else if (command == V4_CONNECT) {
- QByteArray response;
- QQmlDebugStream rs(&response, QIODevice::WriteOnly);
- rs << QByteArray::number(d->version) << QByteArray::number(1);
- sendMessage(d->packMessage(command, sequenceValue.toInt(), response));
-
- d->initializeCondition.wakeAll();
+ } else if (type == "v8request") {
+ handleV8Request(payload);
+ } else if (type == V4_DISCONNECT) {
+ TRACE_PROTOCOL(debug << "... payload:"<<payload << endl);
+ handleV8Request(payload);
} else {
- QByteArray response;
- QQmlDebugStream rs(&response, QIODevice::WriteOnly);
- rs << QByteArray::number(d->version) << QByteArray::number(0);
- sendMessage(d->packMessage(command, sequenceValue.toInt(), response));
+ sendSomethingToSomebody(type, 0);
}
}
}
-void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger)
+void QV4DebugService::sendSomethingToSomebody(const char *type, int magicNumber)
{
- QByteArray data;
- QQmlDebugStream message(&data, QIODevice::WriteOnly);
-
- QV4::Debugging::Debugger::ExecutionState state = debugger->currentExecutionState();
- message << V4_FILENAME << state.fileName.toLatin1();
- message << V4_LINENUMBER << QByteArray().number(state.lineNumber);
-
- QV4DebugService::instance()->sendMessage(QV4DebugServicePrivate::packMessage(V4_BREAK, -1, data));
+ Q_D(QV4DebugService);
- qDebug() << Q_FUNC_INFO;
+ QByteArray response;
+ QQmlDebugStream rs(&response, QIODevice::WriteOnly);
+ rs << QByteArray(type)
+ << QByteArray::number(d->version) << QByteArray::number(magicNumber);
+ sendMessage(d->packMessage(type, response));
}
-void QV4DebugService::pause(int debuggerId, int querySequence)
+void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason)
{
- Q_D(QV4DebugService);
+ Q_UNUSED(reason);
- debuggerId == -1 ? d->debuggerAgent.pauseAll()
- : d->debuggerAgent.pause(d->debuggerMap.value(debuggerId));
- QByteArray response;
- QQmlDebugStream rs(&response, QIODevice::WriteOnly);
- rs << QByteArray::number(d->version) << QByteArray::number(1);
- sendMessage(d->packMessage(V4_PAUSE, querySequence, response));
+ debugServicePrivate->clearHandles(debugger->engine());
+
+ QJsonObject event, body, script;
+ event.insert(QStringLiteral("type"), QStringLiteral("event"));
+
+ switch (reason) {
+ case QV4::Debugging::Step:
+ case QV4::Debugging::PauseRequest:
+ case QV4::Debugging::BreakPoint: {
+ event.insert(QStringLiteral("event"), QStringLiteral("break"));
+ QVector<QV4::StackFrame> frames = debugger->stackTrace(1);
+ if (frames.isEmpty())
+ break;
+
+ const QV4::StackFrame &topFrame = frames.first();
+ body.insert(QStringLiteral("invocationText"), topFrame.function);
+ body.insert(QStringLiteral("sourceLine"), topFrame.line - 1);
+ if (topFrame.column > 0)
+ body.insert(QStringLiteral("sourceColumn"), topFrame.column);
+ QJsonArray breakPoints;
+ foreach (int breakPointId, breakPointIds(topFrame.source, topFrame.line))
+ breakPoints.push_back(breakPointId);
+ body.insert(QStringLiteral("breakpoints"), breakPoints);
+ script.insert(QStringLiteral("name"), topFrame.source);
+ } break;
+ case QV4::Debugging::Throwing:
+ // TODO: complete this!
+ event.insert(QStringLiteral("event"), QStringLiteral("exception"));
+ break;
+ }
+
+ if (!script.isEmpty())
+ body.insert(QStringLiteral("script"), script);
+ if (!body.isEmpty())
+ event.insert(QStringLiteral("body"), body);
+ debugServicePrivate->send(event);
}
-void QV4DebugService::addBreakpoint(const QByteArray &data, int querySequence)
+void QV4DebuggerAgent::sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, int requestSequenceNr)
{
- Q_D(QV4DebugService);
+ QJsonArray body;
+ foreach (const QString source, sources) {
+ QJsonObject src;
+ src[QLatin1String("name")] = source;
+ src[QLatin1String("scriptType")] = 4;
+ body.append(src);
+ }
- QQmlDebugStream ds(data);
- QString fileName;
- int lineNumber = -1;
- while (!ds.atEnd()) {
- QByteArray key;
- QByteArray value;
- ds >> key >> value;
- if (key == V4_FILENAME)
- fileName = QString::fromLatin1(value);
- else if (key == V4_LINENUMBER)
- lineNumber = value.toInt();
- }
- d->debuggerAgent.addBreakPoint(fileName, lineNumber);
- QByteArray response;
- QQmlDebugStream rs(&response, QIODevice::WriteOnly);
- rs << QByteArray::number(d->version) << QByteArray::number(1);
- sendMessage(d->packMessage(V4_ADD_BREAKPOINT, querySequence, response));
+ QJsonObject response;
+ response[QLatin1String("success")] = true;
+ response[QLatin1String("running")] = debugger->state() == QV4::Debugging::Debugger::Running;
+ response[QLatin1String("body")] = body;
+ response[QLatin1String("command")] = QStringLiteral("scripts");
+ response[QLatin1String("request_seq")] = requestSequenceNr;
+ response[QLatin1String("type")] = QStringLiteral("response");
+ debugServicePrivate->send(response);
}
-void QV4DebugService::removeBreakpoint(const QByteArray &data, int querySequence)
+void QV4DebugService::handleV8Request(const QByteArray &payload)
{
Q_D(QV4DebugService);
- QQmlDebugStream ds(data);
- QString fileName;
- int lineNumber = -1;
- while (!ds.atEnd()) {
- QByteArray key;
- QByteArray value;
- ds >> key >> value;
- if (key == V4_FILENAME)
- fileName = QString::fromLatin1(value);
- else if (key == V4_LINENUMBER)
- lineNumber = value.toInt();
- }
- d->debuggerAgent.removeBreakPoint(fileName, lineNumber);
- QByteArray response;
- QQmlDebugStream rs(&response, QIODevice::WriteOnly);
- rs << QByteArray::number(d->version) << QByteArray::number(1);
- sendMessage(d->packMessage(V4_REMOVE_BREAKPOINT, querySequence, response));
+ TRACE_PROTOCOL(debug << "v8request, payload: " << payload << endl);
+
+ QJsonDocument request = QJsonDocument::fromJson(payload);
+ QJsonObject o = request.object();
+ QJsonValue type = o.value(QStringLiteral("type"));
+ if (type.toString() == QStringLiteral("request")) {
+ QJsonValue command = o.value(QStringLiteral("command"));
+ V8CommandHandler *h = d->v8CommandHandler(command.toString());
+ if (h)
+ h->handle(o, this, d);
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qv4debugservice_p.h b/src/qml/debugger/qv4debugservice_p.h
index a89b009c7f..e35010bebf 100644
--- a/src/qml/debugger/qv4debugservice_p.h
+++ b/src/qml/debugger/qv4debugservice_p.h
@@ -57,7 +57,7 @@
QT_BEGIN_NAMESPACE
-namespace QV4 { class ExecutionEngine; }
+namespace QV4 { struct ExecutionEngine; }
class QQmlEngine;
class QV4DebugServicePrivate;
@@ -77,11 +77,10 @@ public:
protected:
void stateChanged(State newState);
void messageReceived(const QByteArray &);
+ void sendSomethingToSomebody(const char *type, int magicNumber = 1);
-private slots:
- void pause(int debuggerId, int querySequence);
- void addBreakpoint(const QByteArray &data, int querySequence);
- void removeBreakpoint(const QByteArray &data, int querySequence);
+private:
+ void handleV8Request(const QByteArray &payload);
private:
Q_DISABLE_COPY(QV4DebugService)
diff --git a/src/qml/debugger/qv8profilerservice.cpp b/src/qml/debugger/qv8profilerservice.cpp
index 33d6747b3b..7b9331da66 100644
--- a/src/qml/debugger/qv8profilerservice.cpp
+++ b/src/qml/debugger/qv8profilerservice.cpp
@@ -247,7 +247,7 @@ void QV8ProfilerService::stopProfiling(const QString &title)
void QV8ProfilerService::takeSnapshot()
{
- Q_D(QV8ProfilerService);
+// Q_D(QV8ProfilerService);
// ### FIXME: v4
// d->takeSnapshot(v8::HeapSnapshot::kFull);
}
@@ -260,7 +260,7 @@ void QV8ProfilerService::deleteSnapshots()
void QV8ProfilerService::sendProfilingData()
{
- Q_D(QV8ProfilerService);
+// Q_D(QV8ProfilerService);
// Send messages to client
// ### FIXME: v4
// d->sendMessages();
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index da596a1d97..1b11fa1bf7 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -2,7 +2,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtQml
description = Qt QML Reference Documentation
-url = http://qt-project.org/doc/qt-$QT_VER/qtqml
+url = http://qt-project.org/doc/qt-$QT_VER
version = $QT_VERSION
examplesinstallpath = qml
diff --git a/src/qml/doc/src/cppintegration/contextproperties.qdoc b/src/qml/doc/src/cppintegration/contextproperties.qdoc
index abdc18981a..d30cc87345 100644
--- a/src/qml/doc/src/cppintegration/contextproperties.qdoc
+++ b/src/qml/doc/src/cppintegration/contextproperties.qdoc
@@ -91,7 +91,7 @@ following examples:
\li \l {Models and Views: AbstractItemModel Example}{AbstractItemModel}
\endlist
-demonstrating the use of QStringList, \l{QList<QObject*>}-based models and
+demonstrating the use of QStringList, QList<QObject*>-based models and
QAbstractItemModel in QML views.
Also see the QQmlContext documentation for more information.
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 8bad77ebab..68233747b7 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -59,7 +59,7 @@ instance which already has a parent.
\section1 Basic Qt Data Types
By default, QML recognizes the following Qt data types, which are
-automatically converted to a corresponding \l {QML Basic Type}{QML basic type}
+automatically converted to a corresponding \l {QML Basic Types}{QML basic type}
when passed from C++ to QML and vice-versa:
\table
@@ -83,7 +83,7 @@ when passed from C++ to QML and vice-versa:
\li \l string
\row
\li QUrl
- \li real
+ \li \l url
\row
\li QColor
\li \l color
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 995fb1bce8..187e4fc7b4 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -699,7 +699,7 @@ its properties have been set. For example, this may be the case if the
initialization is costly, or if the initialization should not be performed until
all property values have been initialized.
-The \l {Qt QML} module provides the QQmlParserStatus to be subclass for these
+The \l {Qt QML} module provides the QQmlParserStatus to be subclassed for these
purposes. It defines a number of virtual methods that are invoked invoked at
various stages during component instantiation. To receive these notifications, a
C++ class should inherit QQmlParserStatus and also notify the Qt meta system
diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc
index 4d12ab9d08..67e76e3e5e 100644
--- a/src/qml/doc/src/cppintegration/topic.qdoc
+++ b/src/qml/doc/src/cppintegration/topic.qdoc
@@ -98,7 +98,7 @@ more information.
\section1 Defining QML Types from C++
QML types can be defined in C++ and then registered with the \l{qtqml-typesystem-topic.html}{QML
-type system}. This allows a C++ class to be instantiated as a \l {QML object type}, enabling custom
+type system}. This allows a C++ class to be instantiated as a \l {QML Object Types}{QML object type}, enabling custom
object types to be implemented in C++ and integrated into existing QML code. A C++ class may be also
registered for other purposes: for example, it could be registered as a \e {Singleton Type} to enable a
single class instance to be imported by QML code, or it could be registered to enable the
diff --git a/src/qml/doc/src/javascript/expressions.qdoc b/src/qml/doc/src/javascript/expressions.qdoc
index a8e6fc8ac0..13238b2e43 100644
--- a/src/qml/doc/src/javascript/expressions.qdoc
+++ b/src/qml/doc/src/javascript/expressions.qdoc
@@ -71,7 +71,7 @@ logic. There are four ways that JavaScript can be used in a QML document:
\li \l{Method Attributes}{custom methods} can be defined
in QML files as JavaScript functions
\li JavaScript files providing functions and variables can be
- \l{Importing JavaScript Files in QML Documents}{imported} in a QML
+ \l{Importing JavaScript Resources in QML}{imported} in a QML
document
\endlist
@@ -103,7 +103,7 @@ property binding definition, as long as the result of the expression is a
value whose type can be assigned to the property.
There are two ways to define a property binding: the first (and most common)
-is, as previously shown, in a \l{QML Object Attributes#property-initialization}
+is, as previously shown, in a \l{QML Object Attributes#Value Assignment on Initialization}
{property initialization}. The second (and much rarer) way is to assign the
property a function returned from the \l{Qt::binding()}{Qt.binding()} function,
from within imperative JavaScript code, as shown below:
@@ -259,7 +259,7 @@ Item {
\endqml
For more information about loading external JavaScript files into QML, read
-the section about \l{Importing JavaScript Files in QML Documents}.
+the section about \l{Importing JavaScript Resources in QML}.
diff --git a/src/qml/doc/src/javascript/imports.qdoc b/src/qml/doc/src/javascript/imports.qdoc
index fa9aa9794c..d70d33fee6 100644
--- a/src/qml/doc/src/javascript/imports.qdoc
+++ b/src/qml/doc/src/javascript/imports.qdoc
@@ -32,7 +32,7 @@
\l{qtqml-javascript-resources.html}{JavaScript resources} may be imported by
QML documents and other JavaScript resources. JavaScript resources may be
imported via either relative or absolute URLs. In the case of a relative URL,
-the location is resolved relative to the location of the \l {QML Document} or
+the location is resolved relative to the location of the \l {QML Documents}{QML document} or
\l{qtqml-javascript-resources.html}{JavaScript Resource} that contains the
import. If the script file is not accessible, an error will occur. If the
JavaScript needs to be fetched from a network resource, the component's
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index b4b8fce162..679f7bac96 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -398,6 +398,55 @@
*/
/*!
+ \fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+ \relates QQmlEngine
+
+ This function may be used to register a singleton type with the name \a qmlName, in the library imported from \a uri having
+ the version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url.
+ The url must be an absolute URL, i.e. url.isRelative() == false.
+
+ In addition the type's QML file must have pragma Singleton statement among its import statements.
+
+ A singleton type may be referenced via the type name with which it was registered, and this typename may be used as the
+ target in a \l Connections type or otherwise used as any other type id would. One exception to this is that a singleton
+ type property may not be aliased (because the singleton type name does not identify an object within the same component
+ as any other item).
+
+ Usage:
+ // First, define your QML singleton type which provides the functionality.
+ \qml
+ pragma Singleton
+ import QtQuick 2.0
+ Item {
+ property int testProp1: 125
+ }
+ \endqml
+
+ \code
+ // Second, register the QML singleton type by calling this function in an initialization function.
+ #include <QtQml>
+ ...
+ qmlRegisterSingletonType(QUrl("file:///absolute/path/SingletonType.qml"), "Qt.example.qobjectSingleton", 1, 0, "RegisteredSingleton");
+ ...
+ \endcode
+
+ In order to use the registered singleton type in QML, you must import the singleton type.
+ \qml
+ import QtQuick 2.0
+ import Qt.example.qobjectSingleton 1.0
+ Item {
+ id: root
+ property int someValue: RegisteredSingleton.testProp1
+ }
+ \endqml
+
+ It is also possible to have QML singleton types registered without using the qmlRegisterSingletonType function.
+ That can be done by adding a pragma Singleton statement among the imports of the type's QML file. In addition
+ the type must be defined in a qmldir file with a singleton keyword and the qmldir must be imported by the QML
+ files using the singleton.
+*/
+
+/*!
\fn int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName);
\relates QQmlEngine
diff --git a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
index 9da77a4905..870eb21a07 100644
--- a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
@@ -76,7 +76,7 @@ with local variables declared in another.
\section1 Type Names and Imported JavaScript Files
-\l {QML Document}s include import statements that define the type names
+\l {QML Documents} include import statements that define the type names
and JavaScript files visible to the document. In addition to their use in the
QML declaration itself, type names are used by JavaScript code when accessing
\l {Attached Properties} and enumeration values.
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index f592a18bb0..61d4e67acb 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -111,36 +111,6 @@ to a \l{QtQml::Date}{Date} object.
*/
/*!
-\qmlbasictype time
-\ingroup qtqmlbasictypes
-\ingroup qtquickbasictypes
-\brief a time value.
-
-The \c time type refers to a time value.
-
-To create a \c time value, specified as "hh:mm:ss":
-
-\qml
-MyTimePicker { time: "14:22:15" }
-\endqml
-
-To read a time value returned from a C++ extension class, use
-\l{QtQml::Qt::formatTime()}{Qt.formatTime()} and \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
-
-Note that when converting historical times to and from javascript that QDateTime and the JS Date object
-have different methods of calculating historical daylight savings time application. This can lead to variations of one hour
-when converting to historical local time.
-
-When integrating with C++, note that any QTime value
-\l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
-converted into a \c time value, and vice-versa.
-
-This basic type is provided by the QML language.
-
-\sa {QML Basic Types}
-*/
-
-/*!
\qmlbasictype point
\ingroup qtqmlbasictypes
\ingroup qtquickbasictypes
diff --git a/src/qml/doc/src/whatsnew.qdoc b/src/qml/doc/src/whatsnew.qdoc
index bf457d7ee6..a0e5202174 100644
--- a/src/qml/doc/src/whatsnew.qdoc
+++ b/src/qml/doc/src/whatsnew.qdoc
@@ -40,8 +40,8 @@ a summary of the new changes:
\li The 'with' statement has been deprecated and is slated for removal in a
future version of the language.
\li New \l Qt.platform object with an os property
-\li New \l qmlClearTypeRegistations() function drops all data from qmlRegisterType calls
-\li New \l qmlRegisterType function for registering composite types.
+\li New \l qmlClearTypeRegistrations() function drops all data from qmlRegisterType() calls
+\li New \l qmlRegisterType() function for registering composite types.
\endlist
\section2 New Submodule
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index d1bd4934cd..5d8a0202fa 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -262,15 +262,15 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
QV4::Scope scope(d->m_v4Engine);
QV4::ExecutionContext *ctx = d->m_v4Engine->current;
QV4::ScopedValue result(scope);
- try {
- QV4::Script script(ctx, program, fileName, lineNumber);
- script.strictMode = ctx->strictMode;
- script.inheritContext = true;
- script.parse();
+
+ QV4::Script script(ctx, program, fileName, lineNumber);
+ script.strictMode = ctx->strictMode;
+ script.inheritContext = true;
+ script.parse();
+ if (!scope.engine->hasException)
result = script.run();
- } catch (...) {
+ if (scope.engine->hasException)
result = ctx->catchException();
- }
return new QJSValuePrivate(d->m_v4Engine, result);
}
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 29734fda92..4035fb9fa6 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -377,12 +377,12 @@ QString QJSValue::toString() const
double QJSValue::toNumber() const
{
QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
- try {
- return d->value.toNumber();
- } catch (...) {
+ double dbl = d->value.toNumber();
+ if (ctx && ctx->engine->hasException) {
ctx->catchException();
return 0;
}
+ return dbl;
}
/*!
@@ -400,12 +400,12 @@ double QJSValue::toNumber() const
bool QJSValue::toBool() const
{
QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
- try {
- return d->value.toBoolean();
- } catch (...) {
+ bool b = d->value.toBoolean();
+ if (ctx && ctx->engine->hasException) {
ctx->catchException();
return false;
}
+ return b;
}
/*!
@@ -423,12 +423,12 @@ bool QJSValue::toBool() const
qint32 QJSValue::toInt() const
{
QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
- try {
- return d->value.toInt32();
- } catch (...) {
+ qint32 i = d->value.toInt32();
+ if (ctx && ctx->engine->hasException) {
ctx->catchException();
return 0;
}
+ return i;
}
/*!
@@ -446,12 +446,12 @@ qint32 QJSValue::toInt() const
quint32 QJSValue::toUInt() const
{
QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
- try {
- return d->value.toUInt32();
- } catch (...) {
+ quint32 u = d->value.toUInt32();
+ if (ctx && ctx->engine->hasException) {
ctx->catchException();
return 0;
}
+ return u;
}
/*!
@@ -518,11 +518,9 @@ QJSValue QJSValue::call(const QJSValueList &args)
ScopedValue result(scope);
QV4::ExecutionContext *ctx = engine->current;
- try {
- result = f->call(callData);
- } catch (...) {
+ result = f->call(callData);
+ if (scope.hasException())
result = ctx->catchException();
- }
return new QJSValuePrivate(engine, result);
}
@@ -574,11 +572,9 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
ScopedValue result(scope);
QV4::ExecutionContext *ctx = engine->current;
- try {
- result = f->call(callData);
- } catch (...) {
+ result = f->call(callData);
+ if (scope.hasException())
result = ctx->catchException();
- }
return new QJSValuePrivate(engine, result);
}
@@ -622,11 +618,9 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
ScopedValue result(scope);
QV4::ExecutionContext *ctx = engine->current;
- try {
- result = f->construct(callData);
- } catch (...) {
+ result = f->construct(callData);
+ if (scope.hasException())
result = ctx->catchException();
- }
return new QJSValuePrivate(engine, result);
}
@@ -718,11 +712,12 @@ void QJSValue::setPrototype(const QJSValue& prototype)
*/
QJSValue& QJSValue::operator=(const QJSValue& other)
{
- if (d == other.d)
- return *this;
- d->deref();
- d = other.d;
- d->ref();
+ if (d != other.d) {
+ d->deref();
+ d = other.d;
+ d->ref();
+ }
+ return *this;
}
/*!
@@ -813,11 +808,10 @@ QJSValue QJSValue::property(const QString& name) const
s->makeIdentifier();
QV4::ExecutionContext *ctx = engine->current;
QV4::ScopedValue result(scope);
- try {
- result = o->get(s);
- } catch (...) {
+ result = o->get(s);
+ if (scope.hasException())
result = ctx->catchException();
- }
+
return new QJSValuePrivate(engine, result);
}
@@ -846,11 +840,9 @@ QJSValue QJSValue::property(quint32 arrayIndex) const
QV4::ExecutionContext *ctx = engine->current;
QV4::ScopedValue result(scope);
- try {
- result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex);
- } catch (...) {
+ result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex);
+ if (scope.hasException())
result = ctx->catchException();
- }
return new QJSValuePrivate(engine, result);
}
@@ -890,12 +882,10 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
QV4::ExecutionContext *ctx = engine->current;
s->makeIdentifier();
- try {
- QV4::ScopedValue v(scope, value.d->getValue(engine));
- o->put(s, v);
- } catch (...) {
+ QV4::ScopedValue v(scope, value.d->getValue(engine));
+ o->put(s, v);
+ if (scope.hasException())
ctx->catchException();
- }
}
/*!
@@ -923,14 +913,12 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
QV4::ExecutionContext *ctx = engine->current;
QV4::ScopedValue v(scope, value.d->getValue(engine));
- try {
- if (arrayIndex != UINT_MAX)
- o->putIndexed(arrayIndex, v);
- else
- o->put(engine->id_uintMax, v);
- } catch (...) {
+ if (arrayIndex != UINT_MAX)
+ o->putIndexed(arrayIndex, v);
+ else
+ o->put(engine->id_uintMax, v);
+ if (scope.hasException())
ctx->catchException();
- }
}
/*!
@@ -956,13 +944,17 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
bool QJSValue::deleteProperty(const QString &name)
{
ExecutionEngine *engine = d->engine;
+ ExecutionContext *ctx = engine->current;
Scope scope(engine);
ScopedObject o(scope, d->value.asObject());
if (!o)
return false;
ScopedString s(scope, engine->newString(name));
- return o->deleteProperty(s);
+ bool b = o->deleteProperty(s);
+ if (scope.hasException())
+ ctx->catchException();
+ return b;
}
/*!
diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp
index dcf7c4755b..245b75b384 100644
--- a/src/qml/jsapi/qjsvalueiterator.cpp
+++ b/src/qml/jsapi/qjsvalueiterator.cpp
@@ -199,21 +199,20 @@ QJSValue QJSValueIterator::value() const
QV4::ScopedObject o(scope, it->it.object);
QV4::ExecutionContext *ctx = engine->current;
- try {
- QV4::ScopedValue v(scope);
- if (!!d_ptr->currentName) {
- QV4::ScopedString n(scope, d_ptr->currentName);
- v = o->get(n);
- } else if (d_ptr->currentIndex != UINT_MAX) {
- v = o->getIndexed(d_ptr->currentIndex);
- } else {
- return QJSValue();
- }
- return new QJSValuePrivate(engine, v);
- } catch (...) {
+ QV4::ScopedValue v(scope);
+ if (!!d_ptr->currentName) {
+ QV4::ScopedString n(scope, d_ptr->currentName);
+ v = o->get(n);
+ } else if (d_ptr->currentIndex != UINT_MAX) {
+ v = o->getIndexed(d_ptr->currentIndex);
+ } else {
+ return QJSValue();
+ }
+ if (scope.hasException()) {
ctx->catchException();
return QJSValue();
}
+ return new QJSValuePrivate(engine, v);
}
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index cde26c323d..94983f51e5 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -1,7 +1,3 @@
-CONFIG += exceptions
-
-CONFIG += warn_off
-
INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
@@ -37,7 +33,6 @@ SOURCES += \
$$PWD/qv4string.cpp \
$$PWD/qv4objectiterator.cpp \
$$PWD/qv4regexp.cpp \
- $$PWD/qv4unwindhelper.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
$$PWD/qv4executableallocator.cpp \
@@ -83,9 +78,6 @@ HEADERS += \
$$PWD/qv4property_p.h \
$$PWD/qv4objectiterator_p.h \
$$PWD/qv4regexp_p.h \
- $$PWD/qv4unwindhelper_p.h \
- $$PWD/qv4unwindhelper_dw2_p.h \
- $$PWD/qv4unwindhelper_arm_p.h \
$$PWD/qv4serialize_p.h \
$$PWD/qv4script_p.h \
$$PWD/qv4scopedvalue_p.h \
@@ -104,31 +96,6 @@ linux-g++*:isEqual(QT_ARCH,i386) {
QMAKE_CXXFLAGS += -march=pentium4 -msse2 -mfpmath=sse
}
-linux*|mac {
- LIBS += -ldl
-}
-
-!win32:!ios:!mac {
- *g++*:equals(QT_ARCH, "arm") {
- static_libgcc = $$system($$QMAKE_CXX -print-file-name=libgcc.a)
- LIBS += $$static_libgcc
- }
- SOURCES += $$PWD/qv4engine_cxxabi.cpp
- DEFINES += V4_CXX_ABI_EXCEPTION
-}
-
-debug-with-libunwind {
- UW_INC=$$(LIBUNWIND_INCLUDES)
- isEmpty(UW_INC): error("Please set LIBUNWIND_INCLUDES")
- INCLUDEPATH += $$UW_INC
- UW_LIBS=$$(LIBUNWIND_LIBS)
- isEmpty(UW_LIBS): error("Please set LIBUNWIND_LIBS")
- LIBS += -L$$UW_LIBS
- equals(QT_ARCH, arm): LIBS += -lunwind-arm
- LIBS += -lunwind-dwarf-common -lunwind-dwarf-local -lunwind-elf32 -lunwind
- DEFINES += WTF_USE_LIBUNWIND_DEBUG=1
-}
-
valgrind {
DEFINES += V4_USE_VALGRIND
}
diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h
index e4580da3d8..f507d174e1 100644
--- a/src/qml/jsruntime/qv4alloca_p.h
+++ b/src/qml/jsruntime/qv4alloca_p.h
@@ -45,10 +45,12 @@
#include <qglobal.h>
#if defined(Q_OS_WIN)
-#include <malloc.h>
-#define alloca _alloca
+# include <malloc.h>
+# ifndef __GNUC__
+# define alloca _alloca
+# endif
#else
-#include <alloca.h>
+# include <alloca.h>
#endif
#endif
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 47b149c9d5..749509c353 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -47,10 +47,11 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(ArgumentsObject);
ArgumentsObject::ArgumentsObject(CallContext *context)
- : Object(context->engine), context(context)
+ : Object(context->engine), context(context), fullyCreated(false)
{
vtbl = &static_vtbl;
type = Type_ArgumentsObject;
+ flags &= ~SimpleArray;
ExecutionEngine *v4 = context->engine;
Scope scope(v4);
@@ -60,36 +61,21 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
internalClass = v4->strictArgumentsObjectClass;
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
- assert(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
- assert(CallerPropertyIndex == internalClass->find(context->engine->id_caller));
+ Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
+ Q_ASSERT(CallerPropertyIndex == internalClass->find(context->engine->id_caller));
memberData[CalleePropertyIndex] = pd;
memberData[CallerPropertyIndex] = pd;
arrayReserve(context->callData->argc);
- for (unsigned int i = 0; i < context->callData->argc; ++i)
+ for (int i = 0; i < context->callData->argc; ++i)
arrayData[i].value = context->callData->args[i];
arrayDataLen = context->callData->argc;
+ fullyCreated = true;
} else {
internalClass = engine()->argumentsObjectClass;
Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
memberData[CalleePropertyIndex].value = context->function->asReturnedValue();
isNonStrictArgumentsObject = true;
-
- uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount);
- uint argCount = qMin(context->realArgumentCount, context->callData->argc);
- arrayReserve(argCount);
- ensureArrayAttributes();
- context->engine->requireArgumentsAccessors(numAccessors);
- for (uint i = 0; i < (uint)numAccessors; ++i) {
- mappedArguments.append(context->callData->args[i]);
- arrayData[i] = context->engine->argumentsAccessors.at(i);
- arrayAttributes[i] = Attr_Accessor;
- }
- for (uint i = numAccessors; i < argCount; ++i) {
- arrayData[i] = Property::fromValue(context->callData->args[i]);
- arrayAttributes[i] = Attr_Data;
- }
- arrayDataLen = argCount;
}
Q_ASSERT(LengthPropertyIndex == internalClass->find(context->engine->id_length));
Property *lp = memberData + ArrayObject::LengthPropertyIndex;
@@ -101,8 +87,34 @@ void ArgumentsObject::destroy(Managed *that)
static_cast<ArgumentsObject *>(that)->~ArgumentsObject();
}
+void ArgumentsObject::fullyCreate()
+{
+ if (fullyCreated)
+ return;
+
+ uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount);
+ uint argCount = qMin(context->realArgumentCount, context->callData->argc);
+ arrayReserve(argCount);
+ ensureArrayAttributes();
+ context->engine->requireArgumentsAccessors(numAccessors);
+ for (uint i = 0; i < (uint)numAccessors; ++i) {
+ mappedArguments.append(context->callData->args[i]);
+ arrayData[i] = context->engine->argumentsAccessors.at(i);
+ arrayAttributes[i] = Attr_Accessor;
+ }
+ for (uint i = numAccessors; i < argCount; ++i) {
+ arrayData[i] = Property::fromValue(context->callData->args[i]);
+ arrayAttributes[i] = Attr_Data;
+ }
+ arrayDataLen = argCount;
+
+ fullyCreated = true;
+}
+
bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs)
{
+ fullyCreate();
+
Scope scope(ctx);
uint pidx = propertyIndexFromArrayIndex(index);
Property *pd = arrayData + pidx;
@@ -139,10 +151,61 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
}
if (ctx->strictMode && !result)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return result;
}
+ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (args->fullyCreated)
+ return Object::getIndexed(m, index, hasProperty);
+
+ if (index < static_cast<uint>(args->context->callData->argc)) {
+ if (hasProperty)
+ *hasProperty = true;
+ return args->context->callData->args[index].asReturnedValue();
+ }
+ return Encode::undefined();
+}
+
+void ArgumentsObject::putIndexed(Managed *m, uint index, const ValueRef value)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (!args->fullyCreated && index >= static_cast<uint>(args->context->callData->argc))
+ args->fullyCreate();
+
+ if (args->fullyCreated) {
+ Object::putIndexed(m, index, value);
+ return;
+ }
+
+ args->context->callData->args[index] = value;
+}
+
+bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (!args->fullyCreated)
+ args->fullyCreate();
+ return Object::deleteIndexedProperty(m, index);
+}
+
+PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
+{
+ const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
+ if (args->fullyCreated)
+ return Object::queryIndexed(m, index);
+
+ uint numAccessors = qMin((int)args->context->function->formalParameterCount, args->context->realArgumentCount);
+ uint argCount = qMin(args->context->realArgumentCount, args->context->callData->argc);
+ if (index >= argCount)
+ return PropertyAttributes();
+ if (index >= numAccessors)
+ return Attr_Data;
+ return Attr_Accessor;
+}
+
DEFINE_MANAGED_VTABLE(ArgumentsGetterFunction);
ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData)
@@ -152,9 +215,9 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData)
Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
if (!o)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
- Q_ASSERT(g->index < o->context->callData->argc);
+ Q_ASSERT(g->index < static_cast<unsigned>(o->context->callData->argc));
return o->context->argument(g->index);
}
@@ -167,19 +230,19 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData)
Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
if (!o)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
- Q_ASSERT(s->index < o->context->callData->argc);
+ Q_ASSERT(s->index < static_cast<unsigned>(o->context->callData->argc));
o->context->callData->args[s->index] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined();
return Encode::undefined();
}
-void ArgumentsObject::markObjects(Managed *that)
+void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e)
{
ArgumentsObject *o = static_cast<ArgumentsObject *>(that);
- o->context->mark();
+ o->context->mark(e);
for (int i = 0; i < o->mappedArguments.size(); ++i)
- o->mappedArguments.at(i).mark();
+ o->mappedArguments.at(i).mark(e);
- Object::markObjects(that);
+ Object::markObjects(that, e);
}
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 33245ca2fd..7c58c48bcc 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -74,20 +74,26 @@ struct ArgumentsSetterFunction: FunctionObject
struct ArgumentsObject: Object {
Q_MANAGED
CallContext *context;
+ bool fullyCreated;
QVector<SafeValue> mappedArguments;
ArgumentsObject(CallContext *context);
~ArgumentsObject() {}
+
enum {
LengthPropertyIndex = 0,
CalleePropertyIndex = 1,
CallerPropertyIndex = 2
};
bool defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs);
-
- static void markObjects(Managed *that);
-protected:
+ static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void putIndexed(Managed *m, uint index, const ValueRef value);
+ static bool deleteIndexedProperty(Managed *m, uint index);
+ static PropertyAttributes queryIndexed(const Managed *m, uint index);
+ static void markObjects(Managed *that, ExecutionEngine *e);
static void destroy(Managed *);
+
+ void fullyCreate();
};
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 3913b9ffe7..a0f0345b8b 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -65,7 +65,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData)
len = callData->args[0].asArrayLength(&ok);
if (!ok)
- v4->current->throwRangeError(callData->args[0]);
+ return v4->current->throwRangeError(callData->args[0]);
if (len < 0x1000)
a->arrayReserve(len);
@@ -131,17 +131,19 @@ uint ArrayPrototype::getLength(ExecutionContext *ctx, ObjectRef o)
return v->toUInt32();
}
-ReturnedValue ArrayPrototype::method_isArray(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx)
{
bool isArray = ctx->callData->argc && ctx->callData->args[0].asArrayObject();
return Encode(isArray);
}
-ReturnedValue ArrayPrototype::method_toString(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject o(scope, ctx->callData->thisObject, ScopedObject::Convert);
- ScopedString s(scope, ctx->engine->newString("join"));
+ if (ctx->engine->hasException)
+ return Encode::undefined();
+ ScopedString s(scope, ctx->engine->newString(QStringLiteral("join")));
ScopedFunctionObject f(scope, o->get(s));
if (!!f) {
ScopedCallData d(scope, 0);
@@ -151,17 +153,19 @@ ReturnedValue ArrayPrototype::method_toString(SimpleCallContext *ctx)
return ObjectPrototype::method_toString(ctx);
}
-ReturnedValue ArrayPrototype::method_toLocaleString(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_toLocaleString(CallContext *ctx)
{
return method_toString(ctx);
}
-ReturnedValue ArrayPrototype::method_concat(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject result(scope, ctx->engine->newArrayObject());
ScopedObject thisObject(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!thisObject)
+ return Encode::undefined();
ScopedArrayObject instance(scope, thisObject);
if (instance) {
result->copyArrayData(instance.getPointer());
@@ -170,7 +174,7 @@ ReturnedValue ArrayPrototype::method_concat(SimpleCallContext *ctx)
}
ScopedArrayObject elt(scope);
- for (uint i = 0; i < ctx->callData->argc; ++i) {
+ for (int i = 0; i < ctx->callData->argc; ++i) {
elt = ctx->callData->args[i];
if (elt)
result->arrayConcat(elt.getPointer());
@@ -181,7 +185,7 @@ ReturnedValue ArrayPrototype::method_concat(SimpleCallContext *ctx)
return result.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_join(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue arg(scope, ctx->argument(0));
@@ -209,6 +213,8 @@ ReturnedValue ArrayPrototype::method_join(SimpleCallContext *ctx)
R += r4;
e = a->getIndexed(i);
+ if (scope.hasException())
+ return Encode::undefined();
if (!e->isNullOrUndefined())
R += e->toString(ctx)->toQString();
}
@@ -227,6 +233,8 @@ ReturnedValue ArrayPrototype::method_join(SimpleCallContext *ctx)
name = Primitive::fromDouble(k).toString(ctx);
r12 = self->get(name);
+ if (scope.hasException())
+ return Encode::undefined();
if (!r12->isNullOrUndefined())
R += r12->toString(ctx)->toQString();
@@ -236,10 +244,12 @@ ReturnedValue ArrayPrototype::method_join(SimpleCallContext *ctx)
return ctx->engine->newString(R)->asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_pop(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_pop(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
if (!len) {
@@ -249,8 +259,12 @@ ReturnedValue ArrayPrototype::method_pop(SimpleCallContext *ctx)
}
ScopedValue result(scope, instance->getIndexed(len - 1));
+ if (scope.hasException())
+ return Encode::undefined();
instance->deleteIndexedProperty(len - 1);
+ if (scope.hasException())
+ return Encode::undefined();
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len - 1);
else
@@ -258,10 +272,12 @@ ReturnedValue ArrayPrototype::method_pop(SimpleCallContext *ctx)
return result.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_push(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
if (len + ctx->callData->argc < len) {
@@ -277,13 +293,13 @@ ReturnedValue ArrayPrototype::method_push(SimpleCallContext *ctx)
instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen)));
else {
ScopedString str(scope, ctx->engine->newString(QStringLiteral("Array.prototype.push: Overflow")));
- ctx->throwRangeError(str);
+ return ctx->throwRangeError(str);
}
return Encode(newLen);
}
if (!instance->protoHasArray() && instance->arrayDataLen <= len) {
- for (uint i = 0; i < ctx->callData->argc; ++i) {
+ for (int i = 0; i < ctx->callData->argc; ++i) {
if (!instance->sparseArray) {
if (len >= instance->arrayAlloc)
instance->arrayReserve(len + 1);
@@ -292,13 +308,13 @@ ReturnedValue ArrayPrototype::method_push(SimpleCallContext *ctx)
instance->arrayAttributes[len] = Attr_Data;
instance->arrayDataLen = len + 1;
} else {
- uint i = instance->allocArrayValue(ctx->callData->args[i]);
- instance->sparseArray->push_back(i, len);
+ uint j = instance->allocArrayValue(ctx->callData->args[i]);
+ instance->sparseArray->push_back(j, len);
}
++len;
}
} else {
- for (uint i = 0; i < ctx->callData->argc; ++i)
+ for (int i = 0; i < ctx->callData->argc; ++i)
instance->putIndexed(len + i, ctx->callData->args[i]);
len += ctx->callData->argc;
}
@@ -310,10 +326,12 @@ ReturnedValue ArrayPrototype::method_push(SimpleCallContext *ctx)
return Encode(len);
}
-ReturnedValue ArrayPrototype::method_reverse(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint length = getLength(ctx, instance);
int lo = 0, hi = length - 1;
@@ -324,10 +342,14 @@ ReturnedValue ArrayPrototype::method_reverse(SimpleCallContext *ctx)
bool loExists, hiExists;
lval = instance->getIndexed(lo, &loExists);
hval = instance->getIndexed(hi, &hiExists);
+ if (scope.hasException())
+ return Encode::undefined();
if (hiExists)
instance->putIndexed(lo, hval);
else
instance->deleteIndexedProperty(lo);
+ if (scope.hasException())
+ return Encode::undefined();
if (loExists)
instance->putIndexed(hi, lval);
else
@@ -336,10 +358,12 @@ ReturnedValue ArrayPrototype::method_reverse(SimpleCallContext *ctx)
return instance.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_shift(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
if (!len) {
@@ -375,12 +399,16 @@ ReturnedValue ArrayPrototype::method_shift(SimpleCallContext *ctx)
for (uint k = 1; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
+ if (scope.hasException())
+ return Encode::undefined();
if (exists)
instance->putIndexed(k - 1, v);
else
instance->deleteIndexedProperty(k - 1);
}
instance->deleteIndexedProperty(len - 1);
+ if (scope.hasException())
+ return Encode::undefined();
}
if (instance->isArrayObject())
@@ -390,10 +418,12 @@ ReturnedValue ArrayPrototype::method_shift(SimpleCallContext *ctx)
return result.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_slice(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject o(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!o)
+ return Encode::undefined();
Scoped<ArrayObject> result(scope, ctx->engine->newArrayObject());
uint len = getLength(ctx, o);
@@ -421,18 +451,21 @@ ReturnedValue ArrayPrototype::method_slice(SimpleCallContext *ctx)
for (uint i = start; i < end; ++i) {
bool exists;
v = o->getIndexed(i, &exists);
- if (exists) {
+ if (scope.hasException())
+ return Encode::undefined();
+ if (exists)
result->arraySet(n, v);
- }
++n;
}
return result.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_sort(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_sort(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
@@ -441,10 +474,12 @@ ReturnedValue ArrayPrototype::method_sort(SimpleCallContext *ctx)
return ctx->callData->thisObject.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_splice(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
Scoped<ArrayObject> newArray(scope, ctx->engine->newArrayObject());
@@ -461,6 +496,8 @@ ReturnedValue ArrayPrototype::method_splice(SimpleCallContext *ctx)
newArray->arrayReserve(deleteCount);
for (uint i = 0; i < deleteCount; ++i) {
newArray->arrayData[i].value = instance->getIndexed(start + i);
+ if (scope.hasException())
+ return Encode::undefined();
newArray->arrayDataLen = i + 1;
}
newArray->setArrayLengthUnchecked(deleteCount);
@@ -472,28 +509,42 @@ ReturnedValue ArrayPrototype::method_splice(SimpleCallContext *ctx)
for (uint k = start; k < len - deleteCount; ++k) {
bool exists;
v = instance->getIndexed(k + deleteCount, &exists);
+ if (scope.hasException())
+ return Encode::undefined();
if (exists)
instance->putIndexed(k + itemCount, v);
else
instance->deleteIndexedProperty(k + itemCount);
+ if (scope.hasException())
+ return Encode::undefined();
}
- for (uint k = len; k > len - deleteCount + itemCount; --k)
+ for (uint k = len; k > len - deleteCount + itemCount; --k) {
instance->deleteIndexedProperty(k - 1);
+ if (scope.hasException())
+ return Encode::undefined();
+ }
} else if (itemCount > deleteCount) {
uint k = len - deleteCount;
while (k > start) {
bool exists;
v = instance->getIndexed(k + deleteCount - 1, &exists);
+ if (scope.hasException())
+ return Encode::undefined();
if (exists)
instance->putIndexed(k + itemCount - 1, v);
else
instance->deleteIndexedProperty(k + itemCount - 1);
+ if (scope.hasException())
+ return Encode::undefined();
--k;
}
}
- for (uint i = 0; i < itemCount; ++i)
+ for (uint i = 0; i < itemCount; ++i) {
instance->putIndexed(start + i, ctx->callData->args[i + 2]);
+ if (scope.hasException())
+ return Encode::undefined();
+ }
ctx->strictMode = true;
instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)));
@@ -501,10 +552,12 @@ ReturnedValue ArrayPrototype::method_splice(SimpleCallContext *ctx)
return newArray.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_unshift(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
ScopedValue v(scope);
@@ -519,6 +572,7 @@ ReturnedValue ArrayPrototype::method_unshift(SimpleCallContext *ctx)
--instance->arrayOffset;
--instance->arrayData;
++instance->arrayDataLen;
+ ++instance->arrayAlloc;
if (instance->arrayAttributes) {
--instance->arrayAttributes;
*instance->arrayAttributes = Attr_Data;
@@ -538,7 +592,7 @@ ReturnedValue ArrayPrototype::method_unshift(SimpleCallContext *ctx)
else
instance->deleteIndexedProperty(k + ctx->callData->argc - 1);
}
- for (uint i = 0; i < ctx->callData->argc; ++i)
+ for (int i = 0; i < ctx->callData->argc; ++i)
instance->putIndexed(i, ctx->callData->args[i]);
}
@@ -551,25 +605,24 @@ ReturnedValue ArrayPrototype::method_unshift(SimpleCallContext *ctx)
return Encode(newLen);
}
-ReturnedValue ArrayPrototype::method_indexOf(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
if (!len)
return Encode(-1);
- ScopedValue searchValue(scope);
+ ScopedValue searchValue(scope, ctx->callData->argument(0));
uint fromIndex = 0;
- if (ctx->callData->argc >= 1)
- searchValue = ctx->callData->args[0];
- else
- searchValue = Primitive::undefinedValue();
-
if (ctx->callData->argc >= 2) {
double f = ctx->callData->args[1].toInteger();
+ if (scope.hasException())
+ return Encode::undefined();
if (f >= len)
return Encode(-1);
if (f < 0)
@@ -591,11 +644,13 @@ ReturnedValue ArrayPrototype::method_indexOf(SimpleCallContext *ctx)
return instance->arrayIndexOf(searchValue, fromIndex, len, ctx, instance.getPointer());
}
-ReturnedValue ArrayPrototype::method_lastIndexOf(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
if (!len)
return Encode(-1);
@@ -610,6 +665,8 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(SimpleCallContext *ctx)
if (ctx->callData->argc >= 2) {
double f = ctx->callData->args[1].toInteger();
+ if (scope.hasException())
+ return Encode::undefined();
if (f > 0)
f = qMin(f, (double)(len - 1));
else if (f < 0) {
@@ -625,22 +682,26 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(SimpleCallContext *ctx)
--k;
bool exists;
v = instance->getIndexed(k, &exists);
+ if (scope.hasException())
+ return Encode::undefined();
if (exists && __qmljs_strict_equal(v, searchValue))
return Encode(k);
}
return Encode(-1);
}
-ReturnedValue ArrayPrototype::method_every(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedCallData callData(scope, 3);
callData->args[2] = instance;
@@ -663,16 +724,18 @@ ReturnedValue ArrayPrototype::method_every(SimpleCallContext *ctx)
return Encode(ok);
}
-ReturnedValue ArrayPrototype::method_some(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedCallData callData(scope, 3);
callData->thisObject = ctx->argument(1);
@@ -695,16 +758,18 @@ ReturnedValue ArrayPrototype::method_some(SimpleCallContext *ctx)
return Encode(false);
}
-ReturnedValue ArrayPrototype::method_forEach(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedCallData callData(scope, 3);
callData->thisObject = ctx->argument(1);
@@ -724,16 +789,18 @@ ReturnedValue ArrayPrototype::method_forEach(SimpleCallContext *ctx)
return Encode::undefined();
}
-ReturnedValue ArrayPrototype::method_map(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
a->arrayReserve(len);
@@ -759,16 +826,18 @@ ReturnedValue ArrayPrototype::method_map(SimpleCallContext *ctx)
return a.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_filter(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
a->arrayReserve(len);
@@ -798,16 +867,18 @@ ReturnedValue ArrayPrototype::method_filter(SimpleCallContext *ctx)
return a.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_reduce(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
uint k = 0;
ScopedValue acc(scope);
@@ -824,7 +895,7 @@ ReturnedValue ArrayPrototype::method_reduce(SimpleCallContext *ctx)
++k;
}
if (!kPresent)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
}
ScopedCallData callData(scope, 4);
@@ -846,20 +917,22 @@ ReturnedValue ArrayPrototype::method_reduce(SimpleCallContext *ctx)
return acc.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_reduceRight(SimpleCallContext *ctx)
+ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!instance)
+ return Encode::undefined();
uint len = getLength(ctx, instance);
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (len == 0) {
if (ctx->callData->argc == 1)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return ctx->argument(1);
}
@@ -877,7 +950,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(SimpleCallContext *ctx)
--k;
}
if (!kPresent)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
}
ScopedCallData callData(scope, 4);
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index 933939e279..7e809f9064 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -66,28 +66,28 @@ struct ArrayPrototype: ArrayObject
static uint getLength(ExecutionContext *ctx, ObjectRef o);
- static ReturnedValue method_isArray(SimpleCallContext *ctx);
- static ReturnedValue method_toString(SimpleCallContext *ctx);
- static ReturnedValue method_toLocaleString(SimpleCallContext *ctx);
- static ReturnedValue method_concat(SimpleCallContext *ctx);
- static ReturnedValue method_join(SimpleCallContext *ctx);
- static ReturnedValue method_pop(SimpleCallContext *ctx);
- static ReturnedValue method_push(SimpleCallContext *ctx);
- static ReturnedValue method_reverse(SimpleCallContext *ctx);
- static ReturnedValue method_shift(SimpleCallContext *ctx);
- static ReturnedValue method_slice(SimpleCallContext *ctx);
- static ReturnedValue method_sort(SimpleCallContext *ctx);
- static ReturnedValue method_splice(SimpleCallContext *ctx);
- static ReturnedValue method_unshift(SimpleCallContext *ctx);
- static ReturnedValue method_indexOf(SimpleCallContext *ctx);
- static ReturnedValue method_lastIndexOf(SimpleCallContext *ctx);
- static ReturnedValue method_every(SimpleCallContext *ctx);
- static ReturnedValue method_some(SimpleCallContext *ctx);
- static ReturnedValue method_forEach(SimpleCallContext *ctx);
- static ReturnedValue method_map(SimpleCallContext *ctx);
- static ReturnedValue method_filter(SimpleCallContext *ctx);
- static ReturnedValue method_reduce(SimpleCallContext *ctx);
- static ReturnedValue method_reduceRight(SimpleCallContext *ctx);
+ static ReturnedValue method_isArray(CallContext *ctx);
+ static ReturnedValue method_toString(CallContext *ctx);
+ static ReturnedValue method_toLocaleString(CallContext *ctx);
+ static ReturnedValue method_concat(CallContext *ctx);
+ static ReturnedValue method_join(CallContext *ctx);
+ static ReturnedValue method_pop(CallContext *ctx);
+ static ReturnedValue method_push(CallContext *ctx);
+ static ReturnedValue method_reverse(CallContext *ctx);
+ static ReturnedValue method_shift(CallContext *ctx);
+ static ReturnedValue method_slice(CallContext *ctx);
+ static ReturnedValue method_sort(CallContext *ctx);
+ static ReturnedValue method_splice(CallContext *ctx);
+ static ReturnedValue method_unshift(CallContext *ctx);
+ static ReturnedValue method_indexOf(CallContext *ctx);
+ static ReturnedValue method_lastIndexOf(CallContext *ctx);
+ static ReturnedValue method_every(CallContext *ctx);
+ static ReturnedValue method_some(CallContext *ctx);
+ static ReturnedValue method_forEach(CallContext *ctx);
+ static ReturnedValue method_map(CallContext *ctx);
+ static ReturnedValue method_filter(CallContext *ctx);
+ static ReturnedValue method_reduce(CallContext *ctx);
+ static ReturnedValue method_reduceRight(CallContext *ctx);
};
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 025f98351f..a0d0027e5f 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -77,7 +77,7 @@ void BooleanPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
defineDefaultProperty(engine->id_valueOf, method_valueOf);
}
-ReturnedValue BooleanPrototype::method_toString(SimpleCallContext *ctx)
+ReturnedValue BooleanPrototype::method_toString(CallContext *ctx)
{
bool result;
if (ctx->callData->thisObject.isBoolean()) {
@@ -86,14 +86,14 @@ ReturnedValue BooleanPrototype::method_toString(SimpleCallContext *ctx)
Scope scope(ctx);
Scoped<BooleanObject> thisObject(scope, ctx->callData->thisObject);
if (!thisObject)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
result = thisObject->value.booleanValue();
}
return Encode(ctx->engine->newString(QLatin1String(result ? "true" : "false")));
}
-ReturnedValue BooleanPrototype::method_valueOf(SimpleCallContext *ctx)
+ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx)
{
if (ctx->callData->thisObject.isBoolean())
return ctx->callData->thisObject.asReturnedValue();
@@ -101,7 +101,7 @@ ReturnedValue BooleanPrototype::method_valueOf(SimpleCallContext *ctx)
Scope scope(ctx);
Scoped<BooleanObject> thisObject(scope, ctx->callData->thisObject);
if (!thisObject)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return thisObject->value.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index 6766fae830..56c00f99ed 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -63,8 +63,8 @@ struct BooleanPrototype: BooleanObject
BooleanPrototype(InternalClass *ic): BooleanObject(ic) {}
void init(ExecutionEngine *engine, ObjectRef ctor);
- static ReturnedValue method_toString(SimpleCallContext *ctx);
- static ReturnedValue method_valueOf(SimpleCallContext *ctx);
+ static ReturnedValue method_toString(CallContext *ctx);
+ static ReturnedValue method_valueOf(CallContext *ctx);
};
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index f3d2ab66ed..372c9ce54b 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -51,54 +51,33 @@
using namespace QV4;
-CallContext *ExecutionContext::newCallContext(void *stackSpace, SafeValue *locals, FunctionObject *function, CallData *callData)
-{
- CallContext *c = (CallContext *)stackSpace;
-#ifndef QT_NO_DEBUG
- c->next = (CallContext *)0x1;
-#endif
-
- engine->current = c;
-
- c->initBaseContext(Type_CallContext, engine, this);
-
- c->function = function;
- c->callData = callData;
- c->realArgumentCount = callData->argc;
-
- c->strictMode = function->strictMode;
- c->marked = false;
- c->outer = function->scope;
-#ifndef QT_NO_DEBUG
- assert(c->outer->next != (ExecutionContext *)0x1);
-#endif
-
- c->activation = 0;
-
- if (function->function) {
- c->compilationUnit = function->function->compilationUnit;
- c->lookups = c->compilationUnit->runtimeLookups;
- }
-
- c->locals = locals;
-
- if (function->varCount)
- std::fill(c->locals, c->locals + function->varCount, Primitive::undefinedValue());
-
- if (callData->argc < function->formalParameterCount) {
-#ifndef QT_NO_DEBUG
- Q_ASSERT(function->formalParameterCount <= QV4::Global::ReservedArgumentCount);
-#endif
- std::fill(c->callData->args + callData->argc, c->callData->args + function->formalParameterCount, Primitive::undefinedValue());
- c->callData->argc = function->formalParameterCount;
- }
-
- return c;
-}
+const ManagedVTable ExecutionContext::static_vtbl =
+{
+ call,
+ construct,
+ markObjects,
+ destroy,
+ 0 /*collectDeletables*/,
+ hasInstance,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ isEqualTo,
+ 0,
+ "ExecutionContext",
+};
CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData)
{
- CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(function, callData->argc)));
+ CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc)));
+ c->init();
engine->current = c;
@@ -108,7 +87,6 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
c->realArgumentCount = callData->argc;
c->strictMode = function->strictMode;
- c->marked = false;
c->outer = function->scope;
#ifndef QT_NO_DEBUG
assert(c->outer->next != (ExecutionContext *)0x1);
@@ -128,7 +106,7 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
c->callData = reinterpret_cast<CallData *>(c->locals + function->varCount);
::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(SafeValue));
- if (callData->argc < function->formalParameterCount)
+ if (callData->argc < static_cast<int>(function->formalParameterCount))
std::fill(c->callData->args + c->callData->argc, c->callData->args + function->formalParameterCount, Primitive::undefinedValue());
c->callData->argc = qMax((uint)callData->argc, function->formalParameterCount);
@@ -137,7 +115,7 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
WithContext *ExecutionContext::newWithContext(ObjectRef with)
{
- WithContext *w = static_cast<WithContext *>(engine->memoryManager->allocContext(sizeof(WithContext)));
+ WithContext *w = new (engine->memoryManager) WithContext;
engine->current = w;
w->initWithContext(this, with);
return w;
@@ -145,7 +123,7 @@ WithContext *ExecutionContext::newWithContext(ObjectRef with)
CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue)
{
- CatchContext *c = static_cast<CatchContext *>(engine->memoryManager->allocContext(sizeof(CatchContext)));
+ CatchContext *c = new (engine->memoryManager) CatchContext;
engine->current = c;
c->initCatchContext(this, exceptionVarName, exceptionValue);
return c;
@@ -153,7 +131,8 @@ CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName
CallContext *ExecutionContext::newQmlContext(FunctionObject *f, ObjectRef qml)
{
- CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(f, 0)));
+ CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0)));
+ c->init();
engine->current = c;
c->initQmlContext(this, qml, f);
@@ -191,22 +170,34 @@ void ExecutionContext::createMutableBinding(const StringRef name, bool deletable
String * const *ExecutionContext::formals() const
{
- return type >= Type_CallContext ? static_cast<const CallContext *>(this)->function->formalParameterList : 0;
+ if (type < Type_SimpleCallContext)
+ return 0;
+ QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function;
+ return f ? f->formalParameterList : 0;
}
unsigned int ExecutionContext::formalCount() const
{
- return type >= Type_CallContext ? static_cast<const CallContext *>(this)->function->formalParameterCount : 0;
+ if (type < Type_SimpleCallContext)
+ return 0;
+ QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function;
+ return f ? f->formalParameterCount : 0;
}
String * const *ExecutionContext::variables() const
{
- return type >= Type_CallContext ? static_cast<const CallContext *>(this)->function->varList : 0;
+ if (type < Type_SimpleCallContext)
+ return 0;
+ QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function;
+ return f ? f->varList : 0;
}
unsigned int ExecutionContext::variableCount() const
{
- return type >= Type_CallContext ? static_cast<const CallContext *>(this)->function->varCount : 0;
+ if (type < Type_SimpleCallContext)
+ return 0;
+ QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function;
+ return f ? f->varCount : 0;
}
@@ -217,6 +208,7 @@ void GlobalContext::initGlobalContext(ExecutionEngine *eng)
callData->tag = QV4::Value::_Integer_Type;
callData->argc = 0;
callData->thisObject = eng->globalObject;
+ callData->args[0] = Encode::undefined();
global = 0;
}
@@ -255,7 +247,6 @@ void CallContext::initQmlContext(ExecutionContext *parentContext, ObjectRef qml,
this->callData->thisObject = Primitive::undefinedValue();
strictMode = true;
- marked = false;
this->outer = function->scope;
#ifndef QT_NO_DEBUG
assert(outer->next != (ExecutionContext *)0x1);
@@ -309,45 +300,44 @@ bool ExecutionContext::deleteProperty(const StringRef name)
}
if (strictMode)
- throwSyntaxError(QString("Can't delete property %1").arg(name->toQString()));
+ throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString()));
return true;
}
bool CallContext::needsOwnArguments() const
{
- return function->needsActivation || callData->argc < function->formalParameterCount;
+ return function->needsActivation || callData->argc < static_cast<int>(function->formalParameterCount);
}
-void ExecutionContext::mark()
+void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine)
{
- if (marked)
- return;
- marked = true;
+ ExecutionContext *ctx = static_cast<ExecutionContext *>(m);
- if (type != Type_SimpleCallContext && outer)
- outer->mark();
+ if (ctx->outer)
+ ctx->outer->mark(engine);
- callData->thisObject.mark();
- for (unsigned arg = 0; arg < callData->argc; ++arg)
- callData->args[arg].mark();
+ // ### shouldn't need these 3 lines
+ ctx->callData->thisObject.mark(engine);
+ for (int arg = 0; arg < ctx->callData->argc; ++arg)
+ ctx->callData->args[arg].mark(engine);
- if (type >= Type_CallContext) {
- QV4::CallContext *c = static_cast<CallContext *>(this);
+ if (ctx->type >= Type_CallContext) {
+ QV4::CallContext *c = static_cast<CallContext *>(ctx);
for (unsigned local = 0, lastLocal = c->variableCount(); local < lastLocal; ++local)
- c->locals[local].mark();
+ c->locals[local].mark(engine);
if (c->activation)
- c->activation->mark();
- c->function->mark();
- } else if (type == Type_WithContext) {
- WithContext *w = static_cast<WithContext *>(this);
- w->withObject->mark();
- } else if (type == Type_CatchContext) {
- CatchContext *c = static_cast<CatchContext *>(this);
- c->exceptionVarName->mark();
- c->exceptionValue.mark();
- } else if (type == Type_GlobalContext) {
- GlobalContext *g = static_cast<GlobalContext *>(this);
- g->global->mark();
+ c->activation->mark(engine);
+ c->function->mark(engine);
+ } else if (ctx->type == Type_WithContext) {
+ WithContext *w = static_cast<WithContext *>(ctx);
+ w->withObject->mark(engine);
+ } else if (ctx->type == Type_CatchContext) {
+ CatchContext *c = static_cast<CatchContext *>(ctx);
+ c->exceptionVarName->mark(engine);
+ c->exceptionValue.mark(engine);
+ } else if (ctx->type == Type_GlobalContext) {
+ GlobalContext *g = static_cast<GlobalContext *>(ctx);
+ g->global->mark(engine);
}
}
@@ -392,6 +382,7 @@ void ExecutionContext::setProperty(const StringRef name, const ValueRef value)
if (strictMode || name->equals(engine->id_this)) {
ScopedValue n(scope, name.asReturnedValue());
throwReferenceError(n);
+ return;
}
engine->globalObject->put(name, value);
}
@@ -457,71 +448,7 @@ ReturnedValue ExecutionContext::getProperty(const StringRef name)
}
}
ScopedValue n(scope, name.asReturnedValue());
- throwReferenceError(n);
- return 0;
-}
-
-ReturnedValue ExecutionContext::getPropertyNoThrow(const StringRef name)
-{
- Scope scope(this);
- ScopedValue v(scope);
- name->makeIdentifier();
-
- if (name->equals(engine->id_this))
- return callData->thisObject.asReturnedValue();
-
- bool hasWith = false;
- bool hasCatchScope = false;
- for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
- if (ctx->type == Type_WithContext) {
- ScopedObject w(scope, static_cast<WithContext *>(ctx)->withObject);
- hasWith = true;
- bool hasProperty = false;
- v = w->get(name, &hasProperty);
- if (hasProperty) {
- return v.asReturnedValue();
- }
- continue;
- }
-
- else if (ctx->type == Type_CatchContext) {
- hasCatchScope = true;
- CatchContext *c = static_cast<CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name))
- return c->exceptionValue.asReturnedValue();
- }
-
- else if (ctx->type >= Type_CallContext) {
- QV4::CallContext *c = static_cast<CallContext *>(ctx);
- ScopedFunctionObject f(scope, c->function);
- if (f->needsActivation || hasWith || hasCatchScope) {
- for (unsigned int i = 0; i < f->varCount; ++i)
- if (f->varList[i]->isEqualTo(name))
- return c->locals[i].asReturnedValue();
- for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
- if (f->formalParameterList[i]->isEqualTo(name))
- return c->callData->args[i].asReturnedValue();
- }
- if (c->activation) {
- bool hasProperty = false;
- v = c->activation->get(name, &hasProperty);
- if (hasProperty)
- return v.asReturnedValue();
- }
- if (f->function && f->function->isNamedExpression()
- && name->equals(f->function->name))
- return f.asReturnedValue();
- }
-
- else if (ctx->type == Type_GlobalContext) {
- GlobalContext *g = static_cast<GlobalContext *>(ctx);
- bool hasProperty = false;
- v = g->global->get(name, &hasProperty);
- if (hasProperty)
- return v.asReturnedValue();
- }
- }
- return Encode::undefined();
+ return throwReferenceError(n);
}
ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectRef base)
@@ -590,58 +517,57 @@ ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectR
}
}
ScopedValue n(scope, name.asReturnedValue());
- throwReferenceError(n);
- return 0;
+ return throwReferenceError(n);
}
-void ExecutionContext::throwError(const ValueRef value)
+ReturnedValue ExecutionContext::throwError(const ValueRef value)
{
- engine->throwException(value);
+ return engine->throwException(value);
}
-void ExecutionContext::throwError(const QString &message)
+ReturnedValue ExecutionContext::throwError(const QString &message)
{
Scope scope(this);
ScopedValue v(scope, engine->newString(message));
v = engine->newErrorObject(v);
- throwError(v);
+ return throwError(v);
}
-void ExecutionContext::throwSyntaxError(const QString &message, const QString &fileName, int line, int column)
+ReturnedValue ExecutionContext::throwSyntaxError(const QString &message, const QString &fileName, int line, int column)
{
Scope scope(this);
Scoped<Object> error(scope, engine->newSyntaxErrorObject(message, fileName, line, column));
- throwError(error);
+ return throwError(error);
}
-void ExecutionContext::throwSyntaxError(const QString &message)
+ReturnedValue ExecutionContext::throwSyntaxError(const QString &message)
{
Scope scope(this);
Scoped<Object> error(scope, engine->newSyntaxErrorObject(message));
- throwError(error);
+ return throwError(error);
}
-void ExecutionContext::throwTypeError()
+ReturnedValue ExecutionContext::throwTypeError()
{
Scope scope(this);
Scoped<Object> error(scope, engine->newTypeErrorObject(QStringLiteral("Type error")));
- throwError(error);
+ return throwError(error);
}
-void ExecutionContext::throwTypeError(const QString &message)
+ReturnedValue ExecutionContext::throwTypeError(const QString &message)
{
Scope scope(this);
Scoped<Object> error(scope, engine->newTypeErrorObject(message));
- throwError(error);
+ return throwError(error);
}
-void ExecutionContext::throwUnimplemented(const QString &message)
+ReturnedValue ExecutionContext::throwUnimplemented(const QString &message)
{
Scope scope(this);
ScopedValue v(scope, engine->newString(QStringLiteral("Unimplemented ") + message));
v = engine->newErrorObject(v);
- throwError(v);
+ return throwError(v);
}
ReturnedValue ExecutionContext::catchException(StackTrace *trace)
@@ -649,41 +575,42 @@ ReturnedValue ExecutionContext::catchException(StackTrace *trace)
return engine->catchException(this, trace);
}
-void ExecutionContext::throwReferenceError(const ValueRef value)
+ReturnedValue ExecutionContext::throwReferenceError(const ValueRef value)
{
Scope scope(this);
Scoped<String> s(scope, value->toString(this));
QString msg = s->toQString() + QStringLiteral(" is not defined");
Scoped<Object> error(scope, engine->newReferenceErrorObject(msg));
- throwError(error);
+ return throwError(error);
}
-void ExecutionContext::throwReferenceError(const QString &message, const QString &fileName, int line, int column)
+ReturnedValue ExecutionContext::throwReferenceError(const QString &message, const QString &fileName, int line, int column)
{
Scope scope(this);
- QString msg = message + QStringLiteral(" is not defined");
+ QString msg = message;
Scoped<Object> error(scope, engine->newReferenceErrorObject(msg, fileName, line, column));
- throwError(error);
+ return throwError(error);
}
-void ExecutionContext::throwRangeError(const ValueRef value)
+ReturnedValue ExecutionContext::throwRangeError(const ValueRef value)
{
Scope scope(this);
ScopedString s(scope, value->toString(this));
QString msg = s->toQString() + QStringLiteral(" out of range");
ScopedObject error(scope, engine->newRangeErrorObject(msg));
- throwError(error);
+ return throwError(error);
}
-void ExecutionContext::throwURIError(const ValueRef msg)
+ReturnedValue ExecutionContext::throwRangeError(const QString &message)
{
Scope scope(this);
- ScopedObject error(scope, engine->newURIErrorObject(msg));
- throwError(error);
+ ScopedObject error(scope, engine->newRangeErrorObject(message));
+ return throwError(error);
}
-void SimpleCallContext::initSimpleCallContext(ExecutionEngine *engine)
+ReturnedValue ExecutionContext::throwURIError(const ValueRef msg)
{
- initBaseContext(Type_SimpleCallContext, engine, engine->current);
- function = 0;
+ Scope scope(this);
+ ScopedObject error(scope, engine->newURIErrorObject(msg));
+ return throwError(error);
}
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index e5b0c431ca..e7f5ee9a9e 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -62,11 +62,25 @@ struct Function;
};
struct CallContext;
+struct CallContext;
struct CatchContext;
struct WithContext;
-struct Q_QML_EXPORT ExecutionContext
+struct Q_QML_EXPORT ExecutionContext : public Managed
{
+ Q_MANAGED
+ ExecutionContext()
+ : Managed(0) {
+ vtbl = &static_vtbl;
+ }
+ void init() {
+ _data = 0;
+ internalClass = 0;
+ inUse = 1;
+ extensible = 1;
+ vtbl = &static_vtbl;
+ }
+
enum Type {
Type_GlobalContext = 0x1,
Type_CatchContext = 0x2,
@@ -78,7 +92,6 @@ struct Q_QML_EXPORT ExecutionContext
Type type;
bool strictMode;
- bool marked;
CallData *callData;
@@ -97,13 +110,12 @@ struct Q_QML_EXPORT ExecutionContext
EvalCode *currentEvalCode;
const uchar **interpreterInstructionPointer;
- char *jitInstructionPointer;
+ int lineNumber;
void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext)
{
this->type = type;
strictMode = false;
- marked = false;
this->engine = engine;
parent = parentContext;
outer = 0;
@@ -111,10 +123,9 @@ struct Q_QML_EXPORT ExecutionContext
compilationUnit = 0;
currentEvalCode = 0;
interpreterInstructionPointer = 0;
- jitInstructionPointer = 0;
+ lineNumber = -1;
}
- CallContext *newCallContext(void *stackSpace, SafeValue *locals, FunctionObject *f, CallData *callData);
CallContext *newCallContext(FunctionObject *f, CallData *callData);
WithContext *newWithContext(ObjectRef with);
CatchContext *newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue);
@@ -127,49 +138,50 @@ struct Q_QML_EXPORT ExecutionContext
void createMutableBinding(const StringRef name, bool deletable);
- void Q_NORETURN throwError(const QV4::ValueRef value);
- void Q_NORETURN throwError(const QString &message);
- void Q_NORETURN throwSyntaxError(const QString &message);
- void Q_NORETURN throwSyntaxError(const QString &message, const QString &fileName, int line, int column);
- void Q_NORETURN throwTypeError();
- void Q_NORETURN throwTypeError(const QString &message);
- void Q_NORETURN throwReferenceError(const ValueRef value);
- void Q_NORETURN throwReferenceError(const QString &value, const QString &fileName, int line, int column);
- void Q_NORETURN throwRangeError(const ValueRef value);
- void Q_NORETURN throwURIError(const ValueRef msg);
- void Q_NORETURN throwUnimplemented(const QString &message);
+ ReturnedValue throwError(const QV4::ValueRef value);
+ ReturnedValue throwError(const QString &message);
+ ReturnedValue throwSyntaxError(const QString &message);
+ ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column);
+ ReturnedValue throwTypeError();
+ ReturnedValue throwTypeError(const QString &message);
+ ReturnedValue throwReferenceError(const ValueRef value);
+ ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column);
+ ReturnedValue throwRangeError(const ValueRef value);
+ ReturnedValue throwRangeError(const QString &message);
+ ReturnedValue throwURIError(const ValueRef msg);
+ ReturnedValue throwUnimplemented(const QString &message);
void setProperty(const StringRef name, const ValueRef value);
ReturnedValue getProperty(const StringRef name);
- ReturnedValue getPropertyNoThrow(const StringRef name);
ReturnedValue getPropertyAndBase(const StringRef name, ObjectRef base);
bool deleteProperty(const StringRef name);
// Can only be called from within catch(...), rethrows if no JS exception.
ReturnedValue catchException(StackTrace *trace = 0);
- void mark();
-
inline CallContext *asCallContext();
inline const CallContext *asCallContext() const;
+
+ static void markObjects(Managed *m, ExecutionEngine *e);
};
-struct SimpleCallContext : public ExecutionContext
+struct CallContext : public ExecutionContext
{
- void initSimpleCallContext(ExecutionEngine *engine);
FunctionObject *function;
int realArgumentCount;
+ SafeValue *locals;
+ Object *activation;
- inline ReturnedValue argument(int i);
-};
-
-struct CallContext : public SimpleCallContext
-{
+ void initSimpleCallContext(ExecutionEngine *engine, ExecutionContext *parent) {
+ initBaseContext(Type_SimpleCallContext, engine, parent);
+ function = 0;
+ locals = 0;
+ activation = 0;
+ }
void initQmlContext(ExecutionContext *parentContext, ObjectRef qml, QV4::FunctionObject *function);
- bool needsOwnArguments() const;
- SafeValue *locals;
- Object *activation;
+ inline ReturnedValue argument(int i);
+ bool needsOwnArguments() const;
};
struct GlobalContext : public ExecutionContext
@@ -196,22 +208,17 @@ struct WithContext : public ExecutionContext
inline CallContext *ExecutionContext::asCallContext()
{
- return type >= Type_CallContext ? static_cast<CallContext *>(this) : 0;
+ return type >= Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0;
}
inline const CallContext *ExecutionContext::asCallContext() const
{
- return type >= Type_CallContext ? static_cast<const CallContext *>(this) : 0;
+ return type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
}
/* Function *f, int argc */
#define requiredMemoryForExecutionContect(f, argc) \
sizeof(CallContext) + sizeof(Value) * (f->varCount + qMax((uint)argc, f->formalParameterCount)) + sizeof(CallData)
-#define requiredMemoryForExecutionContectSimple(f) \
- sizeof(CallContext)
-#define requiredMemoryForQmlExecutionContect(f) \
- sizeof(CallContext) + sizeof(Value) * (f->locals.size())
-#define stackContextSize (sizeof(CallContext) + 32*sizeof(Value))
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index ffc5fa891a..b732c8a04a 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -295,9 +295,16 @@ static inline double DaylightSavingTA(double t)
__time64_t tt = (__time64_t)(t / msPerSecond);
// _localtime_64_s returns non-zero on failure
if (_localtime64_s(&tmtm, &tt) != 0)
-#else
+#elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
long int tt = (long int)(t / msPerSecond);
if (!localtime_r((const time_t*) &tt, &tmtm))
+#else
+ // Returns shared static data which may be overwritten at any time
+ // (for MinGW/Windows localtime is luckily thread safe)
+ long int tt = (long int)(t / msPerSecond);
+ if (struct tm *tmtm_p = localtime((const time_t*) &tt))
+ tmtm = *tmtm_p;
+ else
#endif
return 0;
return (tmtm.tm_isdst > 0) ? msPerHour : 0;
@@ -772,14 +779,14 @@ double DatePrototype::getThisDate(ExecutionContext *ctx)
}
}
-ReturnedValue DatePrototype::method_parse(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_parse(CallContext *ctx)
{
if (!ctx->callData->argc)
return Encode(qSNaN());
return Encode(ParseString(ctx->callData->args[0].toString(ctx)->toQString()));
}
-ReturnedValue DatePrototype::method_UTC(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_UTC(CallContext *ctx)
{
const int numArgs = ctx->callData->argc;
if (numArgs >= 2) {
@@ -799,62 +806,62 @@ ReturnedValue DatePrototype::method_UTC(SimpleCallContext *ctx)
return Encode::undefined();
}
-ReturnedValue DatePrototype::method_now(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_now(CallContext *ctx)
{
Q_UNUSED(ctx);
double t = currentTime();
return Encode(t);
}
-ReturnedValue DatePrototype::method_toString(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toString(CallContext *ctx)
{
double t = getThisDate(ctx);
return ctx->engine->newString(ToString(t))->asReturnedValue();
}
-ReturnedValue DatePrototype::method_toDateString(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toDateString(CallContext *ctx)
{
double t = getThisDate(ctx);
return ctx->engine->newString(ToDateString(t))->asReturnedValue();
}
-ReturnedValue DatePrototype::method_toTimeString(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toTimeString(CallContext *ctx)
{
double t = getThisDate(ctx);
return ctx->engine->newString(ToTimeString(t))->asReturnedValue();
}
-ReturnedValue DatePrototype::method_toLocaleString(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toLocaleString(CallContext *ctx)
{
double t = getThisDate(ctx);
return ctx->engine->newString(ToLocaleString(t))->asReturnedValue();
}
-ReturnedValue DatePrototype::method_toLocaleDateString(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toLocaleDateString(CallContext *ctx)
{
double t = getThisDate(ctx);
return ctx->engine->newString(ToLocaleDateString(t))->asReturnedValue();
}
-ReturnedValue DatePrototype::method_toLocaleTimeString(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toLocaleTimeString(CallContext *ctx)
{
double t = getThisDate(ctx);
return ctx->engine->newString(ToLocaleTimeString(t))->asReturnedValue();
}
-ReturnedValue DatePrototype::method_valueOf(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_valueOf(CallContext *ctx)
{
double t = getThisDate(ctx);
return Encode(t);
}
-ReturnedValue DatePrototype::method_getTime(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getTime(CallContext *ctx)
{
double t = getThisDate(ctx);
return Encode(t);
}
-ReturnedValue DatePrototype::method_getYear(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getYear(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -862,7 +869,7 @@ ReturnedValue DatePrototype::method_getYear(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getFullYear(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getFullYear(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -870,7 +877,7 @@ ReturnedValue DatePrototype::method_getFullYear(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCFullYear(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getUTCFullYear(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -878,7 +885,7 @@ ReturnedValue DatePrototype::method_getUTCFullYear(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getMonth(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getMonth(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -886,7 +893,7 @@ ReturnedValue DatePrototype::method_getMonth(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMonth(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getUTCMonth(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -894,7 +901,7 @@ ReturnedValue DatePrototype::method_getUTCMonth(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getDate(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getDate(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -902,7 +909,7 @@ ReturnedValue DatePrototype::method_getDate(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCDate(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getUTCDate(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -910,7 +917,7 @@ ReturnedValue DatePrototype::method_getUTCDate(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getDay(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getDay(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -918,7 +925,7 @@ ReturnedValue DatePrototype::method_getDay(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCDay(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getUTCDay(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -926,7 +933,7 @@ ReturnedValue DatePrototype::method_getUTCDay(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getHours(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getHours(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -934,7 +941,7 @@ ReturnedValue DatePrototype::method_getHours(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCHours(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getUTCHours(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -942,7 +949,7 @@ ReturnedValue DatePrototype::method_getUTCHours(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getMinutes(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getMinutes(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -950,7 +957,7 @@ ReturnedValue DatePrototype::method_getMinutes(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMinutes(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getUTCMinutes(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -958,7 +965,7 @@ ReturnedValue DatePrototype::method_getUTCMinutes(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getSeconds(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getSeconds(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -966,7 +973,7 @@ ReturnedValue DatePrototype::method_getSeconds(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCSeconds(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getUTCSeconds(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -974,7 +981,7 @@ ReturnedValue DatePrototype::method_getUTCSeconds(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getMilliseconds(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getMilliseconds(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -982,7 +989,7 @@ ReturnedValue DatePrototype::method_getMilliseconds(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMilliseconds(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getUTCMilliseconds(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -990,7 +997,7 @@ ReturnedValue DatePrototype::method_getUTCMilliseconds(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_getTimezoneOffset(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_getTimezoneOffset(CallContext *ctx)
{
double t = getThisDate(ctx);
if (! std::isnan(t))
@@ -998,24 +1005,24 @@ ReturnedValue DatePrototype::method_getTimezoneOffset(SimpleCallContext *ctx)
return Encode(t);
}
-ReturnedValue DatePrototype::method_setTime(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setTime(CallContext *ctx)
{
Scope scope(ctx);
Scoped<DateObject> self(scope, ctx->callData->thisObject);
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
self->value.setDouble(TimeClip(t));
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setMilliseconds(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx)
{
Scope scope(ctx);
Scoped<DateObject> self(scope, ctx->callData->thisObject);
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = LocalTime(self->value.asDouble());
double ms = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1023,11 +1030,11 @@ ReturnedValue DatePrototype::method_setMilliseconds(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setUTCMilliseconds(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
double ms = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1035,11 +1042,11 @@ ReturnedValue DatePrototype::method_setUTCMilliseconds(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setSeconds(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = LocalTime(self->value.asDouble());
double sec = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1049,11 +1056,11 @@ ReturnedValue DatePrototype::method_setSeconds(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setUTCSeconds(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
double sec = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1063,11 +1070,11 @@ ReturnedValue DatePrototype::method_setUTCSeconds(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setMinutes(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = LocalTime(self->value.asDouble());
double min = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1078,11 +1085,11 @@ ReturnedValue DatePrototype::method_setMinutes(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setUTCMinutes(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
double min = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1093,11 +1100,11 @@ ReturnedValue DatePrototype::method_setUTCMinutes(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setHours(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setHours(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = LocalTime(self->value.asDouble());
double hour = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1109,11 +1116,11 @@ ReturnedValue DatePrototype::method_setHours(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setUTCHours(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
double hour = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1125,11 +1132,11 @@ ReturnedValue DatePrototype::method_setUTCHours(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setDate(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setDate(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = LocalTime(self->value.asDouble());
double date = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1138,11 +1145,11 @@ ReturnedValue DatePrototype::method_setDate(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setUTCDate(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
double date = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1151,11 +1158,11 @@ ReturnedValue DatePrototype::method_setUTCDate(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setMonth(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setMonth(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = LocalTime(self->value.asDouble());
double month = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1165,11 +1172,11 @@ ReturnedValue DatePrototype::method_setMonth(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setUTCMonth(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
double month = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1179,11 +1186,11 @@ ReturnedValue DatePrototype::method_setUTCMonth(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setYear(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setYear(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
if (std::isnan(t))
@@ -1205,11 +1212,11 @@ ReturnedValue DatePrototype::method_setYear(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setUTCFullYear(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
double year = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
@@ -1220,11 +1227,11 @@ ReturnedValue DatePrototype::method_setUTCFullYear(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_setFullYear(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = LocalTime(self->value.asDouble());
if (std::isnan(t))
@@ -1237,11 +1244,11 @@ ReturnedValue DatePrototype::method_setFullYear(SimpleCallContext *ctx)
return self->value.asReturnedValue();
}
-ReturnedValue DatePrototype::method_toUTCString(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
return ctx->engine->newString(ToUTCString(t))->asReturnedValue();
@@ -1260,45 +1267,45 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits)
}
}
-ReturnedValue DatePrototype::method_toISOString(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toISOString(CallContext *ctx)
{
DateObject *self = ctx->callData->thisObject.asDateObject();
if (!self)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
double t = self->value.asDouble();
if (!std::isfinite(t))
- ctx->throwRangeError(ctx->callData->thisObject);
+ return ctx->throwRangeError(ctx->callData->thisObject);
QString result;
int year = (int)YearFromTime(t);
if (year < 0 || year > 9999) {
if (qAbs(year) >= 1000000)
return ctx->engine->newString(QStringLiteral("Invalid Date"))->asReturnedValue();
- result += year < 0 ? '-' : '+';
+ result += year < 0 ? QLatin1Char('-') : QLatin1Char('+');
year = qAbs(year);
addZeroPrefixedInt(result, year, 6);
} else {
addZeroPrefixedInt(result, year, 4);
}
- result += '-';
+ result += QLatin1Char('-');
addZeroPrefixedInt(result, (int)MonthFromTime(t) + 1, 2);
- result += '-';
+ result += QLatin1Char('-');
addZeroPrefixedInt(result, (int)DateFromTime(t), 2);
- result += 'T';
+ result += QLatin1Char('T');
addZeroPrefixedInt(result, HourFromTime(t), 2);
- result += ':';
+ result += QLatin1Char(':');
addZeroPrefixedInt(result, MinFromTime(t), 2);
- result += ':';
+ result += QLatin1Char(':');
addZeroPrefixedInt(result, SecFromTime(t), 2);
- result += '.';
+ result += QLatin1Char('.');
addZeroPrefixedInt(result, msFromTime(t), 3);
- result += 'Z';
+ result += QLatin1Char('Z');
return ctx->engine->newString(result)->asReturnedValue();
}
-ReturnedValue DatePrototype::method_toJSON(SimpleCallContext *ctx)
+ReturnedValue DatePrototype::method_toJSON(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue O(scope, __qmljs_to_object(ctx, ValueRef(&ctx->callData->thisObject)));
@@ -1312,7 +1319,7 @@ ReturnedValue DatePrototype::method_toJSON(SimpleCallContext *ctx)
FunctionObject *toIso = v->asFunctionObject();
if (!toIso)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedCallData callData(scope, 0);
callData->thisObject = ctx->callData->thisObject;
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 5cd03024c5..e96cac2f20 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -87,55 +87,55 @@ struct DatePrototype: DateObject
static double getThisDate(ExecutionContext *ctx);
- static ReturnedValue method_parse(SimpleCallContext *ctx);
- static ReturnedValue method_UTC(SimpleCallContext *ctx);
- static ReturnedValue method_now(SimpleCallContext *ctx);
-
- static ReturnedValue method_toString(SimpleCallContext *ctx);
- static ReturnedValue method_toDateString(SimpleCallContext *ctx);
- static ReturnedValue method_toTimeString(SimpleCallContext *ctx);
- static ReturnedValue method_toLocaleString(SimpleCallContext *ctx);
- static ReturnedValue method_toLocaleDateString(SimpleCallContext *ctx);
- static ReturnedValue method_toLocaleTimeString(SimpleCallContext *ctx);
- static ReturnedValue method_valueOf(SimpleCallContext *ctx);
- static ReturnedValue method_getTime(SimpleCallContext *ctx);
- static ReturnedValue method_getYear(SimpleCallContext *ctx);
- static ReturnedValue method_getFullYear(SimpleCallContext *ctx);
- static ReturnedValue method_getUTCFullYear(SimpleCallContext *ctx);
- static ReturnedValue method_getMonth(SimpleCallContext *ctx);
- static ReturnedValue method_getUTCMonth(SimpleCallContext *ctx);
- static ReturnedValue method_getDate(SimpleCallContext *ctx);
- static ReturnedValue method_getUTCDate(SimpleCallContext *ctx);
- static ReturnedValue method_getDay(SimpleCallContext *ctx);
- static ReturnedValue method_getUTCDay(SimpleCallContext *ctx);
- static ReturnedValue method_getHours(SimpleCallContext *ctx);
- static ReturnedValue method_getUTCHours(SimpleCallContext *ctx);
- static ReturnedValue method_getMinutes(SimpleCallContext *ctx);
- static ReturnedValue method_getUTCMinutes(SimpleCallContext *ctx);
- static ReturnedValue method_getSeconds(SimpleCallContext *ctx);
- static ReturnedValue method_getUTCSeconds(SimpleCallContext *ctx);
- static ReturnedValue method_getMilliseconds(SimpleCallContext *ctx);
- static ReturnedValue method_getUTCMilliseconds(SimpleCallContext *ctx);
- static ReturnedValue method_getTimezoneOffset(SimpleCallContext *ctx);
- static ReturnedValue method_setTime(SimpleCallContext *ctx);
- static ReturnedValue method_setMilliseconds(SimpleCallContext *ctx);
- static ReturnedValue method_setUTCMilliseconds(SimpleCallContext *ctx);
- static ReturnedValue method_setSeconds(SimpleCallContext *ctx);
- static ReturnedValue method_setUTCSeconds(SimpleCallContext *ctx);
- static ReturnedValue method_setMinutes(SimpleCallContext *ctx);
- static ReturnedValue method_setUTCMinutes(SimpleCallContext *ctx);
- static ReturnedValue method_setHours(SimpleCallContext *ctx);
- static ReturnedValue method_setUTCHours(SimpleCallContext *ctx);
- static ReturnedValue method_setDate(SimpleCallContext *ctx);
- static ReturnedValue method_setUTCDate(SimpleCallContext *ctx);
- static ReturnedValue method_setMonth(SimpleCallContext *ctx);
- static ReturnedValue method_setUTCMonth(SimpleCallContext *ctx);
- static ReturnedValue method_setYear(SimpleCallContext *ctx);
- static ReturnedValue method_setFullYear(SimpleCallContext *ctx);
- static ReturnedValue method_setUTCFullYear(SimpleCallContext *ctx);
- static ReturnedValue method_toUTCString(SimpleCallContext *ctx);
- static ReturnedValue method_toISOString(SimpleCallContext *ctx);
- static ReturnedValue method_toJSON(SimpleCallContext *ctx);
+ static ReturnedValue method_parse(CallContext *ctx);
+ static ReturnedValue method_UTC(CallContext *ctx);
+ static ReturnedValue method_now(CallContext *ctx);
+
+ static ReturnedValue method_toString(CallContext *ctx);
+ static ReturnedValue method_toDateString(CallContext *ctx);
+ static ReturnedValue method_toTimeString(CallContext *ctx);
+ static ReturnedValue method_toLocaleString(CallContext *ctx);
+ static ReturnedValue method_toLocaleDateString(CallContext *ctx);
+ static ReturnedValue method_toLocaleTimeString(CallContext *ctx);
+ static ReturnedValue method_valueOf(CallContext *ctx);
+ static ReturnedValue method_getTime(CallContext *ctx);
+ static ReturnedValue method_getYear(CallContext *ctx);
+ static ReturnedValue method_getFullYear(CallContext *ctx);
+ static ReturnedValue method_getUTCFullYear(CallContext *ctx);
+ static ReturnedValue method_getMonth(CallContext *ctx);
+ static ReturnedValue method_getUTCMonth(CallContext *ctx);
+ static ReturnedValue method_getDate(CallContext *ctx);
+ static ReturnedValue method_getUTCDate(CallContext *ctx);
+ static ReturnedValue method_getDay(CallContext *ctx);
+ static ReturnedValue method_getUTCDay(CallContext *ctx);
+ static ReturnedValue method_getHours(CallContext *ctx);
+ static ReturnedValue method_getUTCHours(CallContext *ctx);
+ static ReturnedValue method_getMinutes(CallContext *ctx);
+ static ReturnedValue method_getUTCMinutes(CallContext *ctx);
+ static ReturnedValue method_getSeconds(CallContext *ctx);
+ static ReturnedValue method_getUTCSeconds(CallContext *ctx);
+ static ReturnedValue method_getMilliseconds(CallContext *ctx);
+ static ReturnedValue method_getUTCMilliseconds(CallContext *ctx);
+ static ReturnedValue method_getTimezoneOffset(CallContext *ctx);
+ static ReturnedValue method_setTime(CallContext *ctx);
+ static ReturnedValue method_setMilliseconds(CallContext *ctx);
+ static ReturnedValue method_setUTCMilliseconds(CallContext *ctx);
+ static ReturnedValue method_setSeconds(CallContext *ctx);
+ static ReturnedValue method_setUTCSeconds(CallContext *ctx);
+ static ReturnedValue method_setMinutes(CallContext *ctx);
+ static ReturnedValue method_setUTCMinutes(CallContext *ctx);
+ static ReturnedValue method_setHours(CallContext *ctx);
+ static ReturnedValue method_setUTCHours(CallContext *ctx);
+ static ReturnedValue method_setDate(CallContext *ctx);
+ static ReturnedValue method_setUTCDate(CallContext *ctx);
+ static ReturnedValue method_setMonth(CallContext *ctx);
+ static ReturnedValue method_setUTCMonth(CallContext *ctx);
+ static ReturnedValue method_setYear(CallContext *ctx);
+ static ReturnedValue method_setFullYear(CallContext *ctx);
+ static ReturnedValue method_setUTCFullYear(CallContext *ctx);
+ static ReturnedValue method_toUTCString(CallContext *ctx);
+ static ReturnedValue method_toISOString(CallContext *ctx);
+ static ReturnedValue method_toJSON(CallContext *ctx);
static void timezoneUpdated();
};
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 41ed34ea18..95b4100651 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -44,6 +44,7 @@
#include "qv4functionobject_p.h"
#include "qv4function_p.h"
#include "qv4instr_moth_p.h"
+#include "qv4runtime_p.h"
#include <iostream>
#include <algorithm>
@@ -51,14 +52,81 @@
using namespace QV4;
using namespace QV4::Debugging;
+namespace {
+class EvalJob: public Debugger::Job
+{
+ QV4::ExecutionEngine *engine;
+ const QString &script;
+
+public:
+ EvalJob(QV4::ExecutionEngine *engine, const QString &script)
+ : engine(engine)
+ , script(script)
+ {}
+
+ ~EvalJob() {}
+
+ void run()
+ {
+ // TODO
+ qDebug() << "Evaluating script:" << script;
+ Q_UNUSED(engine);
+ }
+
+ bool resultAsBoolean() const
+ {
+ return true;
+ }
+};
+
+class GatherSourcesJob: public Debugger::Job
+{
+ QV4::ExecutionEngine *engine;
+ const int seq;
+
+public:
+ GatherSourcesJob(QV4::ExecutionEngine *engine, int seq)
+ : engine(engine)
+ , seq(seq)
+ {}
+
+ ~GatherSourcesJob() {}
+
+ void run()
+ {
+ QStringList sources;
+
+ foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) {
+ QString fileName = unit->fileName();
+ if (!fileName.isEmpty())
+ sources.append(fileName);
+ }
+
+ Debugger *debugger = engine->debugger;
+ QMetaObject::invokeMethod(debugger->agent(), "sourcesCollected", Qt::QueuedConnection,
+ Q_ARG(QV4::Debugging::Debugger*, debugger),
+ Q_ARG(QStringList, sources),
+ Q_ARG(int, seq));
+ }
+};
+}
+
Debugger::Debugger(QV4::ExecutionEngine *engine)
- : _engine(engine)
+ : m_engine(engine)
, m_agent(0)
, m_state(Running)
, m_pauseRequested(false)
+ , m_gatherSources(0)
+ , m_havePendingBreakPoints(false)
, m_currentInstructionPointer(0)
+ , m_stepping(NotStepping)
+ , m_stopForStepping(false)
+ , m_returnedValue(Primitive::undefinedValue())
+ , m_breakOnThrow(false)
+ , m_runningJob(0)
{
qMetaTypeId<Debugger*>();
+ qMetaTypeId<PauseReason>();
}
Debugger::~Debugger()
@@ -84,6 +152,18 @@ void Debugger::detachFromAgent()
agent->removeDebugger(this);
}
+void Debugger::gatherSources(int requestSequenceNr)
+{
+ QMutexLocker locker(&m_lock);
+
+ m_gatherSources = new GatherSourcesJob(m_engine, requestSequenceNr);
+ if (m_state == Paused) {
+ runInEngine_havingLock(m_gatherSources);
+ delete m_gatherSources;
+ m_gatherSources = 0;
+ }
+}
+
void Debugger::pause()
{
QMutexLocker locker(&m_lock);
@@ -92,19 +172,33 @@ void Debugger::pause()
m_pauseRequested = true;
}
-void Debugger::resume()
+void Debugger::resume(Speed speed)
{
QMutexLocker locker(&m_lock);
- Q_ASSERT(m_state == Paused);
+ if (m_state != Paused)
+ return;
+
+ if (!m_returnedValue.isUndefined())
+ m_returnedValue = Primitive::undefinedValue();
+
+ clearTemporaryBreakPoints();
+ if (speed == StepOver)
+ setTemporaryBreakPointOnNextLine();
+ if (speed == StepOut)
+ m_temporaryBreakPoints = TemporaryBreakPoint(getFunction(), m_engine->current);
+
+ m_stepping = speed;
m_runningCondition.wakeAll();
}
-void Debugger::addBreakPoint(const QString &fileName, int lineNumber)
+void Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition)
{
QMutexLocker locker(&m_lock);
if (!m_pendingBreakPointsToRemove.remove(fileName, lineNumber))
m_pendingBreakPointsToAdd.add(fileName, lineNumber);
m_havePendingBreakPoints = !m_pendingBreakPointsToAdd.isEmpty() || !m_pendingBreakPointsToRemove.isEmpty();
+ if (!condition.isEmpty())
+ m_breakPointConditions.add(fileName, lineNumber, condition);
}
void Debugger::removeBreakPoint(const QString &fileName, int lineNumber)
@@ -113,6 +207,14 @@ void Debugger::removeBreakPoint(const QString &fileName, int lineNumber)
if (!m_pendingBreakPointsToAdd.remove(fileName, lineNumber))
m_pendingBreakPointsToRemove.add(fileName, lineNumber);
m_havePendingBreakPoints = !m_pendingBreakPointsToAdd.isEmpty() || !m_pendingBreakPointsToRemove.isEmpty();
+ m_breakPointConditions.remove(fileName, lineNumber);
+}
+
+void Debugger::setBreakOnThrow(bool onoff)
+{
+ QMutexLocker locker(&m_lock);
+
+ m_breakOnThrow = onoff;
}
Debugger::ExecutionState Debugger::currentExecutionState(const uchar *code) const
@@ -122,20 +224,11 @@ Debugger::ExecutionState Debugger::currentExecutionState(const uchar *code) cons
// ### Locking
ExecutionState state;
- QV4::ExecutionContext *context = _engine->current;
- QV4::Function *function = 0;
- if (CallContext *callCtx = context->asCallContext())
- function = callCtx->function->function;
- else {
- Q_ASSERT(context->type == QV4::ExecutionContext::Type_GlobalContext);
- function = context->engine->globalCode;
- }
+ state.function = getFunction();
+ state.fileName = state.function->sourceFile();
- state.function = function;
- state.fileName = function->sourceFile();
-
- qptrdiff relativeProgramCounter = code - function->codeData;
- state.lineNumber = function->lineNumberForProgramCounter(relativeProgramCounter);
+ qptrdiff relativeProgramCounter = code - state.function->codeData;
+ state.lineNumber = state.function->lineNumberForProgramCounter(relativeProgramCounter);
return state;
}
@@ -145,49 +238,395 @@ void Debugger::setPendingBreakpoints(Function *function)
m_pendingBreakPointsToAddToFutureCode.applyToFunction(function, /*removeBreakPoints*/ false);
}
+QVector<StackFrame> Debugger::stackTrace(int frameLimit) const
+{
+ return m_engine->stackTrace(frameLimit);
+}
+
+static inline CallContext *findContext(ExecutionContext *ctxt, int frame)
+{
+ while (ctxt) {
+ CallContext *cCtxt = ctxt->asCallContext();
+ if (cCtxt && cCtxt->function) {
+ if (frame < 1)
+ return cCtxt;
+ --frame;
+ }
+ ctxt = ctxt->parent;
+ }
+
+ return 0;
+}
+
+static inline CallContext *findScope(ExecutionContext *ctxt, int scope)
+{
+ for (; scope > 0 && ctxt; --scope)
+ ctxt = ctxt->outer;
+
+ return ctxt ? ctxt->asCallContext() : 0;
+}
+
+void Debugger::collectArgumentsInContext(Collector *collector, int frameNr, int scopeNr)
+{
+ if (state() != Paused)
+ return;
+
+ class ArgumentCollectJob: public Job
+ {
+ QV4::ExecutionEngine *engine;
+ Collector *collector;
+ int frameNr;
+ int scopeNr;
+
+ public:
+ ArgumentCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, int scopeNr)
+ : engine(engine)
+ , collector(collector)
+ , frameNr(frameNr)
+ , scopeNr(scopeNr)
+ {}
+
+ ~ArgumentCollectJob() {}
+
+ void run()
+ {
+ if (frameNr < 0)
+ return;
+
+ CallContext *ctxt = findScope(findContext(engine->current, frameNr), scopeNr);
+ if (!ctxt)
+ return;
+
+ Scope scope(engine);
+ ScopedValue v(scope);
+ for (unsigned i = 0, ei = ctxt->formalCount(); i != ei; ++i) {
+ QString qName;
+ if (String *name = ctxt->formals()[i])
+ qName = name->toQString();
+ v = ctxt->argument(i);
+ collector->collect(qName, v);
+ }
+ }
+ };
+
+ ArgumentCollectJob job(m_engine, collector, frameNr, scopeNr);
+ runInEngine(&job);
+}
+
+/// Same as \c retrieveArgumentsFromContext, but now for locals.
+void Debugger::collectLocalsInContext(Collector *collector, int frameNr, int scopeNr)
+{
+ if (state() != Paused)
+ return;
+
+ class LocalCollectJob: public Job
+ {
+ QV4::ExecutionEngine *engine;
+ Collector *collector;
+ int frameNr;
+ int scopeNr;
+
+ public:
+ LocalCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, int scopeNr)
+ : engine(engine)
+ , collector(collector)
+ , frameNr(frameNr)
+ , scopeNr(scopeNr)
+ {}
+
+ void run()
+ {
+ if (frameNr < 0)
+ return;
+
+ CallContext *ctxt = findScope(findContext(engine->current, frameNr), scopeNr);
+ if (!ctxt)
+ return;
+
+ Scope scope(engine);
+ ScopedValue v(scope);
+ for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) {
+ QString qName;
+ if (String *name = ctxt->variables()[i])
+ qName = name->toQString();
+ v = ctxt->locals[i];
+ collector->collect(qName, v);
+ }
+ }
+ };
+
+ LocalCollectJob job(m_engine, collector, frameNr, scopeNr);
+ runInEngine(&job);
+}
+
+bool Debugger::collectThisInContext(Debugger::Collector *collector, int frame)
+{
+ if (state() != Paused)
+ return false;
+
+ class ThisCollectJob: public Job
+ {
+ QV4::ExecutionEngine *engine;
+ Collector *collector;
+ int frameNr;
+ bool *foundThis;
+
+ public:
+ ThisCollectJob(QV4::ExecutionEngine *engine, Collector *collector, int frameNr, bool *foundThis)
+ : engine(engine)
+ , collector(collector)
+ , frameNr(frameNr)
+ , foundThis(foundThis)
+ {}
+
+ void run()
+ {
+ *foundThis = myRun();
+ }
+
+ bool myRun()
+ {
+ ExecutionContext *ctxt = findContext(engine->current, frameNr);
+ while (ctxt) {
+ if (CallContext *cCtxt = ctxt->asCallContext())
+ if (cCtxt->activation)
+ break;
+ ctxt = ctxt->outer;
+ }
+
+ if (!ctxt)
+ return false;
+
+ Scope scope(engine);
+ ScopedObject o(scope, ctxt->asCallContext()->activation);
+ collector->collect(o);
+ return true;
+ }
+ };
+
+ bool foundThis = false;
+ ThisCollectJob job(m_engine, collector, frame, &foundThis);
+ runInEngine(&job);
+ return foundThis;
+}
+
+void Debugger::collectThrownValue(Collector *collector)
+{
+ if (state() != Paused || !m_engine->hasException)
+ return;
+
+ class ThisCollectJob: public Job
+ {
+ QV4::ExecutionEngine *engine;
+ Collector *collector;
+
+ public:
+ ThisCollectJob(QV4::ExecutionEngine *engine, Collector *collector)
+ : engine(engine)
+ , collector(collector)
+ {}
+
+ void run()
+ {
+ Scope scope(engine);
+ ScopedValue v(scope, engine->exceptionValue);
+ collector->collect(QStringLiteral("exception"), v);
+ }
+ };
+
+ ThisCollectJob job(m_engine, collector);
+ runInEngine(&job);
+}
+
+void Debugger::collectReturnedValue(Collector *collector) const
+{
+ if (state() != Paused)
+ return;
+
+ Scope scope(m_engine);
+ ScopedObject o(scope, m_returnedValue);
+ collector->collect(o);
+}
+
+QVector<ExecutionContext::Type> Debugger::getScopeTypes(int frame) const
+{
+ QVector<ExecutionContext::Type> types;
+
+ if (state() != Paused)
+ return types;
+
+ CallContext *sctxt = findContext(m_engine->current, frame);
+ if (!sctxt || sctxt->type < ExecutionContext::Type_SimpleCallContext)
+ return types;
+ CallContext *ctxt = static_cast<CallContext *>(sctxt);
+
+ for (ExecutionContext *it = ctxt; it; it = it->outer)
+ types.append(it->type);
+
+ return types;
+}
+
void Debugger::maybeBreakAtInstruction(const uchar *code, bool breakPointHit)
{
+ if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
+ return;
+
QMutexLocker locker(&m_lock);
m_currentInstructionPointer = code;
+ ExecutionState state = currentExecutionState();
+
// Do debugger internal work
if (m_havePendingBreakPoints) {
-
- if (breakPointHit) {
- ExecutionState state = currentExecutionState();
+ if (breakPointHit)
breakPointHit = !m_pendingBreakPointsToRemove.contains(state.fileName, state.lineNumber);
- }
applyPendingBreakPoints();
}
- // Serve debugging requests from the agent
- if (m_pauseRequested) {
+ if (m_gatherSources) {
+ m_gatherSources->run();
+ delete m_gatherSources;
+ m_gatherSources = 0;
+ }
+
+ if (m_stopForStepping) {
+ clearTemporaryBreakPoints();
+ m_stopForStepping = false;
+ m_pauseRequested = false;
+ pauseAndWait(Step);
+ } else if (m_pauseRequested) { // Serve debugging requests from the agent
m_pauseRequested = false;
- pauseAndWait();
- } else if (breakPointHit)
- pauseAndWait();
+ pauseAndWait(PauseRequest);
+ } else if (breakPointHit) {
+ if (m_stepping == StepOver && m_temporaryBreakPoints.context == m_engine->current)
+ pauseAndWait(Step);
+ else if (reallyHitTheBreakPoint(state.fileName, state.lineNumber))
+ pauseAndWait(BreakPoint);
+ }
if (!m_pendingBreakPointsToAdd.isEmpty() || !m_pendingBreakPointsToRemove.isEmpty())
applyPendingBreakPoints();
}
-void Debugger::aboutToThrow(const QV4::ValueRef value)
+void Debugger::enteringFunction()
+{
+ QMutexLocker locker(&m_lock);
+
+ if (m_stepping == StepIn) {
+ m_stepping = NotStepping;
+ m_stopForStepping = true;
+ m_pauseRequested = true;
+ }
+}
+
+void Debugger::leavingFunction(const ReturnedValue &retVal)
{
- qDebug() << "*** We are about to throw...";
+ Q_UNUSED(retVal); // TODO
+
+ QMutexLocker locker(&m_lock);
+
+ if ((m_stepping == StepOut || m_stepping == StepOver)
+ && temporaryBreakPointInFunction(m_engine->current)) {
+ clearTemporaryBreakPoints();
+ m_stepping = NotStepping;
+ m_stopForStepping = true;
+ m_pauseRequested = true;
+ m_returnedValue = retVal;
+ }
+}
+
+void Debugger::aboutToThrow()
+{
+ if (!m_breakOnThrow)
+ return;
+
+ if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
+ return;
+
+ QMutexLocker locker(&m_lock);
+ clearTemporaryBreakPoints();
+ pauseAndWait(Throwing);
+}
+
+Function *Debugger::getFunction() const
+{
+ ExecutionContext *context = m_engine->current;
+ if (CallContext *callCtx = context->asCallContext())
+ return callCtx->function->function;
+ else {
+ Q_ASSERT(context->type == QV4::ExecutionContext::Type_GlobalContext);
+ return context->engine->globalCode;
+ }
}
-void Debugger::pauseAndWait()
+void Debugger::pauseAndWait(PauseReason reason)
{
+ if (m_runningJob)
+ return;
+
m_state = Paused;
- QMetaObject::invokeMethod(m_agent, "debuggerPaused", Qt::QueuedConnection, Q_ARG(QV4::Debugging::Debugger*, this));
- m_runningCondition.wait(&m_lock);
+ QMetaObject::invokeMethod(m_agent, "debuggerPaused", Qt::QueuedConnection,
+ Q_ARG(QV4::Debugging::Debugger*, this),
+ Q_ARG(QV4::Debugging::PauseReason, reason));
+
+ while (true) {
+ m_runningCondition.wait(&m_lock);
+ if (m_runningJob) {
+ m_runningJob->run();
+ m_jobIsRunning.wakeAll();
+ } else {
+ break;
+ }
+ }
+
m_state = Running;
}
+void Debugger::setTemporaryBreakPointOnNextLine()
+{
+ ExecutionState state = currentExecutionState();
+ Function *function = state.function;
+ if (!function)
+ return;
+
+ QList<qptrdiff> pcs = function->programCountersForAllLines();
+ if (pcs.isEmpty())
+ return;
+
+ m_temporaryBreakPoints = TemporaryBreakPoint(function, m_engine->current);
+ m_temporaryBreakPoints.codeOffsets.reserve(pcs.size());
+ for (QList<qptrdiff>::const_iterator i = pcs.begin(), ei = pcs.end(); i != ei; ++i) {
+ // note: we do set a breakpoint on the current line, because there could be a loop where
+ // a step-over would be jump back to the first instruction making up the current line.
+ qptrdiff offset = *i;
+
+ if (hasBreakOnInstruction(function, offset))
+ continue; // do not set a temporary breakpoint if there already is a breakpoint set by the user
+
+ setBreakOnInstruction(function, offset, true);
+ m_temporaryBreakPoints.codeOffsets.append(offset);
+ }
+}
+
+void Debugger::clearTemporaryBreakPoints()
+{
+ if (m_temporaryBreakPoints.function) {
+ foreach (quintptr offset, m_temporaryBreakPoints.codeOffsets)
+ setBreakOnInstruction(m_temporaryBreakPoints.function, offset, false);
+ m_temporaryBreakPoints = TemporaryBreakPoint();
+ }
+}
+
+bool Debugger::temporaryBreakPointInFunction(ExecutionContext *context) const
+{
+ return m_temporaryBreakPoints.function == getFunction()
+ && m_temporaryBreakPoints.context == context;
+}
+
void Debugger::applyPendingBreakPoints()
{
- foreach (QV4::CompiledData::CompilationUnit *unit, _engine->compilationUnits) {
+ foreach (QV4::CompiledData::CompilationUnit *unit, m_engine->compilationUnits) {
foreach (Function *function, unit->runtimeFunctions) {
m_pendingBreakPointsToAdd.applyToFunction(function, /*removeBreakPoints*/false);
m_pendingBreakPointsToRemove.applyToFunction(function, /*removeBreakPoints*/true);
@@ -205,97 +644,62 @@ void Debugger::applyPendingBreakPoints()
m_havePendingBreakPoints = false;
}
-static void realDumpValue(const QV4::ValueRef v, QV4::ExecutionContext *ctx, std::string prefix)
+void Debugger::setBreakOnInstruction(Function *function, qptrdiff codeOffset, bool onoff)
{
- using namespace QV4;
- using namespace std;
-
- Scope scope(ctx);
-
- cout << prefix << "tag: " << hex << v->tag << dec << endl << prefix << "\t-> ";
- switch (v->type()) {
- case Value::Undefined_Type: cout << "Undefined"; return;
- case Value::Null_Type: cout << "Null"; return;
- case Value::Boolean_Type: cout << "Boolean"; break;
- case Value::Integer_Type: cout << "Integer"; break;
- case Value::Managed_Type: cout << v->managed()->className().toUtf8().data(); break;
- default: cout << "UNKNOWN" << endl; return;
- }
- cout << endl;
-
- if (v->isBoolean()) {
- cout << prefix << "\t-> " << (v->booleanValue() ? "TRUE" : "FALSE") << endl;
- return;
- }
-
- if (v->isInteger()) {
- cout << prefix << "\t-> " << v->integerValue() << endl;
- return;
- }
-
- if (v->isDouble()) {
- cout << prefix << "\t-> " << v->doubleValue() << endl;
- return;
- }
+ uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
+ QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
+ instruction->common.breakPoint = onoff;
+}
- if (v->isString()) {
- // maybe check something on the Managed object?
- cout << prefix << "\t-> @" << hex << v->stringValue() << endl;
- cout << prefix << "\t-> \"" << qPrintable(v->stringValue()->toQString()) << "\"" << endl;
- return;
- }
+bool Debugger::hasBreakOnInstruction(Function *function, qptrdiff codeOffset)
+{
+ uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
+ QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
+ return instruction->common.breakPoint;
+}
- ScopedObject o(scope, v);
- if (!o)
- return;
+bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
+{
+ QString condition = m_breakPointConditions.condition(filename, linenr);
+ if (condition.isEmpty())
+ return true;
- cout << prefix << "\t-> @" << hex << o << endl;
- cout << prefix << "object type: " << o->internalType() << endl << prefix << "\t-> ";
- switch (o->internalType()) {
- case QV4::Managed::Type_Invalid: cout << "Invalid"; break;
- case QV4::Managed::Type_String: cout << "String"; break;
- case QV4::Managed::Type_Object: cout << "Object"; break;
- case QV4::Managed::Type_ArrayObject: cout << "ArrayObject"; break;
- case QV4::Managed::Type_FunctionObject: cout << "FunctionObject"; break;
- case QV4::Managed::Type_BooleanObject: cout << "BooleanObject"; break;
- case QV4::Managed::Type_NumberObject: cout << "NumberObject"; break;
- case QV4::Managed::Type_StringObject: cout << "StringObject"; break;
- case QV4::Managed::Type_DateObject: cout << "DateObject"; break;
- case QV4::Managed::Type_RegExpObject: cout << "RegExpObject"; break;
- case QV4::Managed::Type_ErrorObject: cout << "ErrorObject"; break;
- case QV4::Managed::Type_ArgumentsObject: cout << "ArgumentsObject"; break;
- case QV4::Managed::Type_JSONObject: cout << "JSONObject"; break;
- case QV4::Managed::Type_MathObject: cout << "MathObject"; break;
- case QV4::Managed::Type_ForeachIteratorObject: cout << "ForeachIteratorObject"; break;
- default: cout << "UNKNOWN" << endl; return;
- }
- cout << endl;
+ Q_ASSERT(m_runningJob == 0);
+ EvalJob evilJob(m_engine, condition);
+ m_runningJob = &evilJob;
+ m_runningJob->run();
- cout << prefix << "properties:" << endl;
- ForEachIteratorObject it(ctx, o);
- ScopedValue name(scope);
- ScopedValue pval(scope);
- for (name = it.nextPropertyName(); !name->isNull(); name = it.nextPropertyName()) {
- cout << prefix << "\t\"" << qPrintable(name->stringValue()->toQString()) << "\"" << endl;
- PropertyAttributes attrs;
- Property *d = o->__getOwnProperty__(ScopedString(scope, name), &attrs);
- pval = o->getValue(d, attrs);
- cout << prefix << "\tvalue:" << endl;
- realDumpValue(pval, ctx, prefix + "\t");
- }
+ return evilJob.resultAsBoolean();
}
-void dumpValue(const QV4::ValueRef v, QV4::ExecutionContext *ctx)
+void Debugger::runInEngine(Debugger::Job *job)
{
- realDumpValue(v, ctx, std::string(""));
+ QMutexLocker locker(&m_lock);
+ runInEngine_havingLock(job);
}
+void Debugger::runInEngine_havingLock(Debugger::Job *job)
+{
+ Q_ASSERT(job);
+ Q_ASSERT(m_runningJob == 0);
+
+ m_runningJob = job;
+ m_runningCondition.wakeAll();
+ m_jobIsRunning.wait(&m_lock);
+ m_runningJob = 0;
+}
void DebuggerAgent::addDebugger(Debugger *debugger)
{
Q_ASSERT(!m_debuggers.contains(debugger));
m_debuggers << debugger;
debugger->attachToAgent(this);
+
+ debugger->setBreakOnThrow(m_breakOnThrow);
+
+ foreach (const BreakPoint &breakPoint, m_breakPoints.values())
+ if (breakPoint.enabled)
+ debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
}
void DebuggerAgent::removeDebugger(Debugger *debugger)
@@ -315,16 +719,77 @@ void DebuggerAgent::pauseAll() const
pause(debugger);
}
-void DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber) const
+void DebuggerAgent::resumeAll() const
{
foreach (Debugger *debugger, m_debuggers)
- debugger->addBreakPoint(fileName, lineNumber);
+ if (debugger->state() == Debugger::Paused)
+ debugger->resume(Debugger::FullThrottle);
}
-void DebuggerAgent::removeBreakPoint(const QString &fileName, int lineNumber) const
+int DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
{
- foreach (Debugger *debugger, m_debuggers)
- debugger->removeBreakPoint(fileName, lineNumber);
+ if (enabled)
+ foreach (Debugger *debugger, m_debuggers)
+ debugger->addBreakPoint(fileName, lineNumber, condition);
+
+ int id = m_breakPoints.size();
+ m_breakPoints.insert(id, BreakPoint(fileName, lineNumber, enabled, condition));
+ return id;
+}
+
+void DebuggerAgent::removeBreakPoint(int id)
+{
+ BreakPoint breakPoint = m_breakPoints.value(id);
+ if (!breakPoint.isValid())
+ return;
+
+ m_breakPoints.remove(id);
+
+ if (breakPoint.enabled)
+ foreach (Debugger *debugger, m_debuggers)
+ debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
+}
+
+void DebuggerAgent::removeAllBreakPoints()
+{
+ QList<int> ids = m_breakPoints.keys();
+ foreach (int id, ids)
+ removeBreakPoint(id);
+}
+
+void DebuggerAgent::enableBreakPoint(int id, bool onoff)
+{
+ BreakPoint &breakPoint = m_breakPoints[id];
+ if (!breakPoint.isValid() || breakPoint.enabled == onoff)
+ return;
+ breakPoint.enabled = onoff;
+
+ foreach (Debugger *debugger, m_debuggers) {
+ if (onoff)
+ debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
+ else
+ debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
+ }
+}
+
+QList<int> DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const
+{
+ QList<int> ids;
+
+ for (QHash<int, BreakPoint>::const_iterator i = m_breakPoints.begin(), ei = m_breakPoints.end(); i != ei; ++i)
+ if (i->lineNr == lineNumber && fileName.endsWith(i->fileName))
+ ids.push_back(i.key());
+
+ return ids;
+}
+
+void DebuggerAgent::setBreakOnThrow(bool onoff)
+{
+ if (onoff != m_breakOnThrow) {
+ m_breakOnThrow = onoff;
+ foreach (Debugger *debugger, m_debuggers)
+ debugger->setBreakOnThrow(onoff);
+ }
}
DebuggerAgent::~DebuggerAgent()
@@ -359,32 +824,99 @@ bool Debugger::BreakPoints::contains(const QString &fileName, int lineNumber) co
void Debugger::BreakPoints::applyToFunction(Function *function, bool removeBreakPoints)
{
- Iterator breakPointsForFile = find(function->sourceFile());
- if (breakPointsForFile == end())
- return;
+ Iterator breakPointsForFile = begin();
- QList<int>::Iterator breakPoint = breakPointsForFile->begin();
- while (breakPoint != breakPointsForFile->end()) {
- bool breakPointFound = false;
- const quint32 *lineNumberMappings = function->compiledFunction->lineNumberMapping();
- for (int i = 0; i < function->compiledFunction->nLineNumberMappingEntries; ++i) {
- const int codeOffset = lineNumberMappings[i * 2];
- const int lineNumber = lineNumberMappings[i * 2 + 1];
- if (lineNumber == *breakPoint) {
- uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
- QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
- instruction->common.breakPoint = !removeBreakPoints;
- // Continue setting the next break point.
- breakPointFound = true;
- break;
+ while (breakPointsForFile != end()) {
+ if (!function->sourceFile().endsWith(breakPointsForFile.key())) {
+ ++breakPointsForFile;
+ continue;
+ }
+
+ QList<int>::Iterator breakPoint = breakPointsForFile->begin();
+ while (breakPoint != breakPointsForFile->end()) {
+ bool breakPointFound = false;
+ const quint32 *lineNumberMappings = function->compiledFunction->lineNumberMapping();
+ for (quint32 i = 0; i < function->compiledFunction->nLineNumberMappingEntries; ++i) {
+ const int codeOffset = lineNumberMappings[i * 2];
+ const int lineNumber = lineNumberMappings[i * 2 + 1];
+ if (lineNumber == *breakPoint) {
+ setBreakOnInstruction(function, codeOffset, !removeBreakPoints);
+ // Continue setting the next break point.
+ breakPointFound = true;
+ break;
+ }
}
+ if (breakPointFound)
+ breakPoint = breakPointsForFile->erase(breakPoint);
+ else
+ ++breakPoint;
}
- if (breakPointFound)
- breakPoint = breakPointsForFile->erase(breakPoint);
+
+ if (breakPointsForFile->isEmpty())
+ breakPointsForFile = erase(breakPointsForFile);
+ else
+ ++breakPointsForFile;
+ }
+}
+
+
+Debugger::Collector::~Collector()
+{
+}
+
+void Debugger::Collector::collect(const QString &name, const ScopedValue &value)
+{
+ switch (value->type()) {
+ case Value::Empty_Type:
+ Q_ASSERT(!"empty Value encountered");
+ break;
+ case Value::Undefined_Type:
+ addUndefined(name);
+ break;
+ case Value::Null_Type:
+ addNull(name);
+ break;
+ case Value::Boolean_Type:
+ addBoolean(name, value->booleanValue());
+ break;
+ case Value::Managed_Type:
+ if (String *s = value->asString())
+ addString(name, s->toQString());
else
- ++breakPoint;
+ addObject(name, value);
+ break;
+ case Value::Integer_Type:
+ addInteger(name, value->int_32);
+ break;
+ default: // double
+ addDouble(name, value->doubleValue());
+ break;
}
+}
+
+void Debugger::Collector::collect(const ObjectRef object)
+{
+ bool property = true;
+ qSwap(property, m_isProperty);
- if (breakPointsForFile->isEmpty())
- erase(breakPointsForFile);
+ Scope scope(m_engine);
+ ObjectIterator it(scope, object, ObjectIterator::EnumerableOnly);
+ ScopedValue name(scope);
+ ScopedValue value(scope);
+ while (true) {
+ Value v;
+ name = it.nextPropertyNameAsString(&v);
+ if (name->isNull())
+ break;
+ QString key = name->toQStringNoThrow();
+ value = v;
+ collect(key, value);
+ }
+
+ qSwap(property, m_isProperty);
+}
+
+
+Debugger::Job::~Job()
+{
}
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index e44f415da4..98b549995e 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -45,6 +45,7 @@
#include "qv4global_p.h"
#include "qv4engine_p.h"
#include "qv4context_p.h"
+#include "qv4scopedvalue_p.h"
#include <QHash>
#include <QThread>
@@ -59,30 +60,88 @@ struct Function;
namespace Debugging {
+enum PauseReason {
+ PauseRequest,
+ BreakPoint,
+ Throwing,
+ Step
+};
+
class DebuggerAgent;
class Q_QML_EXPORT Debugger
{
public:
+ class Job
+ {
+ public:
+ virtual ~Job() = 0;
+ virtual void run() = 0;
+ };
+
+ class Q_QML_EXPORT Collector
+ {
+ public:
+ Collector(ExecutionEngine *engine): m_engine(engine), m_isProperty(false) {}
+ virtual ~Collector();
+
+ void collect(const QString &name, const ScopedValue &value);
+ void collect(const ObjectRef object);
+
+ protected:
+ virtual void addUndefined(const QString &name) = 0;
+ virtual void addNull(const QString &name) = 0;
+ virtual void addBoolean(const QString &name, bool value) = 0;
+ virtual void addString(const QString &name, const QString &value) = 0;
+ virtual void addObject(const QString &name, ValueRef value) = 0;
+ virtual void addInteger(const QString &name, int value) = 0;
+ virtual void addDouble(const QString &name, double value) = 0;
+
+ QV4::ExecutionEngine *engine() const { return m_engine; }
+
+ bool isProperty() const { return m_isProperty; }
+ void setIsProperty(bool onoff) { m_isProperty = onoff; }
+
+ private:
+ QV4::ExecutionEngine *m_engine;
+ bool m_isProperty;
+ };
+
enum State {
Running,
Paused
};
- Debugger(ExecutionEngine *_engine);
+ enum Speed {
+ FullThrottle = 0,
+ StepIn,
+ StepOut,
+ StepOver,
+
+ NotStepping = FullThrottle
+ };
+
+ Debugger(ExecutionEngine *engine);
~Debugger();
+ ExecutionEngine *engine() const
+ { return m_engine; }
+
void attachToAgent(DebuggerAgent *agent);
void detachFromAgent();
+ DebuggerAgent *agent() const { return m_agent; }
+ void gatherSources(int requestSequenceNr);
void pause();
- void resume();
+ void resume(Speed speed);
State state() const { return m_state; }
- void addBreakPoint(const QString &fileName, int lineNumber);
+ void addBreakPoint(const QString &fileName, int lineNumber, const QString &condition = QString());
void removeBreakPoint(const QString &fileName, int lineNumber);
+ void setBreakOnThrow(bool onoff);
+
struct ExecutionState
{
ExecutionState() : lineNumber(-1), function(0) {}
@@ -94,22 +153,47 @@ public:
ExecutionState currentExecutionState(const uchar *code = 0) const;
bool pauseAtNextOpportunity() const {
- return m_pauseRequested || m_havePendingBreakPoints;
+ return m_pauseRequested || m_havePendingBreakPoints || m_gatherSources;
}
void setPendingBreakpoints(Function *function);
+ QVector<StackFrame> stackTrace(int frameLimit = -1) const;
+ void collectArgumentsInContext(Collector *collector, int frameNr = 0, int scopeNr = 0);
+ void collectLocalsInContext(Collector *collector, int frameNr = 0, int scopeNr = 0);
+ bool collectThisInContext(Collector *collector, int frame = 0);
+ void collectThrownValue(Collector *collector);
+ void collectReturnedValue(Collector *collector) const;
+ QVector<ExecutionContext::Type> getScopeTypes(int frame = 0) const;
+
public: // compile-time interface
void maybeBreakAtInstruction(const uchar *code, bool breakPointHit);
public: // execution hooks
- void aboutToThrow(const ValueRef value);
+ void enteringFunction();
+ void leavingFunction(const ReturnedValue &retVal);
+ void aboutToThrow();
private:
+ Function *getFunction() const;
+
+ // requires lock to be held
+ void pauseAndWait(PauseReason reason);
+ // requires lock to be held
+ void setTemporaryBreakPointOnNextLine();
// requires lock to be held
- void pauseAndWait();
+ void clearTemporaryBreakPoints();
+ // requires lock to be held
+ bool temporaryBreakPointInFunction(ExecutionContext *context) const;
void applyPendingBreakPoints();
+ static void setBreakOnInstruction(Function *function, qptrdiff codeOffset, bool onoff);
+ static bool hasBreakOnInstruction(Function *function, qptrdiff codeOffset);
+ bool reallyHitTheBreakPoint(const QString &filename, int linenr);
+
+ void runInEngine(Job *job);
+ void runInEngine_havingLock(Debugger::Job *job);
+private:
struct BreakPoints : public QHash<QString, QList<int> >
{
void add(const QString &fileName, int lineNumber);
@@ -118,23 +202,60 @@ private:
void applyToFunction(Function *function, bool removeBreakPoints);
};
- QV4::ExecutionEngine *_engine;
+ QV4::ExecutionEngine *m_engine;
DebuggerAgent *m_agent;
QMutex m_lock;
QWaitCondition m_runningCondition;
State m_state;
bool m_pauseRequested;
+ Job *m_gatherSources;
bool m_havePendingBreakPoints;
BreakPoints m_pendingBreakPointsToAdd;
BreakPoints m_pendingBreakPointsToAddToFutureCode;
BreakPoints m_pendingBreakPointsToRemove;
const uchar *m_currentInstructionPointer;
+ Speed m_stepping;
+ bool m_stopForStepping;
+ QV4::PersistentValue m_returnedValue;
+
+ struct TemporaryBreakPoint {
+ Function *function;
+ QVector<qptrdiff> codeOffsets;
+ ExecutionContext *context;
+ TemporaryBreakPoint(): function(0), context(0) {}
+ TemporaryBreakPoint(Function *function, ExecutionContext *context)
+ : function(function)
+ , context(context)
+ {}
+ } m_temporaryBreakPoints;
+
+ bool m_breakOnThrow;
+
+ Job *m_runningJob;
+ QWaitCondition m_jobIsRunning;
+
+ struct BreakPointConditions: public QHash<QString, QString>
+ {
+ static QString genKey(const QString &fileName, int lineNumber)
+ {
+ return fileName + QLatin1Char(':') + QString::number(lineNumber);
+ }
+
+ QString condition(const QString &fileName, int lineNumber)
+ { return value(genKey(fileName, lineNumber)); }
+ void add(const QString &fileName, int lineNumber, const QString &condition)
+ { insert(genKey(fileName, lineNumber), condition); }
+ void remove(const QString &fileName, int lineNumber)
+ { take(genKey(fileName, lineNumber)); }
+ };
+ BreakPointConditions m_breakPointConditions;
};
class Q_QML_EXPORT DebuggerAgent : public QObject
{
Q_OBJECT
public:
+ DebuggerAgent(): m_breakOnThrow(false) {}
~DebuggerAgent();
void addDebugger(Debugger *debugger);
@@ -142,13 +263,40 @@ public:
void pause(Debugger *debugger) const;
void pauseAll() const;
- void addBreakPoint(const QString &fileName, int lineNumber) const;
- void removeBreakPoint(const QString &fileName, int lineNumber) const;
+ void resumeAll() const;
+ int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString());
+ void removeBreakPoint(int id);
+ void removeAllBreakPoints();
+ void enableBreakPoint(int id, bool onoff);
+ QList<int> breakPointIds(const QString &fileName, int lineNumber) const;
+
+ bool breakOnThrow() const { return m_breakOnThrow; }
+ void setBreakOnThrow(bool onoff);
- Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger) = 0;
+ Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger,
+ QV4::Debugging::PauseReason reason) = 0;
+ Q_INVOKABLE virtual void sourcesCollected(QV4::Debugging::Debugger *debugger,
+ QStringList sources, int requestSequenceNr) = 0;
protected:
QList<Debugger *> m_debuggers;
+
+ struct BreakPoint {
+ QString fileName;
+ int lineNr;
+ bool enabled;
+ QString condition;
+
+ BreakPoint(): lineNr(-1), enabled(false) {}
+ BreakPoint(const QString &fileName, int lineNr, bool enabled, const QString &condition)
+ : fileName(fileName), lineNr(lineNr), enabled(enabled), condition(condition)
+ {}
+
+ bool isValid() const { return lineNr >= 0 && !fileName.isEmpty(); }
+ };
+
+ QHash<int, BreakPoint> m_breakPoints;
+ bool m_breakOnThrow;
};
} // namespace Debugging
@@ -157,5 +305,6 @@ protected:
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QV4::Debugging::Debugger*)
+Q_DECLARE_METATYPE(QV4::Debugging::PauseReason)
#endif // DEBUGGING_H
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 2c68c4f400..f5a515a0ae 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -60,7 +60,6 @@
#include <qv4jsonobject_p.h>
#include <qv4stringobject_p.h>
#include <qv4identifiertable_p.h>
-#include <qv4unwindhelper_p.h>
#include "qv4debugging_p.h"
#include "qv4executableallocator_p.h"
#include "qv4sequenceobject_p.h"
@@ -73,18 +72,64 @@
#include "qv4isel_moth_p.h"
+#if USE(PTHREADS)
+# include <pthread.h>
+#endif
+
QT_BEGIN_NAMESPACE
using namespace QV4;
static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
-static ReturnedValue throwTypeError(SimpleCallContext *ctx)
+static ReturnedValue throwTypeError(CallContext *ctx)
{
- ctx->throwTypeError();
- return Encode::undefined();
+ return ctx->throwTypeError();
+}
+
+quintptr getStackLimit()
+{
+ quintptr stackLimit;
+#if USE(PTHREADS) && !OS(QNX)
+# if OS(DARWIN)
+ pthread_t thread_self = pthread_self();
+ void *stackTop = pthread_get_stackaddr_np(thread_self);
+ stackLimit = reinterpret_cast<quintptr>(stackTop);
+ quintptr size = 0;
+ if (pthread_main_np()) {
+ rlimit limit;
+ getrlimit(RLIMIT_STACK, &limit);
+ size = limit.rlim_cur;
+ } else
+ size = pthread_get_stacksize_np(thread_self);
+ stackLimit -= size;
+# else
+ void* stackBottom = 0;
+ pthread_attr_t attr;
+ pthread_getattr_np(pthread_self(), &attr);
+ size_t stackSize = 0;
+ pthread_attr_getstack(&attr, &stackBottom, &stackSize);
+ pthread_attr_destroy(&attr);
+
+ stackLimit = reinterpret_cast<quintptr>(stackBottom);
+# endif
+// This is wrong. StackLimit is the currently committed stack size, not the real end.
+// only way to get that limit is apparently by using VirtualQuery (Yuck)
+//#elif OS(WINDOWS)
+// PNT_TIB tib = (PNT_TIB)NtCurrentTeb();
+// stackLimit = static_cast<quintptr>(tib->StackLimit);
+#else
+ int dummy;
+ // this is inexact, as part of the stack is used when being called here,
+ // but let's simply default to 1MB from where the stack is right now
+ stackLimit = reinterpret_cast<qintptr>(&dummy) - 1024*1024;
+#endif
+
+ // 256k slack
+ return stackLimit + 256*1024;
}
+
ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
: memoryManager(new QV4::MemoryManager)
, executableAllocator(new QV4::ExecutableAllocator)
@@ -120,11 +165,17 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
memoryManager->setExecutionEngine(this);
- // reserve 8MB for the JS stack
- *jsStack = WTF::PageAllocation::allocate(8*1024*1024, WTF::OSAllocator::JSVMStackPages, true);
+ // reserve space for the JS stack
+ // we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection
+ // and ScopedValues allocated outside of JIT'ed methods.
+ *jsStack = WTF::PageAllocation::allocate(2*JSStackLimit, WTF::OSAllocator::JSVMStackPages, true);
jsStackBase = (SafeValue *)jsStack->base();
jsStackTop = jsStackBase;
+ // set up stack limits
+ jsStackLimit = jsStackBase + JSStackLimit/sizeof(SafeValue);
+ cStackLimit = getStackLimit();
+
Scope scope(this);
identifierTable = new IdentifierTable(this);
@@ -338,7 +389,8 @@ void ExecutionEngine::enableDebugger()
void ExecutionEngine::initRootContext()
{
- rootContext = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext) + sizeof(CallData)));
+ rootContext = static_cast<GlobalContext *>(memoryManager->allocManaged(sizeof(GlobalContext) + sizeof(CallData)));
+ rootContext->init();
current = rootContext;
current->parent = 0;
rootContext->initGlobalContext(this);
@@ -351,9 +403,9 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other)
ExecutionContext *ExecutionEngine::pushGlobalContext()
{
- GlobalContext *g = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext)));
+ GlobalContext *g = new (memoryManager) GlobalContext;
ExecutionContext *oldNext = g->next;
- *g = *rootContext;
+ memcpy(g, rootContext, sizeof(GlobalContext));
g->next = oldNext;
g->parent = current;
current = g;
@@ -361,7 +413,7 @@ ExecutionContext *ExecutionEngine::pushGlobalContext()
return current;
}
-Returned<FunctionObject> *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(SimpleCallContext *))
+Returned<FunctionObject> *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *))
{
BuiltinFunction *f = new (memoryManager) BuiltinFunction(scope, name, code);
return f->asReturned<FunctionObject>();
@@ -548,7 +600,7 @@ Returned<Object> *ExecutionEngine::qmlContextObject() const
{
ExecutionContext *ctx = current;
- if (ctx->type == QV4::ExecutionContext::Type_SimpleCallContext)
+ if (ctx->type == QV4::ExecutionContext::Type_SimpleCallContext && !ctx->outer)
ctx = ctx->parent;
if (!ctx->outer)
@@ -557,7 +609,7 @@ Returned<Object> *ExecutionEngine::qmlContextObject() const
while (ctx->outer && ctx->outer->type != ExecutionContext::Type_GlobalContext)
ctx = ctx->outer;
- assert(ctx);
+ Q_ASSERT(ctx);
if (ctx->type != ExecutionContext::Type_QmlContext)
return 0;
@@ -576,11 +628,12 @@ namespace {
void resolve(StackFrame *frame, ExecutionContext *context, Function *function)
{
qptrdiff offset;
- if (context->interpreterInstructionPointer)
+ if (context->interpreterInstructionPointer) {
offset = *context->interpreterInstructionPointer - 1 - function->codeData;
- else
- offset = context->jitInstructionPointer - (char*)function->codePtr;
- frame->line = function->lineNumberForProgramCounter(offset);
+ frame->line = function->lineNumberForProgramCounter(offset);
+ } else {
+ frame->line = context->lineNumber;
+ }
}
};
}
@@ -593,7 +646,8 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
QV4::ExecutionContext *c = current;
while (c && frameLimit) {
- if (CallContext *callCtx = c->asCallContext()) {
+ CallContext *callCtx = c->asCallContext();
+ if (callCtx && callCtx->function) {
StackFrame frame;
if (callCtx->function->function)
frame.source = callCtx->function->function->sourceFile();
@@ -646,7 +700,8 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
QUrl base;
QV4::ExecutionContext *c = current;
while (c) {
- if (CallContext *callCtx = c->asCallContext()) {
+ CallContext *callCtx = c->asCallContext();
+ if (callCtx && callCtx->function) {
if (callCtx->function->function)
base.setUrl(callCtx->function->function->sourceFile());
break;
@@ -684,76 +739,76 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
void ExecutionEngine::markObjects()
{
- identifierTable->mark();
+ identifierTable->mark(this);
- globalObject->mark();
+ globalObject->mark(this);
if (globalCode)
- globalCode->mark();
+ globalCode->mark(this);
for (int i = 0; i < argumentsAccessors.size(); ++i) {
const Property &pd = argumentsAccessors.at(i);
if (FunctionObject *getter = pd.getter())
- getter->mark();
+ getter->mark(this);
if (FunctionObject *setter = pd.setter())
- setter->mark();
+ setter->mark(this);
}
ExecutionContext *c = current;
while (c) {
- c->mark();
+ c->mark(this);
c = c->parent;
}
- id_length->mark();
- id_prototype->mark();
- id_constructor->mark();
- id_arguments->mark();
- id_caller->mark();
- id_this->mark();
- id___proto__->mark();
- id_enumerable->mark();
- id_configurable->mark();
- id_writable->mark();
- id_value->mark();
- id_get->mark();
- id_set->mark();
- id_eval->mark();
- id_uintMax->mark();
- id_name->mark();
- id_index->mark();
- id_input->mark();
- id_toString->mark();
- id_valueOf->mark();
-
- objectCtor.mark();
- stringCtor.mark();
- numberCtor.mark();
- booleanCtor.mark();
- arrayCtor.mark();
- functionCtor.mark();
- dateCtor.mark();
- regExpCtor.mark();
- errorCtor.mark();
- evalErrorCtor.mark();
- rangeErrorCtor.mark();
- referenceErrorCtor.mark();
- syntaxErrorCtor.mark();
- typeErrorCtor.mark();
- uRIErrorCtor.mark();
-
- exceptionValue.mark();
-
- thrower->mark();
+ id_length->mark(this);
+ id_prototype->mark(this);
+ id_constructor->mark(this);
+ id_arguments->mark(this);
+ id_caller->mark(this);
+ id_this->mark(this);
+ id___proto__->mark(this);
+ id_enumerable->mark(this);
+ id_configurable->mark(this);
+ id_writable->mark(this);
+ id_value->mark(this);
+ id_get->mark(this);
+ id_set->mark(this);
+ id_eval->mark(this);
+ id_uintMax->mark(this);
+ id_name->mark(this);
+ id_index->mark(this);
+ id_input->mark(this);
+ id_toString->mark(this);
+ id_valueOf->mark(this);
+
+ objectCtor.mark(this);
+ stringCtor.mark(this);
+ numberCtor.mark(this);
+ booleanCtor.mark(this);
+ arrayCtor.mark(this);
+ functionCtor.mark(this);
+ dateCtor.mark(this);
+ regExpCtor.mark(this);
+ errorCtor.mark(this);
+ evalErrorCtor.mark(this);
+ rangeErrorCtor.mark(this);
+ referenceErrorCtor.mark(this);
+ syntaxErrorCtor.mark(this);
+ typeErrorCtor.mark(this);
+ uRIErrorCtor.mark(this);
+
+ exceptionValue.mark(this);
+
+ thrower->mark(this);
if (m_qmlExtensions)
- m_qmlExtensions->markObjects();
+ m_qmlExtensions->markObjects(this);
emptyClass->markObjects();
for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
it != end; ++it)
- (*it)->markObjects();
+ (*it)->markObjects(this);
}
namespace {
@@ -807,9 +862,15 @@ QmlExtensions *ExecutionEngine::qmlExtensions()
return m_qmlExtensions;
}
-void ExecutionEngine::throwException(const ValueRef value)
+ReturnedValue ExecutionEngine::throwException(const ValueRef value)
{
- Q_ASSERT(!hasException);
+ // we can get in here with an exception already set, as the runtime
+ // doesn't check after every operation that can throw.
+ // in this case preserve the first exception to give correct error
+ // information
+ if (hasException)
+ return Encode::undefined();
+
hasException = true;
exceptionValue = value;
QV4::Scope scope(this);
@@ -820,10 +881,9 @@ void ExecutionEngine::throwException(const ValueRef value)
exceptionStackTrace = stackTrace();
if (debugger)
- debugger->aboutToThrow(value);
+ debugger->aboutToThrow();
- UnwindHelper::prepareForUnwind(current);
- throwInternal();
+ return Encode::undefined();
}
ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, StackTrace *trace)
@@ -836,11 +896,11 @@ ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext,
exceptionStackTrace.clear();
hasException = false;
ReturnedValue res = exceptionValue.asReturnedValue();
- exceptionValue = Encode::undefined();
+ exceptionValue = Primitive::emptyValue();
return res;
}
-QQmlError ExecutionEngine::convertJavaScriptException(ExecutionContext *context)
+QQmlError ExecutionEngine::catchExceptionAsQmlError(ExecutionContext *context)
{
QV4::StackTrace trace;
QV4::Scope scope(context);
@@ -854,7 +914,7 @@ QQmlError ExecutionEngine::convertJavaScriptException(ExecutionContext *context)
}
QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
if (!!errorObj && errorObj->asSyntaxError()) {
- QV4::ScopedString m(scope, errorObj->engine()->newString("message"));
+ QV4::ScopedString m(scope, errorObj->engine()->newString(QStringLiteral("message")));
QV4::ScopedValue v(scope, errorObj->get(m));
error.setDescription(v->toQStringNoThrow());
} else
@@ -862,14 +922,19 @@ QQmlError ExecutionEngine::convertJavaScriptException(ExecutionContext *context)
return error;
}
-#if !defined(V4_CXX_ABI_EXCEPTION)
-struct DummyException
-{};
-
-void ExecutionEngine::throwInternal()
+bool ExecutionEngine::recheckCStackLimits()
{
- throw DummyException();
-}
+ int dummy;
+#ifdef Q_OS_WIN
+ // ### this is only required on windows, where we currently use heuristics to get the stack limit
+ if (cStackLimit - reinterpret_cast<quintptr>(&dummy) > 128*1024)
+ // we're more then 128k away from our stack limit, assume the thread has changed, and
+ // call getStackLimit
#endif
+ // this can happen after a thread change
+ cStackLimit = getStackLimit();
+
+ return (reinterpret_cast<quintptr>(&dummy) >= cStackLimit);
+}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4engine_cxxabi.cpp b/src/qml/jsruntime/qv4engine_cxxabi.cpp
deleted file mode 100644
index f29af5a284..0000000000
--- a/src/qml/jsruntime/qv4engine_cxxabi.cpp
+++ /dev/null
@@ -1,156 +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 "qv4engine_p.h"
-
-#if defined(V4_CXX_ABI_EXCEPTION)
-
-// On arm we link libgcc statically and want to avoid exporting the _Unwind* symbols
-#if defined(Q_PROCESSOR_ARM)
-#define HIDE_EXPORTS
-#endif
-
-#include <unwind.h>
-#include <exception>
-
-namespace {
-
-// 2.1.1 from http://mentorembedded.github.io/cxx-abi/abi-eh.html
-struct cxa_exception {
- std::type_info *typeInfo;
- void (*exceptionDestructor)(void*);
- std::unexpected_handler unexpectedHandler;
- std::terminate_handler terminateHandler;
- cxa_exception *nextException;
- int handlerCount;
-#ifdef __ARM_EABI_UNWINDER__
- cxa_exception *nextPropagatingException;
- int propagationCount;
-#else
- int handlerSwitchValue;
- const char *actionRecord;
- const char *languageSpecificData;
- void *catchTemp;
- void *adjustedPtr;
-#endif
- _Unwind_Exception unwindHeader;
-};
-
-struct cxa_eh_globals
-{
- cxa_exception *caughtExceptions;
- unsigned int uncaughtExceptions;
-#ifdef __ARM_EABI_UNWINDER__
- cxa_exception* propagatingExceptions;
-#endif
-};
-
-}
-
-extern "C" cxa_eh_globals *__cxa_get_globals();
-
-static void exception_cleanup(_Unwind_Reason_Code, _Unwind_Exception *ex)
-{
- free(ex);
-}
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-void ExecutionEngine::throwInternal()
-{
- _Unwind_Exception *exception = (_Unwind_Exception*)malloc(sizeof(_Unwind_Exception));
- memset(exception, 0, sizeof(*exception));
- exception->exception_cleanup = &exception_cleanup;
-
-#ifdef __ARM_EABI_UNWINDER__
- exception->exception_class[0] = 'Q';
- exception->exception_class[1] = 'M';
- exception->exception_class[2] = 'L';
- exception->exception_class[3] = 'J';
- exception->exception_class[4] = 'S';
- exception->exception_class[5] = 'V';
- exception->exception_class[6] = '4';
- exception->exception_class[7] = 0;
-#else
- exception->exception_class = 0x514d4c4a53563400; // QMLJSV40
-#endif
-
- _Unwind_RaiseException(exception);
- std::terminate();
-}
-
-QT_END_NAMESPACE
-
-/*
- * We override these EABI defined symbols on Android, where we must statically link in the unwinder from libgcc.a
- * and thus also ensure that compiler generated cleanup code / landing pads end up calling these stubs, that
- * ultimately return control to our copy of the unwinder. The symbols are also exported from gnustl_shared, which
- * comes later in the link line.
- */
-#if defined(__ANDROID__) && defined(__ARM_EABI_UNWINDER__)
-#pragma GCC visibility push(default)
-#ifdef __thumb__
-asm (" .pushsection .text.__cxa_end_cleanup\n"
-" .global __cxa_end_cleanup\n"
-" .type __cxa_end_cleanup, \"function\"\n"
-" .thumb_func\n"
-"__cxa_end_cleanup:\n"
-" push\t{r1, r2, r3, r4}\n"
-" bl\t__gnu_end_cleanup\n"
-" pop\t{r1, r2, r3, r4}\n"
-" bl\t_Unwind_Resume @ Never returns\n"
-" .popsection\n");
-#else
-asm (" .pushsection .text.__cxa_end_cleanup\n"
-" .global __cxa_end_cleanup\n"
-" .type __cxa_end_cleanup, \"function\"\n"
-"__cxa_end_cleanup:\n"
-" stmfd\tsp!, {r1, r2, r3, r4}\n"
-" bl\t__gnu_end_cleanup\n"
-" ldmfd\tsp!, {r1, r2, r3, r4}\n"
-" bl\t_Unwind_Resume @ Never returns\n"
-" .popsection\n");
-#endif
-#pragma GCC visibility pop
-#endif
-
-#endif
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 24fb4ad923..c37d4f125d 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -85,7 +85,6 @@ struct ArgumentsObject;
struct ExecutionContext;
struct ExecutionEngine;
class MemoryManager;
-class UnwindHelper;
class ExecutableAllocator;
struct ObjectPrototype;
@@ -114,6 +113,12 @@ class RegExpCache;
struct QmlExtensions;
struct Exception;
+#define CHECK_STACK_LIMITS(v4) \
+ if ((v4->jsStackTop <= v4->jsStackLimit) && (reinterpret_cast<quintptr>(&v4) >= v4->cStackLimit || v4->recheckCStackLimits())) {} \
+ else \
+ return v4->current->throwRangeError(QStringLiteral("Maximum call stack size exceeded."))
+
+
struct Q_QML_EXPORT ExecutionEngine
{
MemoryManager *memoryManager;
@@ -124,22 +129,35 @@ struct Q_QML_EXPORT ExecutionEngine
ExecutionContext *current;
GlobalContext *rootContext;
+ SafeValue *jsStackTop;
+ SafeValue *jsStackLimit;
+ quintptr cStackLimit;
+
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
+ enum { JSStackLimit = 4*1024*1024 };
WTF::PageAllocation *jsStack;
SafeValue *jsStackBase;
- SafeValue *jsStackTop;
SafeValue *stackPush(uint nValues) {
SafeValue *ptr = jsStackTop;
jsStackTop = ptr + nValues;
return ptr;
}
-
void stackPop(uint nValues) {
jsStackTop -= nValues;
}
+ void pushForGC(Managed *m) {
+ *jsStackTop = Value::fromManaged(m);
+ ++jsStackTop;
+ }
+ Managed *popForGC() {
+ --jsStackTop;
+ return jsStackTop->managed();
+ }
+
+
IdentifierTable *identifierTable;
QV4::Debugging::Debugger *debugger;
@@ -263,10 +281,10 @@ struct Q_QML_EXPORT ExecutionEngine
void enableDebugger();
ExecutionContext *pushGlobalContext();
- void pushContext(SimpleCallContext *context);
+ void pushContext(CallContext *context);
ExecutionContext *popContext();
- Returned<FunctionObject> *newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(SimpleCallContext *));
+ Returned<FunctionObject> *newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *));
Returned<BoundFunction> *newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<SafeValue> &boundArgs);
Returned<Object> *newObject();
@@ -321,26 +339,24 @@ struct Q_QML_EXPORT ExecutionEngine
QmlExtensions *qmlExtensions();
+ bool recheckCStackLimits();
+
// Exception handling
SafeValue exceptionValue;
- bool hasException;
+ quint32 hasException;
StackTrace exceptionStackTrace;
- void Q_NORETURN throwException(const ValueRef value);
+ ReturnedValue throwException(const ValueRef value);
ReturnedValue catchException(ExecutionContext *catchingContext, StackTrace *trace);
// Use only inside catch(...) -- will re-throw if no JS exception
- static QQmlError convertJavaScriptException(QV4::ExecutionContext *context);
-
- void Q_NORETURN throwInternal();
- // ----
-
+ static QQmlError catchExceptionAsQmlError(QV4::ExecutionContext *context);
private:
QmlExtensions *m_qmlExtensions;
};
-inline void ExecutionEngine::pushContext(SimpleCallContext *context)
+inline void ExecutionEngine::pushContext(CallContext *context)
{
context->parent = current;
current = context;
@@ -365,11 +381,22 @@ struct ExecutionContextSaver
}
~ExecutionContextSaver()
{
- while (engine->current != savedContext)
- engine->popContext();
+ engine->current = savedContext;
}
};
+inline
+void Managed::mark(QV4::ExecutionEngine *engine)
+{
+ Q_ASSERT(inUse);
+ if (markBit)
+ return;
+ markBit = 1;
+ engine->pushForGC(this);
+}
+
+
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index ef9dc473f3..bac29d19e1 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -82,7 +82,7 @@ ErrorObject::ErrorObject(InternalClass *ic)
Scope scope(engine());
ScopedValue protectThis(scope, this);
- ScopedString s(scope, ic->engine->newString("Error"));
+ ScopedString s(scope, ic->engine->newString(QStringLiteral("Error")));
defineDefaultProperty(QStringLiteral("name"), s);
}
@@ -167,12 +167,12 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, const QStrin
defineDefaultProperty(QStringLiteral("message"), v);
}
-ReturnedValue ErrorObject::method_get_stack(SimpleCallContext *ctx)
+ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
{
Scope scope(ctx);
Scoped<ErrorObject> This(scope, ctx->callData->thisObject);
if (!This)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (!This->stack) {
QString trace;
for (int i = 0; i < This->stackTrace.count(); ++i) {
@@ -192,12 +192,12 @@ ReturnedValue ErrorObject::method_get_stack(SimpleCallContext *ctx)
return This->stack->asReturnedValue();
}
-void ErrorObject::markObjects(Managed *that)
+void ErrorObject::markObjects(Managed *that, ExecutionEngine *e)
{
ErrorObject *This = that->asErrorObject();
if (This->stack)
- This->stack->mark();
- Object::markObjects(that);
+ This->stack->mark(e);
+ Object::markObjects(that, e);
}
DEFINE_MANAGED_VTABLE(ErrorObject);
@@ -383,13 +383,13 @@ void ErrorPrototype::init(ExecutionEngine *engine, ObjectRef ctor, Object *obj)
obj->defineDefaultProperty(QStringLiteral("message"), (s = engine->newString(QString())));
}
-ReturnedValue ErrorPrototype::method_toString(SimpleCallContext *ctx)
+ReturnedValue ErrorPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
Object *o = ctx->callData->thisObject.asObject();
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedValue name(scope, o->get(ctx->engine->id_name));
QString qname;
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index ff43f54f3e..3f4cb8fc43 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -73,8 +73,8 @@ struct ErrorObject: Object {
StackTrace stackTrace;
String *stack;
- static ReturnedValue method_get_stack(SimpleCallContext *ctx);
- static void markObjects(Managed *that);
+ static ReturnedValue method_get_stack(CallContext *ctx);
+ static void markObjects(Managed *that, ExecutionEngine *e);
static void destroy(Managed *that) { static_cast<ErrorObject *>(that)->~ErrorObject(); }
};
@@ -179,7 +179,7 @@ struct ErrorPrototype: ErrorObject
void init(ExecutionEngine *engine, ObjectRef ctor) { init(engine, ctor, this); }
static void init(ExecutionEngine *engine, ObjectRef ctor, Object *obj);
- static ReturnedValue method_toString(SimpleCallContext *ctx);
+ static ReturnedValue method_toString(CallContext *ctx);
};
struct EvalErrorPrototype: ErrorObject
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index e539d62d54..9b31524614 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -121,7 +121,6 @@ bool ExecutableAllocator::Allocation::mergePrevious(ExecutableAllocator *allocat
ExecutableAllocator::ChunkOfPages::~ChunkOfPages()
{
- delete unwindInfo;
Allocation *alloc = firstAllocation;
while (alloc) {
Allocation *next = alloc->next;
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index b4fb2fb0e5..8ce1146ac9 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -105,24 +105,16 @@ public:
int freeAllocationCount() const { return freeAllocations.count(); }
int chunkCount() const { return chunks.count(); }
- // Used to store CIE+FDE on x86/x86-64.
- struct PlatformUnwindInfo
- {
- virtual ~PlatformUnwindInfo() {}
- };
-
struct ChunkOfPages
{
ChunkOfPages()
: pages(0)
, firstAllocation(0)
- , unwindInfo(0)
{}
~ChunkOfPages();
WTF::PageAllocation *pages;
Allocation *firstAllocation;
- PlatformUnwindInfo *unwindInfo;
bool contains(Allocation *alloc) const;
};
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 291d7cc033..ebe214ad72 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -45,7 +45,6 @@
#include "qv4value_p.h"
#include "qv4engine_p.h"
#include "qv4lookup_p.h"
-#include "qv4unwindhelper_p.h"
QT_BEGIN_NAMESPACE
@@ -59,19 +58,21 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
, codeData(0)
, codeSize(_codeSize)
{
+ Q_UNUSED(engine);
+
name = compilationUnit->runtimeStrings[compiledFunction->nameIndex].asString();
formals.resize(compiledFunction->nFormals);
formals.fill(0);
const quint32 *formalsIndices = compiledFunction->formalsTable();
- for (int i = 0; i < compiledFunction->nFormals; ++i)
+ for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
formals[i] = compilationUnit->runtimeStrings[formalsIndices[i]].asString();
locals.resize(compiledFunction->nLocals);
locals.fill(0);
const quint32 *localsIndices = compiledFunction->localsTable();
- for (int i = 0; i < compiledFunction->nLocals; ++i)
+ for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
locals[i] = compilationUnit->runtimeStrings[localsIndices[i]].asString();
}
@@ -80,20 +81,21 @@ Function::~Function()
}
-void Function::mark()
+void Function::mark(ExecutionEngine *e)
{
- name.mark();
+ name.mark(e);
for (int i = 0; i < formals.size(); ++i)
- formals.at(i)->mark();
+ formals.at(i)->mark(e);
for (int i = 0; i < locals.size(); ++i)
- locals.at(i)->mark();
+ locals.at(i)->mark(e);
}
namespace QV4 {
+template <int field, typename SearchType>
struct LineNumberMappingHelper
{
const quint32 *table;
- int lowerBound(int begin, int end, qptrdiff offset) {
+ int lowerBound(int begin, int end, SearchType value) {
int middle;
int n = int(end - begin);
int half;
@@ -101,7 +103,7 @@ struct LineNumberMappingHelper
while (n > 0) {
half = n >> 1;
middle = begin + half;
- if (table[middle * 2] < offset) {
+ if (table[middle * 2 + field] < static_cast<quint32>(value)) {
begin = middle + 1;
n -= half + 1;
} else {
@@ -110,22 +112,57 @@ struct LineNumberMappingHelper
}
return begin;
}
-};
+ int upperBound(int begin, int end, SearchType value) {
+ int middle;
+ int n = int(end - begin);
+ int half;
+ while (n > 0) {
+ half = n >> 1;
+ middle = begin + half;
+ if (value < table[middle * 2 + field]) {
+ n = half;
+ } else {
+ begin = middle + 1;
+ n -= half + 1;
+ }
+ }
+ return begin;
+ }
+};
}
int Function::lineNumberForProgramCounter(qptrdiff offset) const
{
- LineNumberMappingHelper helper;
+ // Access the first field, the program counter
+ LineNumberMappingHelper<0, qptrdiff> helper;
helper.table = compiledFunction->lineNumberMapping();
const uint count = compiledFunction->nLineNumberMappingEntries;
int pos = helper.lowerBound(0, count, offset);
if (pos != 0 && count > 0)
--pos;
- if (pos == count)
+ if (static_cast<uint>(pos) == count)
return -1;
return helper.table[pos * 2 + 1];
}
+QList<qptrdiff> Function::programCountersForAllLines() const
+{
+ // Only store 1 breakpoint per line...
+ QHash<quint32, qptrdiff> offsetsPerLine;
+ const quint32 *mapping = compiledFunction->lineNumberMapping();
+
+ // ... and make it the first instruction by walking backwards over the line mapping table
+ // and inserting all entries keyed on line.
+ for (quint32 i = compiledFunction->nLineNumberMappingEntries; i > 0; ) {
+ --i; // the loop is written this way, because starting at endIndex-1 and checking for i>=0 will never end: i>=0 is always true for unsigned.
+ quint32 offset = mapping[i * 2];
+ quint32 line = mapping[i * 2 + 1];
+ offsetsPerLine.insert(line, offset);
+ }
+
+ return offsetsPerLine.values();
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 35c98897a0..5d284f1b2b 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -86,23 +86,6 @@ struct Function {
const CompiledData::Function *compiledFunction;
CompiledData::CompilationUnit *compilationUnit;
inline ReturnedValue code(ExecutionContext *ctx, const uchar *data) {
-
- struct StackSaver {
- ExecutionEngine *engine;
- SafeValue *stack;
-
- StackSaver(ExecutionEngine *engine)
- : engine(engine)
- , stack(engine->jsStackTop)
- {}
-
- ~StackSaver()
- {
- engine->jsStackTop = stack;
- }
- };
-
- StackSaver(ctx->engine);
return codePtr(ctx, data);
}
@@ -126,9 +109,10 @@ struct Function {
inline bool needsActivation() const
{ return compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); }
- void mark();
+ void mark(ExecutionEngine *e);
int lineNumberForProgramCounter(qptrdiff offset) const;
+ QList<qptrdiff> programCountersForAllLines() const;
};
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 55baef06db..037f06cd35 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -54,6 +54,8 @@
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmlcontextwrapper_p.h>
+#include <private/qqmlengine_p.h>
#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
#include "private/qlocale_tools_p.h"
@@ -111,7 +113,7 @@ FunctionObject::FunctionObject(InternalClass *ic)
, function(0)
{
vtbl = &static_vtbl;
- name = engine()->id_undefined;
+ name = ic->engine->id_undefined;
type = Type_FunctionObject;
needsActivation = false;
@@ -129,7 +131,7 @@ void FunctionObject::init(const StringRef n, bool createProto)
vtbl = &static_vtbl;
name = n;
- Scope s(engine());
+ Scope s(internalClass->engine);
ScopedValue protectThis(s, this);
type = Type_FunctionObject;
@@ -151,14 +153,14 @@ void FunctionObject::init(const StringRef n, bool createProto)
ReturnedValue FunctionObject::newInstance()
{
- Scope scope(engine());
+ Scope scope(internalClass->engine);
ScopedCallData callData(scope, 0);
return construct(callData);
}
bool FunctionObject::hasInstance(Managed *that, const ValueRef value)
{
- Scope scope(that->engine());
+ Scope scope(that->internalClass->engine);
ScopedFunctionObject f(scope, static_cast<FunctionObject *>(that));
ScopedObject v(scope, value);
@@ -166,8 +168,10 @@ bool FunctionObject::hasInstance(Managed *that, const ValueRef value)
return false;
Scoped<Object> o(scope, f->get(scope.engine->id_prototype));
- if (!o)
+ if (!o) {
scope.engine->current->throwTypeError();
+ return false;
+ }
while (v) {
v = v->prototype();
@@ -183,7 +187,7 @@ bool FunctionObject::hasInstance(Managed *that, const ValueRef value)
ReturnedValue FunctionObject::construct(Managed *that, CallData *)
{
- ExecutionEngine *v4 = that->engine();
+ ExecutionEngine *v4 = that->internalClass->engine;
Scope scope(v4);
Scoped<FunctionObject> f(scope, that, Scoped<FunctionObject>::Cast);
@@ -200,26 +204,29 @@ ReturnedValue FunctionObject::call(Managed *, CallData *)
return Encode::undefined();
}
-void FunctionObject::markObjects(Managed *that)
+void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
{
FunctionObject *o = static_cast<FunctionObject *>(that);
if (o->name.managed())
- o->name->mark();
+ o->name->mark(e);
// these are marked in VM::Function:
// for (uint i = 0; i < formalParameterCount; ++i)
// formalParameterList[i]->mark();
// for (uint i = 0; i < varCount; ++i)
// varList[i]->mark();
- o->scope->mark();
+ o->scope->mark(e);
if (o->function)
- o->function->mark();
+ o->function->mark(e);
- Object::markObjects(that);
+ Object::markObjects(that, e);
}
FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Function *function)
{
- if (function->needsActivation() || function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount)
+ if (function->needsActivation() ||
+ function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith ||
+ function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount ||
+ function->isNamedExpression())
return new (scope->engine->memoryManager) ScriptFunction(scope, function);
return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function);
}
@@ -237,17 +244,20 @@ FunctionCtor::FunctionCtor(ExecutionContext *scope)
ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
{
FunctionCtor *f = static_cast<FunctionCtor *>(that);
- ExecutionContext *ctx = f->engine()->current;
+ ExecutionEngine *v4 = f->internalClass->engine;
+ ExecutionContext *ctx = v4->current;
QString arguments;
QString body;
if (callData->argc > 0) {
- for (uint i = 0; i < callData->argc - 1; ++i) {
+ for (int i = 0; i < callData->argc - 1; ++i) {
if (i)
arguments += QLatin1String(", ");
arguments += callData->args[i].toString(ctx)->toQString();
}
body = callData->args[callData->argc - 1].toString(ctx)->toQString();
}
+ if (ctx->engine->hasException)
+ return Encode::undefined();
QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}");
@@ -259,21 +269,20 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
const bool parsed = parser.parseExpression();
if (!parsed)
- f->engine()->current->throwSyntaxError(0);
+ return v4->current->throwSyntaxError(QLatin1String("Parse error"));
using namespace QQmlJS::AST;
FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
- ExecutionEngine *v4 = f->engine();
if (!fe)
- v4->current->throwSyntaxError(0);
+ return v4->current->throwSyntaxError(QLatin1String("Parse error"));
- QQmlJS::V4IR::Module module;
+ QQmlJS::V4IR::Module module(v4->debugger != 0);
QQmlJS::RuntimeCodegen cg(v4->current, f->strictMode);
cg.generateFromFunctionExpression(QString(), function, fe, &module);
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
QV4::Function *vmf = compilationUnit->linkToEngine(v4);
@@ -308,21 +317,21 @@ void FunctionPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
}
-ReturnedValue FunctionPrototype::method_toString(SimpleCallContext *ctx)
+ReturnedValue FunctionPrototype::method_toString(CallContext *ctx)
{
FunctionObject *fun = ctx->callData->thisObject.asFunctionObject();
if (!fun)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return ctx->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue();
}
-ReturnedValue FunctionPrototype::method_apply(SimpleCallContext *ctx)
+ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
{
Scope scope(ctx);
FunctionObject *o = ctx->callData->thisObject.asFunctionObject();
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedValue arg(scope, ctx->argument(1));
@@ -331,10 +340,8 @@ ReturnedValue FunctionPrototype::method_apply(SimpleCallContext *ctx)
quint32 len;
if (!arr) {
len = 0;
- if (!arg->isNullOrUndefined()) {
- ctx->throwTypeError();
- return Encode::undefined();
- }
+ if (!arg->isNullOrUndefined())
+ return ctx->throwTypeError();
} else {
len = ArrayPrototype::getLength(ctx, arr);
}
@@ -342,12 +349,12 @@ ReturnedValue FunctionPrototype::method_apply(SimpleCallContext *ctx)
ScopedCallData callData(scope, len);
if (len) {
- if (arr->protoHasArray() || arr->hasAccessorProperty) {
+ if (!(arr->flags & SimpleArray) || arr->protoHasArray() || arr->hasAccessorProperty) {
for (quint32 i = 0; i < len; ++i)
callData->args[i] = arr->getIndexed(i);
} else {
int alen = qMin(len, arr->arrayDataLen);
- for (quint32 i = 0; i < alen; ++i)
+ for (int i = 0; i < alen; ++i)
callData->args[i] = arr->arrayData[i].value;
for (quint32 i = alen; i < len; ++i)
callData->args[i] = Primitive::undefinedValue();
@@ -358,13 +365,13 @@ ReturnedValue FunctionPrototype::method_apply(SimpleCallContext *ctx)
return o->call(callData);
}
-ReturnedValue FunctionPrototype::method_call(SimpleCallContext *ctx)
+ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
{
Scope scope(ctx);
FunctionObject *o = ctx->callData->thisObject.asFunctionObject();
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedCallData callData(scope, ctx->callData->argc ? ctx->callData->argc - 1 : 0);
if (ctx->callData->argc) {
@@ -375,16 +382,16 @@ ReturnedValue FunctionPrototype::method_call(SimpleCallContext *ctx)
return o->call(callData);
}
-ReturnedValue FunctionPrototype::method_bind(SimpleCallContext *ctx)
+ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
{
Scope scope(ctx);
Scoped<FunctionObject> target(scope, ctx->callData->thisObject);
if (!target)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedValue boundThis(scope, ctx->argument(0));
QVector<SafeValue> boundArgs;
- for (uint i = 1; i < ctx->callData->argc; ++i)
+ for (int i = 1; i < ctx->callData->argc; ++i)
boundArgs += ctx->callData->args[i];
return ctx->engine->newBoundFunction(ctx->engine->rootContext, target, boundThis, boundArgs)->asReturnedValue();
@@ -429,7 +436,11 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
{
- ExecutionEngine *v4 = that->engine();
+ ExecutionEngine *v4 = that->internalClass->engine;
+ if (v4->hasException)
+ return Encode::undefined();
+ CHECK_STACK_LIMITS(v4);
+
Scope scope(v4);
Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that));
@@ -443,6 +454,9 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
callData->thisObject = obj.asReturnedValue();
ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData);
+ if (f->function->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
+
ExecutionContextSaver ctxSaver(context);
ScopedValue result(scope, f->function->code(ctx, f->function->codeData));
if (result->isObject())
@@ -453,18 +467,18 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
{
ScriptFunction *f = static_cast<ScriptFunction *>(that);
- void *stackSpace;
- ExecutionContext *context = f->engine()->current;
+ ExecutionEngine *v4 = f->internalClass->engine;
+ if (v4->hasException)
+ return Encode::undefined();
+ CHECK_STACK_LIMITS(v4);
+
+ ExecutionContext *context = v4->current;
Scope scope(context);
+
CallContext *ctx = context->newCallContext(f, callData);
- if (!f->strictMode && !callData->thisObject.isObject()) {
- if (callData->thisObject.isNullOrUndefined()) {
- ctx->callData->thisObject = f->engine()->globalObject->asReturnedValue();
- } else {
- ctx->callData->thisObject = callData->thisObject.toObject(context)->asReturnedValue();
- }
- }
+ if (f->function->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(ctx->engine, f->function->compiledFunction);
ExecutionContextSaver ctxSaver(context);
return f->function->code(ctx, f->function->codeData);
@@ -509,7 +523,11 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
{
- ExecutionEngine *v4 = that->engine();
+ ExecutionEngine *v4 = that->internalClass->engine;
+ if (v4->hasException)
+ return Encode::undefined();
+ CHECK_STACK_LIMITS(v4);
+
Scope scope(v4);
Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that));
@@ -517,41 +535,68 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
Scoped<Object> proto(scope, f->memberData[Index_Prototype].value);
if (!!proto)
ic = v4->emptyClass->changePrototype(proto.getPointer());
- Scoped<Object> obj(scope, v4->newObject(ic));
+ callData->thisObject = v4->newObject(ic);
ExecutionContext *context = v4->current;
- void *stackSpace = alloca(requiredMemoryForExecutionContectSimple(f));
- callData->thisObject = obj;
- ExecutionContext *ctx = context->newCallContext(stackSpace, scope.alloc(f->varCount), f.getPointer(), callData);
+
+ CallContext ctx;
+ ctx.initSimpleCallContext(v4, context);
+ ctx.strictMode = f->strictMode;
+ ctx.callData = callData;
+ ctx.function = f.getPointer();
+ ctx.compilationUnit = f->function->compilationUnit;
+ ctx.lookups = ctx.compilationUnit->runtimeLookups;
+ ctx.outer = f->scope;
+ ctx.locals = v4->stackPush(f->function->locals.size());
+ while (callData->argc < (int)f->formalParameterCount) {
+ callData->args[callData->argc] = Encode::undefined();
+ ++callData->argc;
+ }
+ v4->pushContext(&ctx);
+
+ if (f->function->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
ExecutionContextSaver ctxSaver(context);
- Scoped<Object> result(scope, f->function->code(ctx, f->function->codeData));
+ Scoped<Object> result(scope, f->function->code(&ctx, f->function->codeData));
if (!result)
- return obj.asReturnedValue();
+ return callData->thisObject.asReturnedValue();
return result.asReturnedValue();
}
ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
{
- ExecutionEngine *v4 = that->engine();
- Scope scope(v4);
- Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that));
+ ExecutionEngine *v4 = that->internalClass->engine;
+ if (v4->hasException)
+ return Encode::undefined();
+ CHECK_STACK_LIMITS(v4);
- void *stackSpace = alloca(requiredMemoryForExecutionContectSimple(f));
+ SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that);
+
+ Scope scope(v4);
ExecutionContext *context = v4->current;
- ExecutionContext *ctx = context->newCallContext(stackSpace, scope.alloc(f->varCount), f.getPointer(), callData);
- if (!f->strictMode && !callData->thisObject.isObject()) {
- if (callData->thisObject.isNullOrUndefined()) {
- ctx->callData->thisObject = f->engine()->globalObject->asReturnedValue();
- } else {
- ctx->callData->thisObject = callData->thisObject.toObject(context)->asReturnedValue();
- }
+ CallContext ctx;
+ ctx.initSimpleCallContext(v4, context);
+ ctx.strictMode = f->strictMode;
+ ctx.callData = callData;
+ ctx.function = f;
+ ctx.compilationUnit = f->function->compilationUnit;
+ ctx.lookups = ctx.compilationUnit->runtimeLookups;
+ ctx.outer = f->scope;
+ ctx.locals = v4->stackPush(f->function->locals.size());
+ while (callData->argc < (int)f->formalParameterCount) {
+ callData->args[callData->argc] = Encode::undefined();
+ ++callData->argc;
}
+ v4->current = &ctx;
+
+ if (f->function->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
ExecutionContextSaver ctxSaver(context);
- return f->function->code(ctx, f->function->codeData);
+ return f->function->code(&ctx, f->function->codeData);
}
@@ -559,7 +604,7 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
DEFINE_MANAGED_VTABLE(BuiltinFunction);
-BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(SimpleCallContext *))
+BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *))
: FunctionObject(scope, name)
, code(code)
{
@@ -568,19 +613,21 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name,
ReturnedValue BuiltinFunction::construct(Managed *f, CallData *)
{
- f->engine()->current->throwTypeError();
- return Encode::undefined();
+ return f->internalClass->engine->current->throwTypeError();
}
ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
{
BuiltinFunction *f = static_cast<BuiltinFunction *>(that);
- ExecutionEngine *v4 = f->engine();
- Scope scope(v4);
+ ExecutionEngine *v4 = f->internalClass->engine;
+ if (v4->hasException)
+ return Encode::undefined();
+ CHECK_STACK_LIMITS(v4);
+
ExecutionContext *context = v4->current;
- SimpleCallContext ctx;
- ctx.initSimpleCallContext(f->scope->engine);
+ CallContext ctx;
+ ctx.initSimpleCallContext(v4, context);
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
v4->pushContext(&ctx);
@@ -592,12 +639,16 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
{
IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that);
- ExecutionEngine *v4 = f->engine();
+ ExecutionEngine *v4 = f->internalClass->engine;
+ if (v4->hasException)
+ return Encode::undefined();
+ CHECK_STACK_LIMITS(v4);
+
ExecutionContext *context = v4->current;
Scope scope(v4);
- SimpleCallContext ctx;
- ctx.initSimpleCallContext(f->scope->engine);
+ CallContext ctx;
+ ctx.initSimpleCallContext(v4, context);
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
v4->pushContext(&ctx);
@@ -611,7 +662,7 @@ DEFINE_MANAGED_VTABLE(IndexedBuiltinFunction);
DEFINE_MANAGED_VTABLE(BoundFunction);
BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<SafeValue> &boundArgs)
- : FunctionObject(scope, 0)
+ : FunctionObject(scope, QStringLiteral("__bound function__"))
, target(target)
, boundArgs(boundArgs)
{
@@ -644,6 +695,8 @@ ReturnedValue BoundFunction::call(Managed *that, CallData *dd)
{
BoundFunction *f = static_cast<BoundFunction *>(that);
Scope scope(f->scope->engine);
+ if (scope.hasException())
+ return Encode::undefined();
ScopedCallData callData(scope, f->boundArgs.size() + dd->argc);
callData->thisObject = f->boundThis;
@@ -656,6 +709,9 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd)
{
BoundFunction *f = static_cast<BoundFunction *>(that);
Scope scope(f->scope->engine);
+ if (scope.hasException())
+ return Encode::undefined();
+
ScopedCallData callData(scope, f->boundArgs.size() + dd->argc);
memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(SafeValue));
memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(SafeValue));
@@ -668,12 +724,12 @@ bool BoundFunction::hasInstance(Managed *that, const ValueRef value)
return FunctionObject::hasInstance(f->target, value);
}
-void BoundFunction::markObjects(Managed *that)
+void BoundFunction::markObjects(Managed *that, ExecutionEngine *e)
{
BoundFunction *o = static_cast<BoundFunction *>(that);
- o->target->mark();
- o->boundThis.mark();
+ o->target->mark(e);
+ o->boundThis.mark(e);
for (int i = 0; i < o->boundArgs.size(); ++i)
- o->boundArgs.at(i).mark();
- FunctionObject::markObjects(that);
+ o->boundArgs.at(i).mark(e);
+ FunctionObject::markObjects(that, e);
}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index eeb041ddc0..2fc36d862f 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -139,7 +139,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
protected:
FunctionObject(InternalClass *ic);
- static void markObjects(Managed *that);
+ static void markObjects(Managed *that, ExecutionEngine *e);
static bool hasInstance(Managed *that, const ValueRef value);
static void destroy(Managed *that)
{ static_cast<FunctionObject*>(that)->~FunctionObject(); }
@@ -164,17 +164,17 @@ struct FunctionPrototype: FunctionObject
FunctionPrototype(InternalClass *ic);
void init(ExecutionEngine *engine, ObjectRef ctor);
- static ReturnedValue method_toString(SimpleCallContext *ctx);
- static ReturnedValue method_apply(SimpleCallContext *ctx);
- static ReturnedValue method_call(SimpleCallContext *ctx);
- static ReturnedValue method_bind(SimpleCallContext *ctx);
+ static ReturnedValue method_toString(CallContext *ctx);
+ static ReturnedValue method_apply(CallContext *ctx);
+ static ReturnedValue method_call(CallContext *ctx);
+ static ReturnedValue method_bind(CallContext *ctx);
};
struct BuiltinFunction: FunctionObject {
Q_MANAGED
- ReturnedValue (*code)(SimpleCallContext *);
+ ReturnedValue (*code)(CallContext *);
- BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(SimpleCallContext *));
+ BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *));
static ReturnedValue construct(Managed *, CallData *);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -184,10 +184,10 @@ struct IndexedBuiltinFunction: FunctionObject
{
Q_MANAGED
- ReturnedValue (*code)(SimpleCallContext *ctx, uint index);
+ ReturnedValue (*code)(CallContext *ctx, uint index);
uint index;
- IndexedBuiltinFunction(ExecutionContext *scope, uint index, ReturnedValue (*code)(SimpleCallContext *ctx, uint index))
+ IndexedBuiltinFunction(ExecutionContext *scope, uint index, ReturnedValue (*code)(CallContext *ctx, uint index))
: FunctionObject(scope)
, code(code)
, index(index)
@@ -197,8 +197,7 @@ struct IndexedBuiltinFunction: FunctionObject
static ReturnedValue construct(Managed *m, CallData *)
{
- m->engine()->current->throwTypeError();
- return Encode::undefined();
+ return m->engine()->current->throwTypeError();
}
static ReturnedValue call(Managed *that, CallData *callData);
@@ -235,7 +234,7 @@ struct BoundFunction: FunctionObject {
static ReturnedValue call(Managed *that, CallData *dd);
static void destroy(Managed *);
- static void markObjects(Managed *that);
+ static void markObjects(Managed *that, ExecutionEngine *e);
static bool hasInstance(Managed *that, const ValueRef value);
};
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index e0f51d22e5..7d7338f19c 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -84,8 +84,8 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
// Black list some platforms
#if defined(V4_ENABLE_JIT)
-#if defined(Q_OS_WINCE) || defined(Q_OS_IOS) || defined(Q_OS_WIN64)
- #undef V4_ENABLE_JIT
+#if defined(Q_OS_IOS) || defined(Q_OS_WIN64) || defined(Q_OS_WINRT)
+# undef V4_ENABLE_JIT
#endif
#endif
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 4dcdb08415..82622de5bb 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -101,16 +101,16 @@ static QString escape(const QString &input)
output.append(QChar(uc));
} else {
output.append('%');
- output.append(QChar(toHex(uc >> 4)));
- output.append(QChar(toHex(uc)));
+ output.append(QLatin1Char(toHex(uc >> 4)));
+ output.append(QLatin1Char(toHex(uc)));
}
} else {
output.append('%');
output.append('u');
- output.append(QChar(toHex(uc >> 12)));
- output.append(QChar(toHex(uc >> 8)));
- output.append(QChar(toHex(uc >> 4)));
- output.append(QChar(toHex(uc)));
+ output.append(QLatin1Char(toHex(uc >> 12)));
+ output.append(QLatin1Char(toHex(uc >> 8)));
+ output.append(QLatin1Char(toHex(uc >> 4)));
+ output.append(QLatin1Char(toHex(uc)));
}
}
return output;
@@ -396,10 +396,12 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
const QString code = callData->args[0].stringValue()->toQString();
bool inheritContext = !ctx->strictMode;
- Script script(ctx, code, QString("eval code"));
+ Script script(ctx, code, QStringLiteral("eval code"));
script.strictMode = (directCall && parentContext->strictMode);
script.inheritContext = inheritContext;
script.parse();
+ if (scope.engine->hasException)
+ return Encode::undefined();
Function *function = script.function();
if (!function)
@@ -457,7 +459,7 @@ static inline int toInt(const QChar &qc, int R)
}
// parseInt [15.1.2.2]
-ReturnedValue GlobalFunctions::method_parseInt(SimpleCallContext *ctx)
+ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue string(scope, ctx->argument(0));
@@ -467,6 +469,10 @@ ReturnedValue GlobalFunctions::method_parseInt(SimpleCallContext *ctx)
// [15.1.2.2] step by step:
String *inputString = string->toString(ctx); // 1
QString trimmed = inputString->toQString().trimmed(); // 2
+
+ if (ctx->engine->hasException)
+ return Encode::undefined();
+
const QChar *pos = trimmed.constData();
const QChar *end = pos + trimmed.length();
@@ -537,19 +543,22 @@ ReturnedValue GlobalFunctions::method_parseInt(SimpleCallContext *ctx)
}
// parseFloat [15.1.2.3]
-ReturnedValue GlobalFunctions::method_parseFloat(SimpleCallContext *ctx)
+ReturnedValue GlobalFunctions::method_parseFloat(CallContext *ctx)
{
Scope scope(ctx);
// [15.1.2.3] step by step:
Scoped<String> inputString(scope, ctx->argument(0), Scoped<String>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
+
QString trimmed = inputString->toQString().trimmed(); // 2
// 4:
if (trimmed.startsWith(QLatin1String("Infinity"))
|| trimmed.startsWith(QLatin1String("+Infinity")))
return Encode(Q_INFINITY);
- if (trimmed.startsWith("-Infinity"))
+ if (trimmed.startsWith(QStringLiteral("-Infinity")))
return Encode(-Q_INFINITY);
QByteArray ba = trimmed.toLatin1();
bool ok;
@@ -563,7 +572,7 @@ ReturnedValue GlobalFunctions::method_parseFloat(SimpleCallContext *ctx)
}
/// isNaN [15.1.2.4]
-ReturnedValue GlobalFunctions::method_isNaN(SimpleCallContext *ctx)
+ReturnedValue GlobalFunctions::method_isNaN(CallContext *ctx)
{
if (!ctx->callData->argc)
// undefined gets converted to NaN
@@ -577,7 +586,7 @@ ReturnedValue GlobalFunctions::method_isNaN(SimpleCallContext *ctx)
}
/// isFinite [15.1.2.5]
-ReturnedValue GlobalFunctions::method_isFinite(SimpleCallContext *ctx)
+ReturnedValue GlobalFunctions::method_isFinite(CallContext *ctx)
{
if (!ctx->callData->argc)
// undefined gets converted to NaN
@@ -591,7 +600,7 @@ ReturnedValue GlobalFunctions::method_isFinite(SimpleCallContext *ctx)
}
/// decodeURI [15.1.3.1]
-ReturnedValue GlobalFunctions::method_decodeURI(SimpleCallContext *context)
+ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context)
{
if (context->callData->argc == 0)
return Encode::undefined();
@@ -602,14 +611,14 @@ ReturnedValue GlobalFunctions::method_decodeURI(SimpleCallContext *context)
if (!ok) {
Scope scope(context);
ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence")));
- context->throwURIError(s);
+ return context->throwURIError(s);
}
return context->engine->newString(out)->asReturnedValue();
}
/// decodeURIComponent [15.1.3.2]
-ReturnedValue GlobalFunctions::method_decodeURIComponent(SimpleCallContext *context)
+ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context)
{
if (context->callData->argc == 0)
return Encode::undefined();
@@ -620,14 +629,14 @@ ReturnedValue GlobalFunctions::method_decodeURIComponent(SimpleCallContext *cont
if (!ok) {
Scope scope(context);
ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence")));
- context->throwURIError(s);
+ return context->throwURIError(s);
}
return context->engine->newString(out)->asReturnedValue();
}
/// encodeURI [15.1.3.3]
-ReturnedValue GlobalFunctions::method_encodeURI(SimpleCallContext *context)
+ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context)
{
if (context->callData->argc == 0)
return Encode::undefined();
@@ -638,14 +647,14 @@ ReturnedValue GlobalFunctions::method_encodeURI(SimpleCallContext *context)
if (!ok) {
Scope scope(context);
ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence")));
- context->throwURIError(s);
+ return context->throwURIError(s);
}
return context->engine->newString(out)->asReturnedValue();
}
/// encodeURIComponent [15.1.3.4]
-ReturnedValue GlobalFunctions::method_encodeURIComponent(SimpleCallContext *context)
+ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context)
{
if (context->callData->argc == 0)
return Encode::undefined();
@@ -656,13 +665,13 @@ ReturnedValue GlobalFunctions::method_encodeURIComponent(SimpleCallContext *cont
if (!ok) {
Scope scope(context);
ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence")));
- context->throwURIError(s);
+ return context->throwURIError(s);
}
return context->engine->newString(out)->asReturnedValue();
}
-ReturnedValue GlobalFunctions::method_escape(SimpleCallContext *context)
+ReturnedValue GlobalFunctions::method_escape(CallContext *context)
{
if (!context->callData->argc)
return context->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
@@ -671,7 +680,7 @@ ReturnedValue GlobalFunctions::method_escape(SimpleCallContext *context)
return context->engine->newString(escape(str))->asReturnedValue();
}
-ReturnedValue GlobalFunctions::method_unescape(SimpleCallContext *context)
+ReturnedValue GlobalFunctions::method_unescape(CallContext *context)
{
if (!context->callData->argc)
return context->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index e6a3b0d773..bf529a465d 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -61,16 +61,16 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject
struct GlobalFunctions
{
- static ReturnedValue method_parseInt(SimpleCallContext *context);
- static ReturnedValue method_parseFloat(SimpleCallContext *context);
- static ReturnedValue method_isNaN(SimpleCallContext *context);
- static ReturnedValue method_isFinite(SimpleCallContext *ctx);
- static ReturnedValue method_decodeURI(SimpleCallContext *context);
- static ReturnedValue method_decodeURIComponent(SimpleCallContext *context);
- static ReturnedValue method_encodeURI(SimpleCallContext *context);
- static ReturnedValue method_encodeURIComponent(SimpleCallContext *context);
- static ReturnedValue method_escape(SimpleCallContext *context);
- static ReturnedValue method_unescape(SimpleCallContext *context);
+ static ReturnedValue method_parseInt(CallContext *context);
+ static ReturnedValue method_parseFloat(CallContext *context);
+ static ReturnedValue method_isNaN(CallContext *context);
+ static ReturnedValue method_isFinite(CallContext *ctx);
+ static ReturnedValue method_decodeURI(CallContext *context);
+ static ReturnedValue method_decodeURIComponent(CallContext *context);
+ static ReturnedValue method_encodeURI(CallContext *context);
+ static ReturnedValue method_encodeURIComponent(CallContext *context);
+ static ReturnedValue method_escape(CallContext *context);
+ static ReturnedValue method_unescape(CallContext *context);
};
}
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
index 08f48c36a4..87fbd6f8e4 100644
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ b/src/qml/jsruntime/qv4identifier.cpp
@@ -57,8 +57,8 @@ static inline int primeForNumBits(int numBits)
IdentifierHashData::IdentifierHashData(int numBits)
- : numBits(numBits)
- , size(0)
+ : size(0)
+ , numBits(numBits)
{
refCount.store(1);
alloc = primeForNumBits(numBits);
@@ -83,7 +83,7 @@ IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier)
int newAlloc = primeForNumBits(d->numBits);
IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(newAlloc * sizeof(IdentifierHashEntry));
memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry));
- for (uint i = 0; i < d->alloc; ++i) {
+ for (int i = 0; i < d->alloc; ++i) {
const IdentifierHashEntry &e = d->entries[i];
if (!e.identifier)
continue;
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index 04c31828cc..e300a4811e 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -91,7 +91,7 @@ void IdentifierTable::addEntry(String *str)
int newAlloc = primeForNumBits(numBits);
String **newEntries = (String **)malloc(newAlloc*sizeof(String *));
memset(newEntries, 0, newAlloc*sizeof(String *));
- for (uint i = 0; i < alloc; ++i) {
+ for (int i = 0; i < alloc; ++i) {
String *e = entries[i];
if (!e)
continue;
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index a02d90e7e2..02fc8b70c6 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -79,10 +79,10 @@ public:
Identifier *identifierImpl(const String *str);
- void mark() {
+ void mark(ExecutionEngine *e) {
for (int i = 0; i < alloc; ++i)
if (entries[i])
- entries[i]->mark();
+ entries[i]->mark(e);
}
};
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 47d2832fa3..8f2548064a 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -89,11 +89,11 @@ QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status stat
QV4::ScopedObject o(scope, v4->newObject());
QV4::ScopedString s(scope);
QV4::ScopedValue v(scope);
- o->put((s = v4->newString("OK")), (v = QV4::Primitive::fromInt32(Ok)));
- o->put((s = v4->newString("LOADING")), (v = QV4::Primitive::fromInt32(Loading)));
- o->put((s = v4->newString("NETWORK_ERROR")), (v = QV4::Primitive::fromInt32(NetworkError)));
- o->put((s = v4->newString("EXCEPTION")), (v = QV4::Primitive::fromInt32(Exception)));
- o->put((s = v4->newString("status")), (v = QV4::Primitive::fromInt32(status)));
+ o->put((s = v4->newString(QStringLiteral("OK"))), (v = QV4::Primitive::fromInt32(Ok)));
+ o->put((s = v4->newString(QStringLiteral("LOADING"))), (v = QV4::Primitive::fromInt32(Loading)));
+ o->put((s = v4->newString(QStringLiteral("NETWORK_ERROR"))), (v = QV4::Primitive::fromInt32(NetworkError)));
+ o->put((s = v4->newString(QStringLiteral("EXCEPTION"))), (v = QV4::Primitive::fromInt32(Exception)));
+ o->put((s = v4->newString(QStringLiteral("status"))), (v = QV4::Primitive::fromInt32(status)));
return o.asReturnedValue();
}
@@ -109,14 +109,12 @@ void QV4Include::callback(const QV4::ValueRef callback, const QV4::ValueRef stat
return;
QV4::ExecutionContext *ctx = v4->current;
- try {
- QV4::ScopedCallData callData(scope, 1);
- callData->thisObject = v4->globalObject->asReturnedValue();
- callData->args[0] = status;
- f->call(callData);
- } catch (...) {
+ QV4::ScopedCallData callData(scope, 1);
+ callData->thisObject = v4->globalObject->asReturnedValue();
+ callData->args[0] = status;
+ f->call(callData);
+ if (scope.hasException())
ctx->catchException();
- }
}
QV4::ReturnedValue QV4Include::result()
@@ -156,18 +154,19 @@ void QV4Include::finished()
QV4::Script script(v4, qmlglobal, code, m_url.toString());
QV4::ExecutionContext *ctx = v4->current;
- QV4::ScopedString status(scope, v4->newString("status"));
- try {
- script.parse();
+ QV4::ScopedString status(scope, v4->newString(QStringLiteral("status")));
+ script.parse();
+ if (!scope.engine->hasException)
script.run();
- resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Ok)));
- } catch (...) {
+ if (scope.engine->hasException) {
QV4::ScopedValue ex(scope, ctx->catchException());
resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Exception)));
- resultObj->put(QV4::ScopedString(scope, v4->newString("exception")), ex);
+ resultObj->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("exception"))), ex);
+ } else {
+ resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Ok)));
}
} else {
- resultObj->put(QV4::ScopedString(scope, v4->newString("status")), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError)));
+ resultObj->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("status"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError)));
}
QV4::ScopedValue cb(scope, m_callbackFunction.value());
@@ -180,7 +179,7 @@ void QV4Include::finished()
/*
Documented in qv8engine.cpp
*/
-QV4::ReturnedValue QV4Include::method_include(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
{
if (!ctx->callData->argc)
return QV4::Encode::undefined();
@@ -222,14 +221,15 @@ QV4::ReturnedValue QV4Include::method_include(QV4::SimpleCallContext *ctx)
QV4::Script script(v4, qmlcontextobject, code, url.toString());
QV4::ExecutionContext *ctx = v4->current;
- try {
- script.parse();
+ script.parse();
+ if (!v4->hasException)
script.run();
- result = resultValue(v4, Ok);
- } catch (...) {
+ if (v4->hasException) {
QV4::ScopedValue ex(scope, ctx->catchException());
result = resultValue(v4, Exception);
- result->asObject()->put(QV4::ScopedString(scope, v4->newString("exception")), ex);
+ result->asObject()->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("exception"))), ex);
+ } else {
+ result = resultValue(v4, Ok);
}
} else {
result = resultValue(v4, NetworkError);
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index 49d65e2149..c4c72f3a83 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -78,7 +78,7 @@ public:
Exception = 3
};
- static QV4::ReturnedValue method_include(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_include(QV4::CallContext *ctx);
private Q_SLOTS:
void finished();
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 02783b79a0..cb799a473c 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -69,10 +69,10 @@ static inline int primeForNumBits(int numBits)
}
PropertyHashData::PropertyHashData(int numBits)
- : numBits(numBits)
+ : refCount(1)
, size(0)
+ , numBits(numBits)
{
- refCount.store(1);
alloc = primeForNumBits(numBits);
entries = (PropertyHash::Entry *)malloc(alloc*sizeof(PropertyHash::Entry));
memset(entries, 0, alloc*sizeof(PropertyHash::Entry));
@@ -85,9 +85,9 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
if (classSize < d->size || grow) {
PropertyHashData *dd = new PropertyHashData(grow ? d->numBits + 1 : d->numBits);
- for (uint i = 0; i < d->alloc; ++i) {
+ for (int i = 0; i < d->alloc; ++i) {
const Entry &e = d->entries[i];
- if (!e.identifier || e.index >= classSize)
+ if (!e.identifier || e.index >= static_cast<unsigned>(classSize))
continue;
uint idx = e.identifier->hashValue % dd->alloc;
while (dd->entries[idx].identifier) {
@@ -97,8 +97,8 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
dd->entries[idx] = e;
}
dd->size = classSize;
- assert(d->refCount.load() > 1);
- d->refCount.deref();
+ Q_ASSERT(d->refCount > 1);
+ --d->refCount;
d = dd;
}
@@ -113,7 +113,7 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
uint PropertyHash::lookup(const Identifier *identifier) const
{
- assert(d->entries);
+ Q_ASSERT(d->entries);
uint idx = identifier->hashValue % d->alloc;
while (1) {
@@ -149,20 +149,20 @@ InternalClass *InternalClass::changeMember(String *string, PropertyAttributes da
if (index)
*index = idx;
- assert(idx != UINT_MAX);
+ Q_ASSERT(idx != UINT_MAX);
- if (data == propertyData[idx])
+ if (data == propertyData.at(idx))
return this;
- Transition t = { string->identifier, (int)data.flags() };
+ Transition t = { { string->identifier }, (int)data.flags() };
QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
if (tit != transitions.constEnd())
return tit.value();
// create a new class and add it to the tree
InternalClass *newClass = engine->newClass(*this);
- newClass->propertyData[idx] = data;
+ newClass->propertyData.set(idx, data);
transitions.insert(t, newClass);
return newClass;
@@ -189,7 +189,7 @@ InternalClass *InternalClass::changePrototype(Object *proto)
newClass->prototype = proto;
} else {
newClass = engine->emptyClass->changePrototype(proto);
- for (int i = 0; i < nameMap.size(); ++i)
+ for (uint i = 0; i < size; ++i)
newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
}
@@ -211,7 +211,7 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data,
if (propertyTable.lookup(string->identifier) < size)
return changeMember(string, data, index);
- Transition t = { string->identifier, (int)data.flags() };
+ Transition t = { { string->identifier }, (int)data.flags() };
QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
if (index)
@@ -228,9 +228,9 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data,
// store a string in the nameMap that's guaranteed to get
// marked properly during GC.
String *name = engine->newIdentifier(string->toQString());
- newClass->nameMap.append(name);
+ newClass->nameMap.add(size, name);
- newClass->propertyData.append(data);
+ newClass->propertyData.add(size, data);
++newClass->size;
transitions.insert(t, newClass);
return newClass;
@@ -238,10 +238,10 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data,
void InternalClass::removeMember(Object *object, Identifier *id)
{
- int propIdx = propertyTable.lookup(id);
- assert(propIdx < size);
+ uint propIdx = propertyTable.lookup(id);
+ Q_ASSERT(propIdx < size);
- Transition t = { id, -1 };
+ Transition t = { { id } , -1 };
QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
if (tit != transitions.constEnd()) {
@@ -251,7 +251,7 @@ void InternalClass::removeMember(Object *object, Identifier *id)
// create a new class and add it to the tree
object->internalClass = engine->emptyClass->changePrototype(prototype);
- for (int i = 0; i < nameMap.size(); ++i) {
+ for (uint i = 0; i < size; ++i) {
if (i == propIdx)
continue;
object->internalClass = object->internalClass->addMember(nameMap.at(i), propertyData.at(i));
@@ -284,7 +284,7 @@ InternalClass *InternalClass::sealed()
m_sealed = engine->emptyClass;
m_sealed = m_sealed->changePrototype(prototype);
- for (int i = 0; i < nameMap.size(); ++i) {
+ for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
attrs.setConfigurable(false);
m_sealed = m_sealed->addMember(nameMap.at(i), attrs);
@@ -301,7 +301,7 @@ InternalClass *InternalClass::frozen()
m_frozen = engine->emptyClass;
m_frozen = m_frozen->changePrototype(prototype);
- for (int i = 0; i < nameMap.size(); ++i) {
+ for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
attrs.setWritable(false);
attrs.setConfigurable(false);
@@ -319,12 +319,9 @@ void InternalClass::destroy()
return;
engine = 0;
- // Free the memory of the hashes/vectors by calling clear(), which
- // re-assigns them to the shared null instance. Therefore Internalclass
- // doesn't need a destructor to be called.
propertyTable.~PropertyHash();
- nameMap.clear();
- propertyData.clear();
+ nameMap.~SharedInternalClassData<String *>();
+ propertyData.~SharedInternalClassData<PropertyAttributes>();
if (m_sealed)
m_sealed->destroy();
@@ -348,7 +345,7 @@ void InternalClass::markObjects()
it != end; ++it) {
if (it.key().flags == Transition::ProtoChange) {
Q_ASSERT(it.value()->prototype);
- it.value()->prototype->mark();
+ it.value()->prototype->mark(engine);
}
}
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 659789b344..9586637b32 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -82,7 +82,7 @@ struct PropertyHashData
free(entries);
}
- QBasicAtomicInt refCount;
+ int refCount;
int alloc;
int size;
int numBits;
@@ -97,15 +97,102 @@ inline PropertyHash::PropertyHash()
inline PropertyHash::PropertyHash(const PropertyHash &other)
{
d = other.d;
- d->refCount.ref();
+ ++d->refCount;
}
inline PropertyHash::~PropertyHash()
{
- if (!d->refCount.deref())
+ if (!--d->refCount)
delete d;
}
+
+template <typename T>
+struct SharedInternalClassData {
+ struct Private {
+ Private(int alloc)
+ : refcount(1),
+ alloc(alloc),
+ size(0)
+ { data = new T [alloc]; }
+ ~Private() { delete [] data; }
+
+ int refcount;
+ uint alloc;
+ uint size;
+ T *data;
+ };
+ Private *d;
+
+ inline SharedInternalClassData() {
+ d = new Private(8);
+ }
+
+ inline SharedInternalClassData(const SharedInternalClassData &other)
+ : d(other.d)
+ {
+ ++d->refcount;
+ }
+ inline ~SharedInternalClassData() {
+ if (!--d->refcount)
+ delete d;
+ }
+
+ void add(uint pos, T value) {
+ if (pos < d->size) {
+ Q_ASSERT(d->refcount > 1);
+ // need to detach
+ Private *dd = new Private(pos + 8);
+ memcpy(dd->data, d->data, pos*sizeof(T));
+ dd->size = pos + 1;
+ dd->data[pos] = value;
+ if (!--d->refcount)
+ delete d;
+ d = dd;
+ return;
+ }
+ Q_ASSERT(pos == d->size);
+ if (pos == d->alloc) {
+ T *n = new T[d->alloc * 2];
+ memcpy(n, d->data, d->alloc*sizeof(T));
+ delete [] d->data;
+ d->data = n;
+ d->alloc *= 2;
+ }
+ d->data[pos] = value;
+ ++d->size;
+ }
+
+ void set(uint pos, T value) {
+ Q_ASSERT(pos < d->size);
+ if (d->refcount > 1) {
+ // need to detach
+ Private *dd = new Private(d->alloc);
+ memcpy(dd->data, d->data, d->size*sizeof(T));
+ dd->size = d->size;
+ if (!--d->refcount)
+ delete d;
+ d = dd;
+ }
+ d->data[pos] = value;
+ }
+
+ T *constData() const {
+ return d->data;
+ }
+ T at(uint i) const {
+ Q_ASSERT(i < d->size);
+ return d->data[i];
+ }
+ T operator[] (uint i) {
+ Q_ASSERT(i < d->size);
+ return d->data[i];
+ }
+
+private:
+ SharedInternalClassData &operator=(const SharedInternalClassData &other);
+};
+
struct InternalClassTransition
{
union {
@@ -124,9 +211,8 @@ struct InternalClass {
ExecutionEngine *engine;
Object *prototype;
PropertyHash propertyTable; // id to valueIndex
- QVector<String *> nameMap;
-
- QVector<PropertyAttributes> propertyData;
+ SharedInternalClassData<String *> nameMap;
+ SharedInternalClassData<PropertyAttributes> propertyData;
typedef InternalClassTransition Transition;
QHash<Transition, InternalClass *> transitions; // id to next class, positive means add, negative delete
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 331b528409..458b46b36e 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -612,10 +612,9 @@ bool JsonParser::parseString(QString *string)
lastError = QJsonParseError::IllegalEscapeSequence;
return false;
}
- qDebug() << "scanEscape" << hex << ch;
if (QChar::requiresSurrogates(ch)) {
- *string += QChar::highSurrogate(ch);
- *string += QChar::lowSurrogate(ch);
+ *string += QChar(QChar::highSurrogate(ch));
+ *string += QChar(QChar::lowSurrogate(ch));
} else {
*string += QChar(ch);
}
@@ -661,42 +660,42 @@ struct Stringify
static QString quote(const QString &str)
{
- QString product = "\"";
+ QString product = QStringLiteral("\"");
for (int i = 0; i < str.length(); ++i) {
QChar c = str.at(i);
switch (c.unicode()) {
case '"':
- product += "\\\"";
+ product += QStringLiteral("\\\"");
break;
case '\\':
- product += "\\\\";
+ product += QStringLiteral("\\\\");
break;
case '\b':
- product += "\\b";
+ product += QStringLiteral("\\b");
break;
case '\f':
- product += "\\f";
+ product += QStringLiteral("\\f");
break;
case '\n':
- product += "\\n";
+ product += QStringLiteral("\\n");
break;
case '\r':
- product += "\\r";
+ product += QStringLiteral("\\r");
break;
case '\t':
- product += "\\t";
+ product += QStringLiteral("\\t");
break;
default:
if (c.unicode() <= 0x1f) {
- product += "\\u00";
- product += c.unicode() > 0xf ? '1' : '0';
- product += "0123456789abcdef"[c.unicode() & 0xf];
+ product += QStringLiteral("\\u00");
+ product += c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0');
+ product += QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]);
} else {
product += c;
}
}
}
- product += '"';
+ product += QLatin1Char('"');
return product;
}
@@ -768,9 +767,9 @@ QString Stringify::makeMember(const QString &key, ValueRef v)
{
QString strP = Str(key, v);
if (!strP.isEmpty()) {
- QString member = quote(key) + ':';
+ QString member = quote(key) + QLatin1Char(':');
if (!gap.isEmpty())
- member += ' ';
+ member += QLatin1Char(' ');
member += strP;
return member;
}
@@ -779,8 +778,10 @@ QString Stringify::makeMember(const QString &key, ValueRef v)
QString Stringify::JO(ObjectRef o)
{
- if (stack.contains(o.getPointer()))
+ if (stack.contains(o.getPointer())) {
ctx->throwTypeError();
+ return QString();
+ }
Scope scope(ctx);
@@ -799,7 +800,7 @@ QString Stringify::JO(ObjectRef o)
name = it.nextPropertyNameAsString(val);
if (name->isNull())
break;
- QString key = name->toQStringNoThrow();
+ QString key = name->toQString();
QString member = makeMember(key, val);
if (!member.isEmpty())
partial += member;
@@ -821,10 +822,10 @@ QString Stringify::JO(ObjectRef o)
if (partial.isEmpty()) {
result = QStringLiteral("{}");
} else if (gap.isEmpty()) {
- result = "{" + partial.join(",") + "}";
+ result = QStringLiteral("{") + partial.join(QLatin1Char(',')) + QStringLiteral("}");
} else {
- QString separator = ",\n" + indent;
- result = "{\n" + indent + partial.join(separator) + "\n" + stepback + "}";
+ QString separator = QStringLiteral(",\n") + indent;
+ result = QStringLiteral("{\n") + indent + partial.join(separator) + QStringLiteral("\n") + stepback + QStringLiteral("}");
}
indent = stepback;
@@ -834,8 +835,10 @@ QString Stringify::JO(ObjectRef o)
QString Stringify::JA(ArrayObjectRef a)
{
- if (stack.contains(a.getPointer()))
+ if (stack.contains(a.getPointer())) {
ctx->throwTypeError();
+ return QString();
+ }
Scope scope(a->engine());
@@ -864,10 +867,10 @@ QString Stringify::JA(ArrayObjectRef a)
if (partial.isEmpty()) {
result = QStringLiteral("[]");
} else if (gap.isEmpty()) {
- result = "[" + partial.join(",") + "]";
+ result = QStringLiteral("[") + partial.join(QLatin1Char(',')) + QStringLiteral("]");
} else {
- QString separator = ",\n" + indent;
- result = "[\n" + indent + partial.join(separator) + "\n" + stepback + "]";
+ QString separator = QStringLiteral(",\n") + indent;
+ result = QStringLiteral("[\n") + indent + partial.join(separator) + QStringLiteral("\n") + stepback + QStringLiteral("]");
}
indent = stepback;
@@ -889,7 +892,7 @@ JsonObject::JsonObject(ExecutionEngine *engine)
}
-ReturnedValue JsonObject::method_parse(SimpleCallContext *ctx)
+ReturnedValue JsonObject::method_parse(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue v(scope, ctx->argument(0));
@@ -901,13 +904,13 @@ ReturnedValue JsonObject::method_parse(SimpleCallContext *ctx)
ScopedValue result(scope, parser.parse(&error));
if (error.error != QJsonParseError::NoError) {
DEBUG << "parse error" << error.errorString();
- ctx->throwSyntaxError("JSON.parse: Parse error");
+ return ctx->throwSyntaxError(QStringLiteral("JSON.parse: Parse error"));
}
return result.asReturnedValue();
}
-ReturnedValue JsonObject::method_stringify(SimpleCallContext *ctx)
+ReturnedValue JsonObject::method_stringify(CallContext *ctx)
{
Scope scope(ctx);
@@ -922,7 +925,7 @@ ReturnedValue JsonObject::method_stringify(SimpleCallContext *ctx)
for (uint i = 0; i < arrayLen; ++i) {
v = o->getIndexed(i);
if (v->asNumberObject() || v->asStringObject() || v->isNumber())
- v = __qmljs_to_string(v, ctx);
+ v = __qmljs_to_string(ctx, v);
if (v->isString()) {
String *s = v->stringValue();
if (!stringify.propertyList.contains(s))
@@ -947,7 +950,7 @@ ReturnedValue JsonObject::method_stringify(SimpleCallContext *ctx)
ScopedValue arg0(scope, ctx->argument(0));
QString result = stringify.Str(QString(), arg0);
- if (result.isEmpty())
+ if (result.isEmpty() || scope.engine->hasException)
return Encode::undefined();
return ctx->engine->newString(result)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index bdce810680..f63e7726f5 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -56,8 +56,8 @@ private:
public:
JsonObject(ExecutionEngine *engine);
- static ReturnedValue method_parse(SimpleCallContext *ctx);
- static ReturnedValue method_stringify(SimpleCallContext *ctx);
+ static ReturnedValue method_parse(CallContext *ctx);
+ static ReturnedValue method_stringify(CallContext *ctx);
static ReturnedValue fromJsonValue(ExecutionEngine *engine, const QJsonValue &value);
static ReturnedValue fromJsonObject(ExecutionEngine *engine, const QJsonObject &object);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 4ee24d29eb..f67b24c040 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -49,16 +49,6 @@ using namespace QV4;
Property *Lookup::lookup(Object *obj, PropertyAttributes *attrs)
{
int i = 0;
- while (i < level && obj && obj->internalClass == classList[i]) {
- obj = obj->prototype();
- ++i;
- }
-
- if (index != UINT_MAX && obj->internalClass == classList[i]) {
- *attrs = obj->internalClass->propertyData.at(index);
- return obj->memberData + index;
- }
-
while (i < Size && obj) {
classList[i] = obj->internalClass;
@@ -72,7 +62,7 @@ Property *Lookup::lookup(Object *obj, PropertyAttributes *attrs)
obj = obj->prototype();
++i;
}
- level = i;
+ level = Size;
while (obj) {
index = obj->internalClass->find(name);
@@ -97,7 +87,7 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object)
switch (object->type()) {
case Value::Undefined_Type:
case Value::Null_Type:
- engine->current->throwTypeError();
+ return engine->current->throwTypeError();
case Value::Boolean_Type:
proto = engine->booleanClass->prototype;
break;
@@ -140,9 +130,12 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object)
ReturnedValue Lookup::getter0(Lookup *l, const ValueRef object)
{
- if (Object *o = object->asObject()) {
+ 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].value.asReturnedValue();
+ return static_cast<Object *>(o)->memberData[l->index].value.asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, object);
@@ -150,7 +143,10 @@ ReturnedValue Lookup::getter0(Lookup *l, const ValueRef object)
ReturnedValue Lookup::getter1(Lookup *l, const ValueRef object)
{
- if (Object *o = object->asObject()) {
+ 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].value.asReturnedValue();
@@ -161,7 +157,10 @@ ReturnedValue Lookup::getter1(Lookup *l, const ValueRef object)
ReturnedValue Lookup::getter2(Lookup *l, const ValueRef object)
{
- if (Object *o = object->asObject()) {
+ 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) {
o = o->prototype();
if (l->classList[1] == o->internalClass) {
@@ -177,7 +176,10 @@ ReturnedValue Lookup::getter2(Lookup *l, const ValueRef object)
ReturnedValue Lookup::getterAccessor0(Lookup *l, const ValueRef object)
{
- if (Object *o = object->asObject()) {
+ 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) {
Scope scope(o->engine());
FunctionObject *getter = o->memberData[l->index].getter();
@@ -195,7 +197,10 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, const ValueRef object)
ReturnedValue Lookup::getterAccessor1(Lookup *l, const ValueRef object)
{
- if (Object *o = object->asObject()) {
+ 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) {
Scope scope(o->engine());
@@ -214,7 +219,10 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, const ValueRef object)
ReturnedValue Lookup::getterAccessor2(Lookup *l, const ValueRef object)
{
- if (Object *o = object->asObject()) {
+ 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) {
o = o->prototype();
if (l->classList[1] == o->internalClass) {
@@ -335,7 +343,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx)
}
Scope scope(ctx);
Scoped<String> n(scope, l->name);
- ctx->throwReferenceError(n);
+ return ctx->throwReferenceError(n);
}
ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionContext *ctx)
@@ -439,6 +447,8 @@ void Lookup::setterGeneric(Lookup *l, const ValueRef object, const ValueRef valu
ScopedObject o(scope, object);
if (!o) {
o = __qmljs_convert_to_object(scope.engine->current, object);
+ if (!o) // type error
+ return;
ScopedString s(scope, l->name);
o->put(s, value);
return;
@@ -463,6 +473,8 @@ void Lookup::setterInsert0(Lookup *l, const ValueRef object, const ValueRef valu
Object *o = object->asObject();
if (o && o->internalClass == l->classList[0]) {
if (!o->prototype()) {
+ if (l->index >= o->memberDataAlloc)
+ o->ensureMemberIndex(l->index);
o->memberData[l->index].value = *value;
o->internalClass = l->classList[3];
return;
@@ -479,6 +491,8 @@ void Lookup::setterInsert1(Lookup *l, const ValueRef object, const ValueRef valu
if (o && o->internalClass == l->classList[0]) {
Object *p = o->prototype();
if (p && p->internalClass == l->classList[1]) {
+ if (l->index >= o->memberDataAlloc)
+ o->ensureMemberIndex(l->index);
o->memberData[l->index].value = *value;
o->internalClass = l->classList[3];
return;
@@ -497,7 +511,8 @@ void Lookup::setterInsert2(Lookup *l, const ValueRef object, const ValueRef valu
if (p && p->internalClass == l->classList[1]) {
p = p->prototype();
if (p && p->internalClass == l->classList[2]) {
- o->ensureMemberIndex(l->index);
+ if (l->index >= o->memberDataAlloc)
+ o->ensureMemberIndex(l->index);
o->memberData[l->index].value = *value;
o->internalClass = l->classList[3];
return;
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 31bb8f2b94..6455a08037 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -168,29 +168,34 @@ QString Managed::className() const
case Type_ForeachIteratorObject:
s = "__ForeachIterator";
break;
+ case Type_RegExp:
+ s = "RegExp";
+ break;
+ case Type_QmlSequence:
+ s = "QmlSequence";
+ break;
}
return QString::fromLatin1(s);
}
bool Managed::hasInstance(Managed *m, const ValueRef)
{
- m->engine()->current->throwTypeError();
+ return m->engine()->current->throwTypeError();
}
ReturnedValue Managed::construct(Managed *m, CallData *)
{
- m->engine()->current->throwTypeError();
+ return m->engine()->current->throwTypeError();
}
ReturnedValue Managed::call(Managed *m, CallData *)
{
- m->engine()->current->throwTypeError();
+ return m->engine()->current->throwTypeError();
}
ReturnedValue Managed::getLookup(Managed *m, Lookup *)
{
- m->engine()->current->throwTypeError();
- return 0;
+ return m->engine()->current->throwTypeError();
}
void Managed::setLookup(Managed *m, Lookup *, const ValueRef)
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index b4469c8048..47ac5e05e4 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -81,7 +81,7 @@ struct ManagedVTable
{
ReturnedValue (*call)(Managed *, CallData *data);
ReturnedValue (*construct)(Managed *, CallData *data);
- void (*markObjects)(Managed *);
+ void (*markObjects)(Managed *, ExecutionEngine *e);
void (*destroy)(Managed *);
void (*collectDeletables)(Managed *, GCDeletable **deletable);
bool (*hasInstance)(Managed *, const ValueRef value);
@@ -166,13 +166,7 @@ public:
void operator delete(void *ptr);
void operator delete(void *ptr, MemoryManager *mm);
- inline void mark() {
- if (markBit)
- return;
- markBit = 1;
- if (vtbl->markObjects)
- vtbl->markObjects(this);
- }
+ inline void mark(QV4::ExecutionEngine *engine);
enum Type {
Type_Invalid,
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 6280b7c392..5a7af1f041 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -46,6 +46,9 @@
#include <qmath.h>
#include <qnumeric.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qthreadstorage.h>
+
using namespace QV4;
static const double qt_PI = 2.0 * ::asin(1.0);
@@ -99,7 +102,7 @@ static double copySign(double x, double y)
return x;
}
-ReturnedValue MathObject::method_abs(SimpleCallContext *context)
+ReturnedValue MathObject::method_abs(CallContext *context)
{
if (!context->callData->argc)
return Encode(qSNaN());
@@ -116,7 +119,7 @@ ReturnedValue MathObject::method_abs(SimpleCallContext *context)
return Encode(v < 0 ? -v : v);
}
-ReturnedValue MathObject::method_acos(SimpleCallContext *context)
+ReturnedValue MathObject::method_acos(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : 2;
if (v > 1)
@@ -125,7 +128,7 @@ ReturnedValue MathObject::method_acos(SimpleCallContext *context)
return Encode(::acos(v));
}
-ReturnedValue MathObject::method_asin(SimpleCallContext *context)
+ReturnedValue MathObject::method_asin(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : 2;
if (v > 1)
@@ -134,7 +137,7 @@ ReturnedValue MathObject::method_asin(SimpleCallContext *context)
return Encode(::asin(v));
}
-ReturnedValue MathObject::method_atan(SimpleCallContext *context)
+ReturnedValue MathObject::method_atan(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
if (v == 0.0)
@@ -143,7 +146,7 @@ ReturnedValue MathObject::method_atan(SimpleCallContext *context)
return Encode(::atan(v));
}
-ReturnedValue MathObject::method_atan2(SimpleCallContext *context)
+ReturnedValue MathObject::method_atan2(CallContext *context)
{
double v1 = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
double v2 = context->callData->argc > 1 ? context->callData->args[1].toNumber() : qSNaN();
@@ -161,7 +164,7 @@ ReturnedValue MathObject::method_atan2(SimpleCallContext *context)
return Encode(::atan2(v1, v2));
}
-ReturnedValue MathObject::method_ceil(SimpleCallContext *context)
+ReturnedValue MathObject::method_ceil(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
if (v < 0.0 && v > -1.0)
@@ -170,13 +173,13 @@ ReturnedValue MathObject::method_ceil(SimpleCallContext *context)
return Encode(::ceil(v));
}
-ReturnedValue MathObject::method_cos(SimpleCallContext *context)
+ReturnedValue MathObject::method_cos(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
return Encode(::cos(v));
}
-ReturnedValue MathObject::method_exp(SimpleCallContext *context)
+ReturnedValue MathObject::method_exp(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
if (qIsInf(v)) {
@@ -189,13 +192,13 @@ ReturnedValue MathObject::method_exp(SimpleCallContext *context)
}
}
-ReturnedValue MathObject::method_floor(SimpleCallContext *context)
+ReturnedValue MathObject::method_floor(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
return Encode(::floor(v));
}
-ReturnedValue MathObject::method_log(SimpleCallContext *context)
+ReturnedValue MathObject::method_log(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
if (v < 0)
@@ -204,10 +207,10 @@ ReturnedValue MathObject::method_log(SimpleCallContext *context)
return Encode(::log(v));
}
-ReturnedValue MathObject::method_max(SimpleCallContext *context)
+ReturnedValue MathObject::method_max(CallContext *context)
{
double mx = -qInf();
- for (unsigned i = 0; i < context->callData->argc; ++i) {
+ for (int i = 0; i < context->callData->argc; ++i) {
double x = context->callData->args[i].toNumber();
if (x > mx || std::isnan(x))
mx = x;
@@ -215,10 +218,10 @@ ReturnedValue MathObject::method_max(SimpleCallContext *context)
return Encode(mx);
}
-ReturnedValue MathObject::method_min(SimpleCallContext *context)
+ReturnedValue MathObject::method_min(CallContext *context)
{
double mx = qInf();
- for (unsigned i = 0; i < context->callData->argc; ++i) {
+ for (int i = 0; i < context->callData->argc; ++i) {
double x = context->callData->args[i].toNumber();
if ((x == 0 && mx == x && copySign(1.0, x) == -1.0)
|| (x < mx) || std::isnan(x)) {
@@ -228,7 +231,7 @@ ReturnedValue MathObject::method_min(SimpleCallContext *context)
return Encode(mx);
}
-ReturnedValue MathObject::method_pow(SimpleCallContext *context)
+ReturnedValue MathObject::method_pow(CallContext *context)
{
double x = context->callData->argc > 0 ? context->callData->args[0].toNumber() : qSNaN();
double y = context->callData->argc > 1 ? context->callData->args[1].toNumber() : qSNaN();
@@ -278,31 +281,37 @@ ReturnedValue MathObject::method_pow(SimpleCallContext *context)
return Encode(qSNaN());
}
-ReturnedValue MathObject::method_random(SimpleCallContext *)
+Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage);
+
+ReturnedValue MathObject::method_random(CallContext *context)
{
+ if (!seedCreatedStorage()->hasLocalData()) {
+ qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(context));
+ seedCreatedStorage()->setLocalData(new bool(true));
+ }
return Encode(qrand() / (double) RAND_MAX);
}
-ReturnedValue MathObject::method_round(SimpleCallContext *context)
+ReturnedValue MathObject::method_round(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
v = copySign(::floor(v + 0.5), v);
return Encode(v);
}
-ReturnedValue MathObject::method_sin(SimpleCallContext *context)
+ReturnedValue MathObject::method_sin(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
return Encode(::sin(v));
}
-ReturnedValue MathObject::method_sqrt(SimpleCallContext *context)
+ReturnedValue MathObject::method_sqrt(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
return Encode(::sqrt(v));
}
-ReturnedValue MathObject::method_tan(SimpleCallContext *context)
+ReturnedValue MathObject::method_tan(CallContext *context)
{
double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
if (v == 0.0)
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index b65264b5dd..dca75e6c28 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -51,24 +51,24 @@ struct MathObject: Object
{
MathObject(ExecutionEngine *engine);
- static ReturnedValue method_abs(SimpleCallContext *context);
- static ReturnedValue method_acos(SimpleCallContext *context);
- static ReturnedValue method_asin(SimpleCallContext *context);
- static ReturnedValue method_atan(SimpleCallContext *context);
- static ReturnedValue method_atan2(SimpleCallContext *context);
- static ReturnedValue method_ceil(SimpleCallContext *context);
- static ReturnedValue method_cos(SimpleCallContext *context);
- static ReturnedValue method_exp(SimpleCallContext *context);
- static ReturnedValue method_floor(SimpleCallContext *context);
- static ReturnedValue method_log(SimpleCallContext *context);
- static ReturnedValue method_max(SimpleCallContext *context);
- static ReturnedValue method_min(SimpleCallContext *context);
- static ReturnedValue method_pow(SimpleCallContext *context);
- static ReturnedValue method_random(SimpleCallContext *context);
- static ReturnedValue method_round(SimpleCallContext *context);
- static ReturnedValue method_sin(SimpleCallContext *context);
- static ReturnedValue method_sqrt(SimpleCallContext *context);
- static ReturnedValue method_tan(SimpleCallContext *context);
+ static ReturnedValue method_abs(CallContext *context);
+ static ReturnedValue method_acos(CallContext *context);
+ static ReturnedValue method_asin(CallContext *context);
+ static ReturnedValue method_atan(CallContext *context);
+ static ReturnedValue method_atan2(CallContext *context);
+ static ReturnedValue method_ceil(CallContext *context);
+ static ReturnedValue method_cos(CallContext *context);
+ static ReturnedValue method_exp(CallContext *context);
+ static ReturnedValue method_floor(CallContext *context);
+ static ReturnedValue method_log(CallContext *context);
+ static ReturnedValue method_max(CallContext *context);
+ static ReturnedValue method_min(CallContext *context);
+ static ReturnedValue method_pow(CallContext *context);
+ static ReturnedValue method_random(CallContext *context);
+ static ReturnedValue method_round(CallContext *context);
+ static ReturnedValue method_sin(CallContext *context);
+ static ReturnedValue method_sqrt(CallContext *context);
+ static ReturnedValue method_tan(CallContext *context);
};
}
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index a03f2865f1..0b15588ed4 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -146,13 +146,27 @@ struct MemoryManager::Data
uint nChunks[MaxItemSize/16];
uint availableItems[MaxItemSize/16];
uint allocCount[MaxItemSize/16];
+ int totalItems;
+ int totalAlloc;
struct Chunk {
PageAllocation memory;
int chunkSize;
};
QVector<Chunk> heapChunks;
- QHash<Managed *, uint> protectedObject;
+
+
+ struct LargeItem {
+ LargeItem *next;
+ void *data;
+
+ Managed *managed() {
+ return reinterpret_cast<Managed *>(&data);
+ }
+ };
+
+ LargeItem *largeItems;
+
// statistics:
#ifdef DETAILED_MM_STATS
@@ -164,6 +178,9 @@ struct MemoryManager::Data
, gcBlocked(false)
, engine(0)
, stackTop(0)
+ , totalItems(0)
+ , totalAlloc(0)
+ , largeItems(0)
{
memset(smallItems, 0, sizeof(smallItems));
memset(nChunks, 0, sizeof(nChunks));
@@ -197,7 +214,6 @@ bool operator<(const MemoryManager::Data::Chunk &a, const MemoryManager::Data::C
MemoryManager::MemoryManager()
: m_d(new Data(true))
- , m_contextList(0)
, m_persistentValues(0)
, m_weakValues(0)
{
@@ -250,21 +266,26 @@ Managed *MemoryManager::alloc(std::size_t size)
willAllocate(size);
#endif // DETAILED_MM_STATS
- assert(size >= 16);
- assert(size % 16 == 0);
+ Q_ASSERT(size >= 16);
+ Q_ASSERT(size % 16 == 0);
size_t pos = size >> 4;
- ++m_d->allocCount[pos];
- // fits into a small bucket
- assert(size < MemoryManager::Data::MaxItemSize);
+ // doesn't fit into a small bucket
+ if (size >= MemoryManager::Data::MaxItemSize) {
+ // we use malloc for this
+ MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(malloc(size + sizeof(MemoryManager::Data::LargeItem)));
+ item->next = m_d->largeItems;
+ m_d->largeItems = item;
+ return item->managed();
+ }
Managed *m = m_d->smallItems[pos];
if (m)
goto found;
// try to free up space, otherwise allocate
- if (m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && !m_d->aggressiveGC) {
+ if (m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && m_d->totalAlloc > (m_d->totalItems >> 1) && !m_d->aggressiveGC) {
runGC();
m = m_d->smallItems[pos];
if (m)
@@ -277,11 +298,11 @@ Managed *MemoryManager::alloc(std::size_t size)
uint shift = ++m_d->nChunks[pos];
if (shift > 10)
shift = 10;
- std::size_t allocSize = CHUNK_SIZE*(1 << shift);
+ std::size_t allocSize = CHUNK_SIZE*(size_t(1) << shift);
allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize);
Data::Chunk allocation;
allocation.memory = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
- allocation.chunkSize = size;
+ allocation.chunkSize = int(size);
m_d->heapChunks.append(allocation);
std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end());
char *chunk = (char *)allocation.memory.base();
@@ -299,7 +320,9 @@ Managed *MemoryManager::alloc(std::size_t size)
}
*last = 0;
m = m_d->smallItems[pos];
- m_d->availableItems[pos] += allocation.memory.size()/size - 1;
+ const size_t increase = allocation.memory.size()/size - 1;
+ m_d->availableItems[pos] += uint(increase);
+ m_d->totalItems += int(increase);
#ifdef V4_USE_VALGRIND
VALGRIND_MAKE_MEM_NOACCESS(allocation.memory, allocation.chunkSize);
#endif
@@ -310,16 +333,17 @@ Managed *MemoryManager::alloc(std::size_t size)
VALGRIND_MEMPOOL_ALLOC(this, m, size);
#endif
+ ++m_d->allocCount[pos];
+ ++m_d->totalAlloc;
m_d->smallItems[pos] = m->nextFree();
return m;
}
void MemoryManager::mark()
{
- m_d->engine->markObjects();
+ SafeValue *markBase = m_d->engine->jsStackTop;
- for (QHash<Managed *, uint>::const_iterator it = m_d->protectedObject.begin(); it != m_d->protectedObject.constEnd(); ++it)
- it.key()->mark();
+ m_d->engine->markObjects();
PersistentValuePrivate *persistent = m_persistentValues;
while (persistent) {
@@ -330,7 +354,7 @@ void MemoryManager::mark()
persistent = n;
continue;
}
- persistent->value.mark();
+ persistent->value.mark(m_d->engine);
persistent = persistent->next;
}
@@ -338,7 +362,7 @@ void MemoryManager::mark()
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)
+#if COMPILER(MSVC) && !OS(WINRT) // WinRT must use exact GC
# if CPU(X86_64)
HANDLE thread = GetCurrentThread();
WOW64_CONTEXT ctxt;
@@ -394,7 +418,14 @@ void MemoryManager::mark()
}
if (keepAlive)
- qobjectWrapper->getPointer()->mark();
+ qobjectWrapper->getPointer()->mark(m_d->engine);
+ }
+
+ // now that we marked all roots, start marking recursively and popping from the mark stack
+ while (m_d->engine->jsStackTop > markBase) {
+ Managed *m = m_d->engine->popForGC();
+ Q_ASSERT (m->vtbl->markObjects);
+ m->vtbl->markObjects(m, m_d->engine);
}
}
@@ -436,18 +467,21 @@ void MemoryManager::sweep(bool lastSweep)
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);
- ExecutionContext *ctx = m_contextList;
- ExecutionContext **n = &m_contextList;
- while (ctx) {
- ExecutionContext *next = ctx->next;
- if (!ctx->marked) {
- free(ctx);
- *n = next;
- } else {
- ctx->marked = false;
- n = &ctx->next;
+ Data::LargeItem *i = m_d->largeItems;
+ Data::LargeItem **last = &m_d->largeItems;
+ while (i) {
+ Managed *m = i->managed();
+ Q_ASSERT(m->inUse);
+ if (m->markBit) {
+ m->markBit = 0;
+ last = &i->next;
+ i = i->next;
+ continue;
}
- ctx = next;
+
+ *last = i->next;
+ free(i);
+ i = *last;
}
deletable = *firstDeletable;
@@ -472,7 +506,7 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size,
// qDebug("chunk @ %p, size = %lu, in use: %s, mark bit: %s",
// chunk, m->size, (m->inUse ? "yes" : "no"), (m->markBit ? "true" : "false"));
- assert((qintptr) chunk % 16 == 0);
+ Q_ASSERT((qintptr) chunk % 16 == 0);
if (m->inUse) {
if (m->markBit) {
@@ -533,6 +567,7 @@ void MemoryManager::runGC()
// << " 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)
@@ -558,17 +593,6 @@ MemoryManager::~MemoryManager()
#endif
}
-void MemoryManager::protect(Managed *m)
-{
- ++m_d->protectedObject[m];
-}
-
-void MemoryManager::unprotect(Managed *m)
-{
- if (!--m_d->protectedObject[m])
- m_d->protectedObject.remove(m);
-}
-
void MemoryManager::setExecutionEngine(ExecutionEngine *engine)
{
m_d->engine = engine;
@@ -627,7 +651,7 @@ void MemoryManager::collectFromStack() const
heapChunkBoundaries[i++] = reinterpret_cast<char*>(it->memory.base()) - 1;
heapChunkBoundaries[i++] = reinterpret_cast<char*>(it->memory.base()) + it->memory.size() - it->chunkSize;
}
- assert(i == m_d->heapChunks.count() * 2);
+ Q_ASSERT(i == m_d->heapChunks.count() * 2);
for (; current < m_d->stackTop; ++current) {
char* genericPtr = reinterpret_cast<char *>(*current);
@@ -636,7 +660,7 @@ void MemoryManager::collectFromStack() const
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.
- assert(index >= 0 && index < m_d->heapChunks.count() * 2);
+ 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);
@@ -651,7 +675,7 @@ void MemoryManager::collectFromStack() const
continue;
// qDebug() << " marking";
- m->mark();
+ m->mark(m_d->engine);
}
}
}
@@ -664,7 +688,7 @@ void MemoryManager::collectFromJSStack() const
Managed *m = v->asManaged();
if (m && m->inUse)
// Skip pointers to already freed objects, they are bogus as well
- m->mark();
+ m->mark(m_d->engine);
++v;
}
}
diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h
index 95f49545b8..7d28319536 100644
--- a/src/qml/jsruntime/qv4mm_p.h
+++ b/src/qml/jsruntime/qv4mm_p.h
@@ -91,9 +91,6 @@ public:
MemoryManager();
~MemoryManager();
- void protect(Managed *m);
- void unprotect(Managed *m);
-
// TODO: this is only for 64bit (and x86 with SSE/AVX), so exend it for other architectures to be slightly more efficient (meaning, align on 8-byte boundaries).
// Note: all occurances of "16" in alloc/dealloc are also due to the alignment.
static inline std::size_t align(std::size_t size)
@@ -106,8 +103,6 @@ public:
return o;
}
- ExecutionContext *allocContext(uint size);
-
bool isGCBlocked() const;
void setGCBlocked(bool blockGC);
void runGC();
@@ -137,21 +132,11 @@ private:
protected:
QScopedPointer<Data> m_d;
- ExecutionContext *m_contextList;
public:
PersistentValuePrivate *m_persistentValues;
PersistentValuePrivate *m_weakValues;
};
-inline ExecutionContext *MemoryManager::allocContext(uint size)
-{
- ExecutionContext *newContext = (ExecutionContext *)malloc(size);
- newContext->next = m_contextList;
- m_contextList = newContext;
- return newContext;
-}
-
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 8a09de5349..039b790aed 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -107,7 +107,7 @@ inline ReturnedValue thisNumberValue(ExecutionContext *ctx)
return ctx->callData->thisObject.asReturnedValue();
NumberObject *n = ctx->callData->thisObject.asNumberObject();
if (!n)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return n->value.asReturnedValue();
}
@@ -117,21 +117,21 @@ inline double thisNumber(ExecutionContext *ctx)
return ctx->callData->thisObject.asDouble();
NumberObject *n = ctx->callData->thisObject.asNumberObject();
if (!n)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return n->value.asDouble();
}
-ReturnedValue NumberPrototype::method_toString(SimpleCallContext *ctx)
+ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
{
double num = thisNumber(ctx);
+ if (ctx->engine->hasException)
+ return Encode::undefined();
if (ctx->callData->argc && !ctx->callData->args[0].isUndefined()) {
int radix = ctx->callData->args[0].toInt32();
- if (radix < 2 || radix > 36) {
- ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix")
+ if (radix < 2 || radix > 36)
+ return ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix")
.arg(radix));
- return Encode::undefined();
- }
if (std::isnan(num)) {
return ctx->engine->newString(QStringLiteral("NaN"))->asReturnedValue();
@@ -173,23 +173,26 @@ ReturnedValue NumberPrototype::method_toString(SimpleCallContext *ctx)
return Primitive::fromDouble(num).toString(ctx)->asReturnedValue();
}
-ReturnedValue NumberPrototype::method_toLocaleString(SimpleCallContext *ctx)
+ReturnedValue NumberPrototype::method_toLocaleString(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue v(scope, thisNumberValue(ctx));
-
ScopedString str(scope, v->toString(ctx));
+ if (ctx->engine->hasException)
+ return Encode::undefined();
return str.asReturnedValue();
}
-ReturnedValue NumberPrototype::method_valueOf(SimpleCallContext *ctx)
+ReturnedValue NumberPrototype::method_valueOf(CallContext *ctx)
{
return thisNumberValue(ctx);
}
-ReturnedValue NumberPrototype::method_toFixed(SimpleCallContext *ctx)
+ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx)
{
double v = thisNumber(ctx);
+ if (ctx->engine->hasException)
+ return Encode::undefined();
double fdigits = 0;
@@ -200,7 +203,7 @@ ReturnedValue NumberPrototype::method_toFixed(SimpleCallContext *ctx)
fdigits = 0;
if (fdigits < 0 || fdigits > 20)
- ctx->throwRangeError(ctx->callData->thisObject);
+ return ctx->throwRangeError(ctx->callData->thisObject);
QString str;
if (std::isnan(v))
@@ -214,10 +217,12 @@ ReturnedValue NumberPrototype::method_toFixed(SimpleCallContext *ctx)
return ctx->engine->newString(str)->asReturnedValue();
}
-ReturnedValue NumberPrototype::method_toExponential(SimpleCallContext *ctx)
+ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx)
{
Scope scope(ctx);
double d = thisNumber(ctx);
+ if (ctx->engine->hasException)
+ return Encode::undefined();
int fdigits = -1;
@@ -225,7 +230,7 @@ ReturnedValue NumberPrototype::method_toExponential(SimpleCallContext *ctx)
int fdigits = ctx->callData->args[0].toInt32();
if (fdigits < 0 || fdigits > 20) {
ScopedString error(scope, ctx->engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range")));
- ctx->throwRangeError(error);
+ return ctx->throwRangeError(error);
}
}
@@ -237,18 +242,20 @@ ReturnedValue NumberPrototype::method_toExponential(SimpleCallContext *ctx)
return ctx->engine->newString(result)->asReturnedValue();
}
-ReturnedValue NumberPrototype::method_toPrecision(SimpleCallContext *ctx)
+ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue v(scope, thisNumberValue(ctx));
+ if (ctx->engine->hasException)
+ return Encode::undefined();
if (!ctx->callData->argc || ctx->callData->args[0].isUndefined())
- return __qmljs_to_string(v, ctx);
+ return __qmljs_to_string(ctx, v);
double precision = ctx->callData->args[0].toInt32();
if (precision < 1 || precision > 21) {
ScopedString error(scope, ctx->engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range")));
- ctx->throwRangeError(error);
+ return ctx->throwRangeError(error);
}
char str[100];
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index a4d13267bd..1ca3a71249 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -63,12 +63,12 @@ struct NumberPrototype: NumberObject
NumberPrototype(InternalClass *ic): NumberObject(ic) {}
void init(ExecutionEngine *engine, ObjectRef ctor);
- static ReturnedValue method_toString(SimpleCallContext *ctx);
- static ReturnedValue method_toLocaleString(SimpleCallContext *ctx);
- static ReturnedValue method_valueOf(SimpleCallContext *ctx);
- static ReturnedValue method_toFixed(SimpleCallContext *ctx);
- static ReturnedValue method_toExponential(SimpleCallContext *ctx);
- static ReturnedValue method_toPrecision(SimpleCallContext *ctx);
+ static ReturnedValue method_toString(CallContext *ctx);
+ static ReturnedValue method_toLocaleString(CallContext *ctx);
+ static ReturnedValue method_valueOf(CallContext *ctx);
+ static ReturnedValue method_toFixed(CallContext *ctx);
+ static ReturnedValue method_toExponential(CallContext *ctx);
+ static ReturnedValue method_toPrecision(CallContext *ctx);
};
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index b04c65196e..e4df95716d 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -147,6 +147,9 @@ ReturnedValue Object::getValue(const ValueRef thisObject, const Property *p, Pro
void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef value)
{
+ if (internalClass->engine->hasException)
+ return;
+
if (attrs.isAccessor()) {
if (pd->set) {
Scope scope(pd->set->engine());
@@ -168,7 +171,6 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val
reject:
if (engine()->current->strictMode)
engine()->current->throwTypeError();
-
}
void Object::defineDefaultProperty(const StringRef name, ValueRef value)
@@ -185,7 +187,7 @@ void Object::defineDefaultProperty(const QString &name, ValueRef value)
defineDefaultProperty(s, value);
}
-void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(SimpleCallContext *), int argumentCount)
+void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount)
{
ExecutionEngine *e = engine();
Scope scope(e);
@@ -195,7 +197,7 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Si
defineDefaultProperty(s, function);
}
-void Object::defineDefaultProperty(const StringRef name, ReturnedValue (*code)(SimpleCallContext *), int argumentCount)
+void Object::defineDefaultProperty(const StringRef name, ReturnedValue (*code)(CallContext *), int argumentCount)
{
ExecutionEngine *e = engine();
Scope scope(e);
@@ -204,7 +206,7 @@ void Object::defineDefaultProperty(const StringRef name, ReturnedValue (*code)(S
defineDefaultProperty(name, function);
}
-void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(SimpleCallContext *), ReturnedValue (*setter)(SimpleCallContext *))
+void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
{
ExecutionEngine *e = engine();
Scope scope(e);
@@ -212,7 +214,7 @@ void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)
defineAccessorProperty(s, getter, setter);
}
-void Object::defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(SimpleCallContext *), ReturnedValue (*setter)(SimpleCallContext *))
+void Object::defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
{
ExecutionEngine *v4 = engine();
Property *p = insertMember(name, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
@@ -237,40 +239,40 @@ void Object::defineReadonlyProperty(const StringRef name, ValueRef value)
pd->value = *value;
}
-void Object::markObjects(Managed *that)
+void Object::markObjects(Managed *that, ExecutionEngine *e)
{
Object *o = static_cast<Object *>(that);
if (!o->hasAccessorProperty) {
- for (int i = 0; i < o->internalClass->size; ++i)
- o->memberData[i].value.mark();
+ for (uint i = 0; i < o->internalClass->size; ++i)
+ o->memberData[i].value.mark(e);
} else {
- for (int i = 0; i < o->internalClass->size; ++i) {
+ for (uint i = 0; i < o->internalClass->size; ++i) {
const Property &pd = o->memberData[i];
if (o->internalClass->propertyData[i].isAccessor()) {
if (pd.getter())
- pd.getter()->mark();
+ pd.getter()->mark(e);
if (pd.setter())
- pd.setter()->mark();
+ pd.setter()->mark(e);
} else {
- pd.value.mark();
+ pd.value.mark(e);
}
}
}
if (o->flags & SimpleArray) {
for (uint i = 0; i < o->arrayDataLen; ++i)
- o->arrayData[i].value.mark();
+ o->arrayData[i].value.mark(e);
return;
} else {
for (uint i = 0; i < o->arrayDataLen; ++i) {
const Property &pd = o->arrayData[i];
if (o->arrayAttributes && o->arrayAttributes[i].isAccessor()) {
if (pd.getter())
- pd.getter()->mark();
+ pd.getter()->mark(e);
if (pd.setter())
- pd.setter()->mark();
+ pd.setter()->mark(e);
} else {
- pd.value.mark();
+ pd.value.mark(e);
}
}
}
@@ -690,6 +692,9 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty)
// Section 8.12.5
void Object::internalPut(const StringRef name, const ValueRef value)
{
+ if (internalClass->engine->hasException)
+ return;
+
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return putIndexed(idx, value);
@@ -715,8 +720,10 @@ void Object::internalPut(const StringRef name, const ValueRef value)
else if (isArrayObject() && name->equals(engine()->id_length)) {
bool ok;
uint l = value->asArrayLength(&ok);
- if (!ok)
+ if (!ok) {
engine()->current->throwRangeError(value);
+ return;
+ }
ok = setArrayLength(l);
if (!ok)
goto reject;
@@ -772,6 +779,9 @@ void Object::internalPut(const StringRef name, const ValueRef value)
void Object::internalPutIndexed(uint index, const ValueRef value)
{
+ if (internalClass->engine->hasException)
+ return;
+
Property *pd = 0;
PropertyAttributes attrs;
@@ -841,6 +851,9 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
// Section 8.12.7
bool Object::internalDeleteProperty(const StringRef name)
{
+ if (internalClass->engine->hasException)
+ return false;
+
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return deleteIndexedProperty(idx);
@@ -864,6 +877,9 @@ bool Object::internalDeleteProperty(const StringRef name)
bool Object::internalDeleteIndexedProperty(uint index)
{
+ if (internalClass->engine->hasException)
+ return false;
+
uint pidx = propertyIndexFromArrayIndex(index);
if (pidx == UINT_MAX)
return true;
@@ -902,7 +918,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name,
if (isArrayObject() && name->equals(ctx->engine->id_length)) {
assert(ArrayObject::LengthPropertyIndex == internalClass->find(ctx->engine->id_length));
Property *lp = memberData + ArrayObject::LengthPropertyIndex;
- cattrs = internalClass->propertyData.data() + ArrayObject::LengthPropertyIndex;
+ cattrs = internalClass->propertyData.constData() + ArrayObject::LengthPropertyIndex;
if (attrs.isEmpty() || p.isSubset(attrs, *lp, *cattrs))
return true;
if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable())
@@ -914,6 +930,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name,
if (!ok) {
ScopedValue v(scope, p.value);
ctx->throwRangeError(v);
+ return false;
}
succeeded = setArrayLength(l);
}
@@ -930,7 +947,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name,
{
uint member = internalClass->find(name.getPointer());
current = (member < UINT_MAX) ? memberData + member : 0;
- cattrs = internalClass->propertyData.data() + member;
+ cattrs = internalClass->propertyData.constData() + member;
}
if (!current) {
@@ -1111,25 +1128,31 @@ void Object::copyArrayData(Object *other)
ReturnedValue Object::arrayIndexOf(const ValueRef v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o)
{
+ Q_UNUSED(ctx);
+
Scope scope(engine());
ScopedValue value(scope);
- if (o->protoHasArray() || o->arrayAttributes) {
+ if (!(o->flags & SimpleArray) || o->protoHasArray()) {
// lets be safe and slow
for (uint i = fromIndex; i < endIndex; ++i) {
bool exists;
value = o->getIndexed(i, &exists);
+ if (scope.hasException())
+ return Encode::undefined();
if (exists && __qmljs_strict_equal(value, v))
return Encode(i);
}
} else if (sparseArray) {
for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n != sparseArray->end() && n->key() < endIndex; n = n->nextNode()) {
value = o->getValue(arrayData + n->value, arrayAttributes ? arrayAttributes[n->value] : Attr_Data);
+ if (scope.hasException())
+ return Encode::undefined();
if (__qmljs_strict_equal(value, v))
return Encode(n->key());
}
} else {
- if ((int) endIndex > arrayDataLen)
+ if (endIndex > arrayDataLen)
endIndex = arrayDataLen;
Property *pd = arrayData;
Property *end = pd + endIndex;
@@ -1137,6 +1160,8 @@ ReturnedValue Object::arrayIndexOf(const ValueRef v, uint fromIndex, uint endInd
while (pd < end) {
if (!pd->value.isEmpty()) {
value = o->getValue(pd, arrayAttributes ? arrayAttributes[pd - arrayData] : Attr_Data);
+ if (scope.hasException())
+ return Encode::undefined();
if (__qmljs_strict_equal(value, v))
return Encode((uint)(pd - arrayData));
}
@@ -1168,14 +1193,14 @@ void Object::arrayConcat(const ArrayObject *other)
}
}
} else {
- int oldSize = arrayLength();
+ uint oldSize = arrayLength();
arrayReserve(oldSize + other->arrayDataLen);
if (oldSize > arrayDataLen) {
- for (int i = arrayDataLen; i < oldSize; ++i)
+ for (uint i = arrayDataLen; i < oldSize; ++i)
arrayData[i].value = Primitive::emptyValue();
}
if (other->arrayAttributes) {
- for (int i = 0; i < other->arrayDataLen; ++i) {
+ for (uint i = 0; i < other->arrayDataLen; ++i) {
bool exists;
arrayData[oldSize + i].value = const_cast<ArrayObject *>(other)->getIndexed(i, &exists);
arrayDataLen = oldSize + i + 1;
@@ -1200,7 +1225,7 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va
return;
if (sparseArray) {
- context->throwUnimplemented("Object::sort unimplemented for sparse arrays");
+ context->throwUnimplemented(QStringLiteral("Object::sort unimplemented for sparse arrays"));
return;
}
@@ -1230,8 +1255,10 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va
}
}
- if (!(comparefn->isUndefined() || comparefn->asObject()))
+ if (!(comparefn->isUndefined() || comparefn->asObject())) {
context->throwTypeError();
+ return;
+ }
ArrayElementLessThan lessThan(context, thisObject, comparefn);
@@ -1242,7 +1269,7 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va
// and aborts otherwise. We do not want JavaScript to easily crash
// the entire application and therefore choose qSort, which doesn't
// have this property.
- qSort(begin, begin + len, lessThan);
+ std::sort(begin, begin + len, lessThan);
}
@@ -1251,7 +1278,7 @@ void Object::initSparse()
if (!sparseArray) {
flags &= ~SimpleArray;
sparseArray = new SparseArray;
- for (int i = 0; i < arrayDataLen; ++i) {
+ for (uint i = 0; i < arrayDataLen; ++i) {
if (!((arrayAttributes && arrayAttributes[i].isGeneric()) || arrayData[i].value.isEmpty())) {
SparseArrayNode *n = sparseArray->insert(i);
n->value = i + arrayOffset;
@@ -1271,7 +1298,7 @@ void Object::initSparse()
}
arrayData[o - 1].value = Primitive::fromInt32(arrayDataLen + off);
}
- for (int i = arrayDataLen + off; i < arrayAlloc; ++i) {
+ for (uint i = arrayDataLen + off; i < arrayAlloc; ++i) {
arrayData[i].value = Primitive::fromInt32(i + 1);
}
}
@@ -1292,19 +1319,17 @@ void Object::arrayReserve(uint n)
off = arrayOffset;
}
arrayAlloc = qMax(n, 2*arrayAlloc);
- Property *newArrayData = new Property[arrayAlloc];
+ Property *newArrayData = new Property[arrayAlloc + off];
if (arrayData) {
- memcpy(newArrayData, arrayData, sizeof(Property)*arrayDataLen);
+ memcpy(newArrayData + off, arrayData, sizeof(Property)*arrayDataLen);
delete [] (arrayData - off);
}
- arrayData = newArrayData;
+ arrayData = newArrayData + off;
if (sparseArray) {
for (uint i = arrayFreeList; i < arrayAlloc; ++i) {
arrayData[i].value = Primitive::emptyValue();
arrayData[i].value = Primitive::fromInt32(i + 1);
}
- } else {
- arrayOffset = 0;
}
if (arrayAttributes) {
@@ -1327,7 +1352,9 @@ void Object::ensureArrayAttributes()
return;
flags &= ~SimpleArray;
- arrayAttributes = new PropertyAttributes[arrayAlloc];
+ uint off = sparseArray ? 0 : arrayOffset;
+ arrayAttributes = new PropertyAttributes[arrayAlloc + off];
+ arrayAttributes += off;
for (uint i = 0; i < arrayDataLen; ++i)
arrayAttributes[i] = Attr_Data;
for (uint i = arrayDataLen; i < arrayAlloc; ++i)
@@ -1418,6 +1445,8 @@ ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list)
void ArrayObject::init(ExecutionEngine *engine)
{
+ Q_UNUSED(engine);
+
type = Type_ArrayObject;
memberData[LengthPropertyIndex].value = Primitive::fromInt32(0);
}
@@ -1433,7 +1462,7 @@ QStringList ArrayObject::toQStringList() const
uint32_t length = arrayLength();
for (uint32_t i = 0; i < length; ++i) {
v = const_cast<ArrayObject *>(this)->getIndexed(i);
- result.append(v->toString(engine->current)->toQString());
+ result.append(v->toQStringNoThrow());
}
return result;
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 097d40db55..daef18d4e2 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -158,10 +158,10 @@ struct Q_QML_EXPORT Object: Managed {
/* The spec default: Writable: true, Enumerable: false, Configurable: true */
void defineDefaultProperty(const StringRef name, ValueRef value);
void defineDefaultProperty(const QString &name, ValueRef value);
- void defineDefaultProperty(const QString &name, ReturnedValue (*code)(SimpleCallContext *), int argumentCount = 0);
- void defineDefaultProperty(const StringRef name, ReturnedValue (*code)(SimpleCallContext *), int argumentCount = 0);
- void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(SimpleCallContext *), ReturnedValue (*setter)(SimpleCallContext *));
- void defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(SimpleCallContext *), ReturnedValue (*setter)(SimpleCallContext *));
+ void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
+ void defineDefaultProperty(const StringRef name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
+ void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
+ void defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
/* Fixed: Writable: false, Enumerable: false, Configurable: false */
void defineReadonlyProperty(const QString &name, ValueRef value);
void defineReadonlyProperty(const StringRef name, ValueRef value);
@@ -300,7 +300,7 @@ public:
using Managed::advanceIterator;
protected:
static void destroy(Managed *that);
- static void markObjects(Managed *that);
+ static void markObjects(Managed *that, ExecutionEngine *e);
static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
static void put(Managed *m, const StringRef name, const ValueRef value);
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 46698b0ad3..04fa504991 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -42,6 +42,7 @@
#include "qv4object_p.h"
#include "qv4stringobject_p.h"
#include "qv4identifier_p.h"
+#include "qv4argumentsobject_p.h"
using namespace QV4;
@@ -56,6 +57,11 @@ ObjectIterator::ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const
object = o;
current = o;
tmpDynamicProperty.value = Primitive::undefinedValue();
+
+ if (object && object->isNonStrictArgumentsObject) {
+ Scope scope(object->engine());
+ Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
+ }
}
ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
@@ -69,6 +75,11 @@ ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
object = o;
current = o;
tmpDynamicProperty.value = Primitive::undefinedValue();
+
+ if (object && object->isNonStrictArgumentsObject) {
+ Scope scope(object->engine());
+ Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
+ }
}
Property *ObjectIterator::next(StringRef name, uint *index, PropertyAttributes *attrs)
@@ -83,7 +94,7 @@ Property *ObjectIterator::next(StringRef name, uint *index, PropertyAttributes *
if (!current)
break;
- while (p = current->advanceIterator(this, name, index, attrs)) {
+ while ((p = current->advanceIterator(this, name, index, attrs))) {
// check the property is not already defined earlier in the proto chain
if (current != object) {
Property *pp;
@@ -174,10 +185,10 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString()
DEFINE_MANAGED_VTABLE(ForEachIteratorObject);
-void ForEachIteratorObject::markObjects(Managed *that)
+void ForEachIteratorObject::markObjects(Managed *that, ExecutionEngine *e)
{
ForEachIteratorObject *o = static_cast<ForEachIteratorObject *>(that);
- o->workArea[0].mark();
- o->workArea[1].mark();
- Object::markObjects(that);
+ o->workArea[0].mark(e);
+ o->workArea[1].mark(e);
+ Object::markObjects(that, e);
}
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index e38fa8d7b6..19aedf3766 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -96,7 +96,7 @@ struct ForEachIteratorObject: Object {
ReturnedValue nextPropertyName() { return it.nextPropertyNameAsString(); }
protected:
- static void markObjects(Managed *that);
+ static void markObjects(Managed *that, ExecutionEngine *e);
SafeObject workArea[2];
};
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 7cfda589e5..f17bd7d5ba 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -41,6 +41,7 @@
#include "qv4objectproto_p.h"
+#include "qv4argumentsobject_p.h"
#include "qv4mm_p.h"
#include "qv4scopedvalue_p.h"
#include <QtCore/qnumeric.h>
@@ -138,48 +139,53 @@ void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor)
p->setSetter(v4->newBuiltinFunction(v4->rootContext, id_proto, method_set_proto)->getPointer());
}
-ReturnedValue ObjectPrototype::method_getPrototypeOf(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->argument(0));
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<Object> p(scope, o->prototype());
return !!p ? p->asReturnedValue() : Encode::null();
}
-ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> O(scope, ctx->argument(0));
if (!O)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
+
+ if (O->isNonStrictArgumentsObject)
+ Scoped<ArgumentsObject>(scope, O)->fullyCreate();
ScopedValue v(scope, ctx->argument(1));
Scoped<String> name(scope, v->toString(ctx));
+ if (scope.hasException())
+ return Encode::undefined();
PropertyAttributes attrs;
Property *desc = O->__getOwnProperty__(name, &attrs);
return fromPropertyDescriptor(ctx, desc, attrs);
}
-ReturnedValue ObjectPrototype::method_getOwnPropertyNames(SimpleCallContext *context)
+ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context)
{
Scope scope(context);
ScopedObject O(scope, context->argument(0));
if (!O)
- context->throwTypeError();
+ return context->throwTypeError();
ScopedArrayObject array(scope, getOwnPropertyNames(context->engine, context->callData->args[0]));
return array.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_create(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_create(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue O(scope, ctx->argument(0));
if (!O->isObject() && !O->isNull())
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<Object> newObject(scope, ctx->engine->newObject());
newObject->setPrototype(O->asObject());
@@ -192,34 +198,40 @@ ReturnedValue ObjectPrototype::method_create(SimpleCallContext *ctx)
return newObject.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_defineProperty(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> O(scope, ctx->argument(0));
if (!O)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<String> name(scope, ctx->argument(1), Scoped<String>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
ScopedValue attributes(scope, ctx->argument(2));
Property pd;
PropertyAttributes attrs;
toPropertyDescriptor(ctx, attributes, &pd, &attrs);
+ if (scope.engine->hasException)
+ return Encode::undefined();
if (!O->__defineOwnProperty__(ctx, name, pd, attrs))
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return O.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_defineProperties(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> O(scope, ctx->argument(0));
if (!O)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<Object> o(scope, ctx->argument(1), Scoped<Object>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
ScopedValue val(scope);
ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
@@ -234,24 +246,26 @@ ReturnedValue ObjectPrototype::method_defineProperties(SimpleCallContext *ctx)
PropertyAttributes nattrs;
val = o->getValue(pd, attrs);
toPropertyDescriptor(ctx, val, &n, &nattrs);
+ if (scope.engine->hasException)
+ return Encode::undefined();
bool ok;
if (name)
ok = O->__defineOwnProperty__(ctx, name, n, nattrs);
else
ok = O->__defineOwnProperty__(ctx, index, n, nattrs);
if (!ok)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
}
return O.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_seal(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_seal(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->argument(0));
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
o->extensible = false;
@@ -266,12 +280,15 @@ ReturnedValue ObjectPrototype::method_seal(SimpleCallContext *ctx)
return o.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_freeze(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->argument(0));
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
+
+ if (o->isNonStrictArgumentsObject)
+ Scoped<ArgumentsObject>(scope, o)->fullyCreate();
o->extensible = false;
@@ -287,23 +304,23 @@ ReturnedValue ObjectPrototype::method_freeze(SimpleCallContext *ctx)
return o.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_preventExtensions(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->argument(0));
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
o->extensible = false;
return o.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_isSealed(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->argument(0));
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (o->extensible)
return Encode(false);
@@ -326,12 +343,12 @@ ReturnedValue ObjectPrototype::method_isSealed(SimpleCallContext *ctx)
return Encode(true);
}
-ReturnedValue ObjectPrototype::method_isFrozen(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->argument(0));
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (o->extensible)
return Encode(false);
@@ -354,22 +371,22 @@ ReturnedValue ObjectPrototype::method_isFrozen(SimpleCallContext *ctx)
return Encode(true);
}
-ReturnedValue ObjectPrototype::method_isExtensible(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->argument(0));
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return Encode((bool)o->extensible);
}
-ReturnedValue ObjectPrototype::method_keys(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_keys(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->argument(0));
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
@@ -385,7 +402,7 @@ ReturnedValue ObjectPrototype::method_keys(SimpleCallContext *ctx)
return a.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_toString(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
if (ctx->callData->thisObject.isUndefined()) {
@@ -395,41 +412,49 @@ ReturnedValue ObjectPrototype::method_toString(SimpleCallContext *ctx)
} else {
ScopedObject obj(scope, __qmljs_to_object(ctx, ValueRef(&ctx->callData->thisObject)));
QString className = obj->className();
- return ctx->engine->newString(QString::fromUtf8("[object %1]").arg(className))->asReturnedValue();
+ return ctx->engine->newString(QString::fromLatin1("[object %1]").arg(className))->asReturnedValue();
}
}
-ReturnedValue ObjectPrototype::method_toLocaleString(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject o(scope, ctx->callData->thisObject.toObject(ctx));
+ if (!o)
+ return Encode::undefined();
Scoped<FunctionObject> f(scope, o->get(ctx->engine->id_toString));
if (!f)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedCallData callData(scope, 0);
callData->thisObject = o;
return f->call(callData);
}
-ReturnedValue ObjectPrototype::method_valueOf(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue v(scope, ctx->callData->thisObject.toObject(ctx));
+ if (ctx->engine->hasException)
+ return Encode::undefined();
return v.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_hasOwnProperty(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_hasOwnProperty(CallContext *ctx)
{
Scope scope(ctx);
Scoped<String> P(scope, ctx->argument(0), Scoped<String>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<Object> O(scope, ctx->callData->thisObject, Scoped<Object>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
bool r = O->__getOwnProperty__(P) != 0;
if (!r)
r = !O->query(P).isEmpty();
return Encode(r);
}
-ReturnedValue ObjectPrototype::method_isPrototypeOf(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_isPrototypeOf(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> V(scope, ctx->argument(0));
@@ -437,6 +462,8 @@ ReturnedValue ObjectPrototype::method_isPrototypeOf(SimpleCallContext *ctx)
return Encode(false);
Scoped<Object> O(scope, ctx->callData->thisObject, Scoped<Object>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<Object> proto(scope, V->prototype());
while (proto) {
if (O.getPointer() == proto.getPointer())
@@ -446,28 +473,34 @@ ReturnedValue ObjectPrototype::method_isPrototypeOf(SimpleCallContext *ctx)
return Encode(false);
}
-ReturnedValue ObjectPrototype::method_propertyIsEnumerable(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx)
{
Scope scope(ctx);
Scoped<String> p(scope, ctx->argument(0), Scoped<String>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<Object> o(scope, ctx->callData->thisObject, Scoped<Object>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
PropertyAttributes attrs;
o->__getOwnProperty__(p, &attrs);
return Encode(attrs.isEnumerable());
}
-ReturnedValue ObjectPrototype::method_defineGetter(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx)
{
if (ctx->callData->argc < 2)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scope scope(ctx);
Scoped<String> prop(scope, ctx->argument(0), Scoped<String>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<FunctionObject> f(scope, ctx->argument(1));
if (!f)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<Object> o(scope, ctx->callData->thisObject);
if (!o) {
@@ -481,17 +514,19 @@ ReturnedValue ObjectPrototype::method_defineGetter(SimpleCallContext *ctx)
return Encode::undefined();
}
-ReturnedValue ObjectPrototype::method_defineSetter(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx)
{
if (ctx->callData->argc < 2)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scope scope(ctx);
Scoped<String> prop(scope, ctx->argument(0), Scoped<String>::Convert);
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<FunctionObject> f(scope, ctx->argument(1));
if (!f)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<Object> o(scope, ctx->callData->thisObject);
if (!o) {
@@ -505,22 +540,22 @@ ReturnedValue ObjectPrototype::method_defineSetter(SimpleCallContext *ctx)
return Encode::undefined();
}
-ReturnedValue ObjectPrototype::method_get_proto(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx)
{
Scope scope(ctx);
ScopedObject o(scope, ctx->callData->thisObject.asObject());
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return o->prototype()->asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_set_proto(SimpleCallContext *ctx)
+ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Object> o(scope, ctx->callData->thisObject);
if (!o || !ctx->callData->argc)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (ctx->callData->args[0].isNull()) {
o->setPrototype(0);
@@ -537,7 +572,7 @@ ReturnedValue ObjectPrototype::method_set_proto(SimpleCallContext *ctx)
}
}
if (!ok)
- ctx->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
+ return ctx->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
return Encode::undefined();
}
@@ -545,8 +580,10 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef
{
Scope scope(ctx);
ScopedObject o(scope, v);
- if (!o)
+ if (!o) {
ctx->throwTypeError();
+ return;
+ }
attrs->clear();
desc->setGetter(0);
@@ -568,6 +605,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef
desc->setGetter((FunctionObject *)0x1);
} else {
ctx->throwTypeError();
+ return;
}
attrs->setType(PropertyAttributes::Accessor);
}
@@ -581,21 +619,26 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef
desc->setSetter((FunctionObject *)0x1);
} else {
ctx->throwTypeError();
+ return;
}
attrs->setType(PropertyAttributes::Accessor);
}
if (o->__hasProperty__(ctx->engine->id_writable)) {
- if (attrs->isAccessor())
+ if (attrs->isAccessor()) {
ctx->throwTypeError();
+ return;
+ }
attrs->setWritable((tmp = o->get(ctx->engine->id_writable))->toBoolean());
// writable forces it to be a data descriptor
desc->value = Primitive::undefinedValue();
}
if (o->__hasProperty__(ctx->engine->id_value)) {
- if (attrs->isAccessor())
+ if (attrs->isAccessor()) {
ctx->throwTypeError();
+ return;
+ }
desc->value = o->get(ctx->engine->id_value);
attrs->setType(PropertyAttributes::Data);
}
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index b5dcd06032..0bd8072db8 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -64,32 +64,32 @@ struct ObjectPrototype: Object
void init(ExecutionEngine *engine, ObjectRef ctor);
- static ReturnedValue method_getPrototypeOf(SimpleCallContext *ctx);
- static ReturnedValue method_getOwnPropertyDescriptor(SimpleCallContext *ctx);
- static ReturnedValue method_getOwnPropertyNames(SimpleCallContext *context);
- static ReturnedValue method_create(SimpleCallContext *ctx);
- static ReturnedValue method_defineProperty(SimpleCallContext *ctx);
- static ReturnedValue method_defineProperties(SimpleCallContext *ctx);
- static ReturnedValue method_seal(SimpleCallContext *ctx);
- static ReturnedValue method_freeze(SimpleCallContext *ctx);
- static ReturnedValue method_preventExtensions(SimpleCallContext *ctx);
- static ReturnedValue method_isSealed(SimpleCallContext *ctx);
- static ReturnedValue method_isFrozen(SimpleCallContext *ctx);
- static ReturnedValue method_isExtensible(SimpleCallContext *ctx);
- static ReturnedValue method_keys(SimpleCallContext *ctx);
-
- static ReturnedValue method_toString(SimpleCallContext *ctx);
- static ReturnedValue method_toLocaleString(SimpleCallContext *ctx);
- static ReturnedValue method_valueOf(SimpleCallContext *ctx);
- static ReturnedValue method_hasOwnProperty(SimpleCallContext *ctx);
- static ReturnedValue method_isPrototypeOf(SimpleCallContext *ctx);
- static ReturnedValue method_propertyIsEnumerable(SimpleCallContext *ctx);
-
- static ReturnedValue method_defineGetter(SimpleCallContext *ctx);
- static ReturnedValue method_defineSetter(SimpleCallContext *ctx);
-
- static ReturnedValue method_get_proto(SimpleCallContext *ctx);
- static ReturnedValue method_set_proto(SimpleCallContext *ctx);
+ static ReturnedValue method_getPrototypeOf(CallContext *ctx);
+ static ReturnedValue method_getOwnPropertyDescriptor(CallContext *ctx);
+ static ReturnedValue method_getOwnPropertyNames(CallContext *context);
+ static ReturnedValue method_create(CallContext *ctx);
+ static ReturnedValue method_defineProperty(CallContext *ctx);
+ static ReturnedValue method_defineProperties(CallContext *ctx);
+ static ReturnedValue method_seal(CallContext *ctx);
+ static ReturnedValue method_freeze(CallContext *ctx);
+ static ReturnedValue method_preventExtensions(CallContext *ctx);
+ static ReturnedValue method_isSealed(CallContext *ctx);
+ static ReturnedValue method_isFrozen(CallContext *ctx);
+ static ReturnedValue method_isExtensible(CallContext *ctx);
+ static ReturnedValue method_keys(CallContext *ctx);
+
+ static ReturnedValue method_toString(CallContext *ctx);
+ static ReturnedValue method_toLocaleString(CallContext *ctx);
+ static ReturnedValue method_valueOf(CallContext *ctx);
+ static ReturnedValue method_hasOwnProperty(CallContext *ctx);
+ static ReturnedValue method_isPrototypeOf(CallContext *ctx);
+ static ReturnedValue method_propertyIsEnumerable(CallContext *ctx);
+
+ static ReturnedValue method_defineGetter(CallContext *ctx);
+ static ReturnedValue method_defineSetter(CallContext *ctx);
+
+ static ReturnedValue method_get_proto(CallContext *ctx);
+ static ReturnedValue method_set_proto(CallContext *ctx);
static void toPropertyDescriptor(ExecutionContext *ctx, const ValueRef v, Property *desc, PropertyAttributes *attrs);
static ReturnedValue fromPropertyDescriptor(ExecutionContext *ctx, const Property *desc, PropertyAttributes attrs);
diff --git a/src/qml/jsruntime/qv4qmlextensions.cpp b/src/qml/jsruntime/qv4qmlextensions.cpp
index a55330ff67..547813bc66 100644
--- a/src/qml/jsruntime/qv4qmlextensions.cpp
+++ b/src/qml/jsruntime/qv4qmlextensions.cpp
@@ -44,8 +44,8 @@
using namespace QV4;
-void QmlExtensions::markObjects()
+void QmlExtensions::markObjects(ExecutionEngine *e)
{
if (valueTypeWrapperPrototype)
- valueTypeWrapperPrototype->mark();
+ valueTypeWrapperPrototype->mark(e);
}
diff --git a/src/qml/jsruntime/qv4qmlextensions_p.h b/src/qml/jsruntime/qv4qmlextensions_p.h
index cf9e287efe..b1e8052fc2 100644
--- a/src/qml/jsruntime/qv4qmlextensions_p.h
+++ b/src/qml/jsruntime/qv4qmlextensions_p.h
@@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
struct Object;
+struct ExecutionEngine;
struct Q_QML_EXPORT QmlExtensions
{
@@ -56,7 +57,7 @@ struct Q_QML_EXPORT QmlExtensions
Object *valueTypeWrapperPrototype;
- void markObjects();
+ void markObjects(ExecutionEngine *e);
};
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 1fd47c7c66..f1b0e0bdc4 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -257,6 +257,8 @@ void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const
{
+ Q_UNUSED(revisionMode);
+
QQmlData *ddata = QQmlData::get(m_object, false);
if (!ddata)
return 0;
@@ -277,7 +279,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
return QV4::Encode::undefined();
}
- QV4:Scope scope(ctx);
+ QV4::Scope scope(ctx);
QV4::ScopedString name(scope, n);
if (name->equals(m_destroy) || name->equals(scope.engine->id_toString)) {
@@ -329,16 +331,23 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
if (hasProperty)
*hasProperty = true;
- if (result->isFunction() && !result->isVarProperty()) {
- if (result->isVMEFunction()) {
+ return getProperty(ctx, result);
+}
+
+ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired)
+{
+ QV4::Scope scope(ctx);
+
+ if (property->isFunction() && !property->isVarProperty()) {
+ if (property->isVMEFunction()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
Q_ASSERT(vmemo);
- return vmemo->vmeMethod(result->coreIndex);
- } else if (result->isV4Function()) {
+ return vmemo->vmeMethod(property->coreIndex);
+ } else if (property->isV4Function()) {
QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->engine->qmlContextObject());
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex, qmlcontextobject);
- } else if (result->isSignalHandler()) {
- QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, result->coreIndex));
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex, qmlcontextobject);
+ } else if (property->isSignalHandler()) {
+ QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, property->coreIndex));
QV4::ScopedString connect(scope, ctx->engine->newIdentifier(QStringLiteral("connect")));
QV4::ScopedString disconnect(scope, ctx->engine->newIdentifier(QStringLiteral("disconnect")));
@@ -347,42 +356,44 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
return handler.asReturnedValue();
} else {
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex);
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex);
}
}
QQmlEnginePrivate *ep = ctx->engine->v8Engine->engine() ? QQmlEnginePrivate::get(ctx->engine->v8Engine->engine()) : 0;
- if (result->hasAccessors()) {
+ if (property->hasAccessors()) {
QQmlNotifier *n = 0;
QQmlNotifier **nptr = 0;
- if (ep && ep->propertyCapture && result->accessors->notifier)
+ if (ep && ep->propertyCapture && property->accessors->notifier)
nptr = &n;
- QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *result, nptr));
+ QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *property, nptr));
- if (result->accessors->notifier) {
- if (n)
- ep->captureProperty(n);
- } else {
- ep->captureProperty(m_object, result->coreIndex, result->notifyIndex);
+ if (captureRequired) {
+ if (property->accessors->notifier) {
+ if (n)
+ ep->captureProperty(n);
+ } else {
+ ep->captureProperty(m_object, property->coreIndex, property->notifyIndex);
+ }
}
return rv.asReturnedValue();
}
- if (ep && !result->isConstant())
- ep->captureProperty(m_object, result->coreIndex, result->notifyIndex);
+ if (captureRequired && ep && !property->isConstant())
+ ep->captureProperty(m_object, property->coreIndex, property->notifyIndex);
- if (result->isVarProperty()) {
+ if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
Q_ASSERT(vmemo);
- return vmemo->vmeProperty(result->coreIndex);
- } else if (result->isDirect()) {
- return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *result, 0);
+ return vmemo->vmeProperty(property->coreIndex);
+ } else if (property->isDirect()) {
+ return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *property, 0);
} else {
- return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *result, 0);
+ return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *property, 0);
}
}
@@ -416,8 +427,6 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC
if (QQmlData::wasDeleted(object))
return false;
- QV4::Scope scope(ctx);
-
QQmlPropertyData local;
QQmlPropertyData *result = 0;
{
@@ -433,24 +442,33 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC
return false;
}
- if (!result->isWritable() && !result->isQList()) {
+ setProperty(object, ctx, result, value);
+ return true;
+}
+
+void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const ValueRef value)
+{
+ if (!property->isWritable() && !property->isQList()) {
QString error = QLatin1String("Cannot assign to read-only property \"") +
- name->toQString() + QLatin1Char('\"');
+ property->name(object) + QLatin1Char('\"');
ctx->throwTypeError(error);
+ return;
}
QQmlBinding *newBinding = 0;
+ QV4::Scope scope(ctx);
QV4::ScopedFunctionObject f(scope, value);
if (f) {
if (!f->bindingKeyFlag) {
- if (!result->isVarProperty() && result->propType != qMetaTypeId<QJSValue>()) {
+ if (!property->isVarProperty() && property->propType != qMetaTypeId<QJSValue>()) {
// assigning a JS function to a non var or QJSValue property or is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to ");
- if (!QMetaType::typeName(result->propType))
+ if (!QMetaType::typeName(property->propType))
error += QLatin1String("[unknown property type]");
else
- error += QLatin1String(QMetaType::typeName(result->propType));
+ error += QLatin1String(QMetaType::typeName(property->propType));
ctx->throwError(error);
+ return;
}
} else {
// binding assignment.
@@ -460,23 +478,21 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC
newBinding = new QQmlBinding(value, object, callingQmlContext, frame.source,
qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
- newBinding->setTarget(object, *result, callingQmlContext);
- newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
- QQmlBinding::RequiresThisObject);
+ newBinding->setTarget(object, *property, callingQmlContext);
}
}
QQmlAbstractBinding *oldBinding =
- QQmlPropertyPrivate::setBinding(object, result->coreIndex, -1, newBinding);
+ QQmlPropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding);
if (oldBinding)
oldBinding->destroy();
- if (!newBinding && result->isVarProperty()) {
+ if (!newBinding && property->isVarProperty()) {
// allow assignment of "special" values (null, undefined, function) to var properties
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
- vmemo->setVMEProperty(result->coreIndex, value);
- return true;
+ vmemo->setVMEProperty(property->coreIndex, value);
+ return;
}
#define PROPERTY_STORE(cpptype, value) \
@@ -484,56 +500,57 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC
int status = -1; \
int flags = 0; \
void *argv[] = { &o, 0, &status, &flags }; \
- QMetaObject::metacall(object, QMetaObject::WriteProperty, result->coreIndex, argv);
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex, argv);
- if (value->isNull() && result->isQObject()) {
+ if (value->isNull() && property->isQObject()) {
PROPERTY_STORE(QObject*, 0);
- } else if (value->isUndefined() && result->isResettable()) {
+ } else if (value->isUndefined() && property->isResettable()) {
void *a[] = { 0 };
- QMetaObject::metacall(object, QMetaObject::ResetProperty, result->coreIndex, a);
- } else if (value->isUndefined() && result->propType == qMetaTypeId<QVariant>()) {
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a);
+ } else if (value->isUndefined() && property->propType == qMetaTypeId<QVariant>()) {
PROPERTY_STORE(QVariant, QVariant());
- } else if (value->isUndefined() && result->propType == QMetaType::QJsonValue) {
+ } else if (value->isUndefined() && property->propType == QMetaType::QJsonValue) {
PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
- } else if (!newBinding && result->propType == qMetaTypeId<QJSValue>()) {
+ } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) {
PROPERTY_STORE(QJSValue, new QJSValuePrivate(ctx->engine, value));
} else if (value->isUndefined()) {
QString error = QLatin1String("Cannot assign [undefined] to ");
- if (!QMetaType::typeName(result->propType))
+ if (!QMetaType::typeName(property->propType))
error += QLatin1String("[unknown property type]");
else
- error += QLatin1String(QMetaType::typeName(result->propType));
+ error += QLatin1String(QMetaType::typeName(property->propType));
ctx->throwError(error);
+ return;
} else if (value->asFunctionObject()) {
// this is handled by the binding creation above
- } else if (result->propType == QMetaType::Int && value->isNumber()) {
- PROPERTY_STORE(int, qRound(value->asDouble()));
- } else if (result->propType == QMetaType::QReal && value->isNumber()) {
+ } else if (property->propType == QMetaType::Int && value->isNumber()) {
+ PROPERTY_STORE(int, value->asDouble());
+ } else if (property->propType == QMetaType::QReal && value->isNumber()) {
PROPERTY_STORE(qreal, qreal(value->asDouble()));
- } else if (result->propType == QMetaType::Float && value->isNumber()) {
+ } else if (property->propType == QMetaType::Float && value->isNumber()) {
PROPERTY_STORE(float, float(value->asDouble()));
- } else if (result->propType == QMetaType::Double && value->isNumber()) {
+ } else if (property->propType == QMetaType::Double && value->isNumber()) {
PROPERTY_STORE(double, double(value->asDouble()));
- } else if (result->propType == QMetaType::QString && value->isString()) {
+ } else if (property->propType == QMetaType::QString && value->isString()) {
PROPERTY_STORE(QString, value->toQStringNoThrow());
- } else if (result->isVarProperty()) {
+ } else if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
- vmemo->setVMEProperty(result->coreIndex, value);
+ vmemo->setVMEProperty(property->coreIndex, value);
} else {
QVariant v;
- if (result->isQList())
+ if (property->isQList())
v = ctx->engine->v8Engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
else
- v = ctx->engine->v8Engine->toVariant(value, result->propType);
+ v = ctx->engine->v8Engine->toVariant(value, property->propType);
QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine);
- if (!QQmlPropertyPrivate::write(object, *result, v, callingQmlContext)) {
+ if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
const char *valueType = 0;
if (v.userType() == QVariant::Invalid) valueType = "null";
else valueType = QMetaType::typeName(v.userType());
- const char *targetTypeName = QMetaType::typeName(result->propType);
+ const char *targetTypeName = QMetaType::typeName(property->propType);
if (!targetTypeName)
targetTypeName = "an unregistered type";
@@ -542,10 +559,9 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC
QLatin1String(" to ") +
QLatin1String(targetTypeName);
ctx->throwError(error);
+ return;
}
}
-
- return true;
}
ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
@@ -600,6 +616,45 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
}
}
+ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyIndex, bool captureRequired)
+{
+ if (QQmlData::wasDeleted(m_object))
+ return QV4::Encode::null();
+ QQmlData *ddata = QQmlData::get(m_object, /*create*/false);
+ if (!ddata)
+ return QV4::Encode::undefined();
+
+ QQmlPropertyCache *cache = ddata->propertyCache;
+ Q_ASSERT(cache);
+ QQmlPropertyData *property = cache->property(propertyIndex);
+ Q_ASSERT(property); // We resolved this property earlier, so it better exist!
+ return getProperty(ctx, property, captureRequired);
+}
+
+void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value)
+{
+ if (QQmlData::wasDeleted(m_object))
+ return;
+ QQmlData *ddata = QQmlData::get(m_object, /*create*/false);
+ if (!ddata)
+ return;
+
+ QQmlPropertyCache *cache = ddata->propertyCache;
+ Q_ASSERT(cache);
+ QQmlPropertyData *property = cache->property(propertyIndex);
+ Q_ASSERT(property); // We resolved this property earlier, so it better exist!
+ return setProperty(m_object, ctx, property, value);
+}
+
+bool QObjectWrapper::isEqualTo(Managed *a, Managed *b)
+{
+ QV4::QObjectWrapper *qobjectWrapper = a->as<QV4::QObjectWrapper>();
+ if (QV4::QmlTypeWrapper *qmlTypeWrapper = b->asObject()->as<QV4::QmlTypeWrapper>())
+ return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object();
+
+ return false;
+}
+
ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QQmlData *ddata, QObject *object)
{
QQmlEngine *qmlEngine = engine->v8Engine->engine();
@@ -624,7 +679,7 @@ void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value)
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = m->engine();
- if (QQmlData::wasDeleted(that->m_object))
+ if (v4->hasException || QQmlData::wasDeleted(that->m_object))
return;
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
@@ -660,7 +715,7 @@ Property *QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String
const QMetaObject *mo = that->m_object->metaObject();
const int propertyCount = mo->propertyCount();
- if (it->arrayIndex < propertyCount) {
+ if (it->arrayIndex < static_cast<uint>(propertyCount)) {
name = that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()));
++it->arrayIndex;
if (attributes)
@@ -669,7 +724,7 @@ Property *QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String
return &it->tmpDynamicProperty;
}
const int methodCount = mo->methodCount();
- if (it->arrayIndex < propertyCount + methodCount) {
+ if (it->arrayIndex < static_cast<uint>(propertyCount + methodCount)) {
name = that->engine()->newString(QString::fromUtf8(mo->method(it->arrayIndex - propertyCount).name()));
++it->arrayIndex;
if (attributes)
@@ -724,10 +779,9 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
}
}
- try {
- f->call(callData);
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ f->call(callData);
+ if (scope.hasException()) {
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
if (error.description().isEmpty())
error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(f->name->toQString()));
QQmlEnginePrivate::get(v4->v8Engine->engine())->warning(error);
@@ -790,7 +844,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
} // namespace QV4
-ReturnedValue QObjectWrapper::method_connect(SimpleCallContext *ctx)
+ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
{
if (ctx->callData->argc == 0)
V4THROW_ERROR("Function.prototype.connect: no arguments given");
@@ -836,7 +890,7 @@ ReturnedValue QObjectWrapper::method_connect(SimpleCallContext *ctx)
return Encode::undefined();
}
-ReturnedValue QObjectWrapper::method_disconnect(SimpleCallContext *ctx)
+ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
{
if (ctx->callData->argc == 0)
V4THROW_ERROR("Function.prototype.disconnect: no arguments given");
@@ -887,36 +941,36 @@ ReturnedValue QObjectWrapper::method_disconnect(SimpleCallContext *ctx)
return Encode::undefined();
}
-static void markChildQObjectsRecursively(QObject *parent)
+static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e)
{
const QObjectList &children = parent->children();
for (int i = 0; i < children.count(); ++i) {
QObject *child = children.at(i);
QQmlData *ddata = QQmlData::get(child, /*create*/false);
if (ddata)
- ddata->jsWrapper.markOnce();
- markChildQObjectsRecursively(child);
+ ddata->jsWrapper.markOnce(e);
+ markChildQObjectsRecursively(child, e);
}
}
-void QObjectWrapper::markObjects(Managed *that)
+void QObjectWrapper::markObjects(Managed *that, QV4::ExecutionEngine *e)
{
QObjectWrapper *This = static_cast<QObjectWrapper*>(that);
if (QObject *o = This->m_object.data()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
if (vme)
- vme->mark();
+ vme->mark(e);
// Children usually don't need to be marked, the gc keeps them alive.
// But in the rare case of a "floating" QObject without a parent that
// _gets_ marked (we've been called here!) then we also need to
// propagate the marking down to the children recursively.
if (!o->parent())
- markChildQObjectsRecursively(o);
+ markChildQObjectsRecursively(o, e);
}
- QV4::Object::markObjects(that);
+ QV4::Object::markObjects(that, e);
}
namespace {
@@ -1183,7 +1237,7 @@ static int MatchScore(const QV4::ValueRef actual, int conversionType)
} else if (QV4::Object *obj = actual->asObject()) {
QV8Engine *engine = obj->engine()->v8Engine;
- if (QV4::VariantObject *v = obj->as<QV4::VariantObject>()) {
+ if (obj->as<QV4::VariantObject>()) {
if (conversionType == qMetaTypeId<QVariant>())
return 0;
if (engine->toVariant(actual, -1).userType() == conversionType)
@@ -1281,7 +1335,7 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d
if (returnType == QMetaType::UnknownType) {
QString typeName = QString::fromLatin1(unknownTypeError);
QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName);
- QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->current->throwError(error);
}
if (data.hasArguments()) {
@@ -1295,12 +1349,12 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d
if (!args) {
QString typeName = QString::fromLatin1(unknownTypeError);
QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName);
- QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->current->throwError(error);
}
if (args[0] > callArgs->argc) {
QString error = QLatin1String("Insufficient arguments");
- QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->current->throwError(error);
}
return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs);
@@ -1399,7 +1453,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
candidate = RelatedMethod(object, candidate, dummy);
}
- QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->current->throwError(error);
}
}
@@ -1494,6 +1548,7 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, const QV4::ValueRe
QV4::Scope scope(QV8Engine::getV4(engine));
+ bool queryEngine = false;
if (callType == qMetaTypeId<QJSValue>()) {
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
qjsValuePtr = new (&allocData) QJSValue(new QJSValuePrivate(v4, value));
@@ -1523,6 +1578,8 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, const QV4::ValueRe
qobjectPtr = 0;
if (QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>())
qobjectPtr = qobjectWrapper->object();
+ else if (QV4::QmlTypeWrapper *qmlTypeWrapper = value->as<QV4::QmlTypeWrapper>())
+ queryEngine = qmlTypeWrapper->isSingleton();
type = callType;
} else if (callType == qMetaTypeId<QVariant>()) {
qvariantPtr = new (&allocData) QVariant(engine->toVariant(value, -1));
@@ -1565,6 +1622,10 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, const QV4::ValueRe
} else if (callType == QMetaType::Void) {
*qvariantPtr = QVariant();
} else {
+ queryEngine = true;
+ }
+
+ if (queryEngine) {
qvariantPtr = new (&allocData) QVariant();
type = -1;
@@ -1697,7 +1758,7 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con
if (!m_object)
return Encode::undefined();
if (QQmlData::keepAliveDuringGarbageCollection(m_object))
- ctx->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
+ return ctx->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
int delay = 0;
if (argc > 0)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index eadbacc096..a73c96d098 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -94,7 +94,16 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object
using Object::get;
+ ReturnedValue getProperty(ExecutionContext *ctx, int propertyIndex, bool captureRequired);
+ void setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value);
+
+protected:
+ static bool isEqualTo(Managed *that, Managed *o);
+
private:
+ ReturnedValue getProperty(ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true);
+ static void setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const ValueRef value);
+
static ReturnedValue create(ExecutionEngine *engine, QQmlData *ddata, QObject *object);
QObjectWrapper(ExecutionEngine *engine, QObject *object);
@@ -108,15 +117,15 @@ private:
static void put(Managed *m, const StringRef name, const ValueRef value);
static PropertyAttributes query(const Managed *, StringRef name);
static Property *advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes);
- static void markObjects(Managed *that);
+ 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 ReturnedValue method_connect(SimpleCallContext *ctx);
- static ReturnedValue method_disconnect(SimpleCallContext *ctx);
+ static ReturnedValue method_connect(CallContext *ctx);
+ static ReturnedValue method_disconnect(CallContext *ctx);
};
struct QObjectMethod : public QV4::FunctionObject
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 103605ee7a..5ec63061dc 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -132,8 +132,10 @@ void RegExp::destroy(Managed *that)
static_cast<RegExp*>(that)->~RegExp();
}
-void RegExp::markObjects(Managed *that)
+void RegExp::markObjects(Managed *that, ExecutionEngine *e)
{
+ Q_UNUSED(that);
+ Q_UNUSED(e);
}
ReturnedValue RegExp::get(Managed *, const StringRef, bool *)
@@ -143,24 +145,40 @@ ReturnedValue RegExp::get(Managed *, const StringRef, bool *)
ReturnedValue RegExp::getIndexed(Managed *m, uint index, bool *hasProperty)
{
+ Q_UNUSED(m);
+ Q_UNUSED(index);
+ Q_UNUSED(hasProperty);
+
return Encode::undefined();
}
void RegExp::put(Managed *m, const StringRef name, const ValueRef value)
{
+ Q_UNUSED(m);
+ Q_UNUSED(name);
+ Q_UNUSED(value);
}
void RegExp::putIndexed(Managed *m, uint index, const ValueRef value)
{
+ Q_UNUSED(m);
+ Q_UNUSED(index);
+ Q_UNUSED(value);
}
PropertyAttributes RegExp::query(const Managed *m, StringRef name)
{
+ Q_UNUSED(m);
+ Q_UNUSED(name);
+
return Attr_Invalid;
}
PropertyAttributes RegExp::queryIndexed(const Managed *m, uint index)
{
+ Q_UNUSED(m);
+ Q_UNUSED(index);
+
return Attr_Invalid;
}
@@ -171,10 +189,19 @@ bool RegExp::deleteProperty(Managed *, const StringRef)
bool RegExp::deleteIndexedProperty(Managed *m, uint index)
{
+ Q_UNUSED(m);
+ Q_UNUSED(index);
+
return false;
}
Property *RegExp::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes)
{
+ Q_UNUSED(m);
+ Q_UNUSED(it);
+ Q_UNUSED(name);
+ Q_UNUSED(index);
+ Q_UNUSED(attributes);
+
return 0;
}
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index f674bea042..9041ff2ef4 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -110,7 +110,7 @@ public:
protected:
static void destroy(Managed *that);
- static void markObjects(Managed *that);
+ static void markObjects(Managed *that, QV4::ExecutionEngine *e);
static ReturnedValue get(Managed *, const StringRef, bool *);
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
static void put(Managed *m, const StringRef name, const ValueRef value);
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 6eaa8c387d..a8597229c4 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -175,16 +175,17 @@ void RegExpObject::destroy(Managed *that)
static_cast<RegExpObject *>(that)->~RegExpObject();
}
-void RegExpObject::markObjects(Managed *that)
+void RegExpObject::markObjects(Managed *that, ExecutionEngine *e)
{
RegExpObject *re = static_cast<RegExpObject*>(that);
if (re->value)
- re->value->mark();
- Object::markObjects(that);
+ re->value->mark(e);
+ Object::markObjects(that, e);
}
Property *RegExpObject::lastIndexProperty(ExecutionContext *ctx)
{
+ Q_UNUSED(ctx);
Q_ASSERT(0 == internalClass->find(ctx->engine->newIdentifier(QStringLiteral("lastIndex"))));
return &memberData[0];
}
@@ -200,14 +201,14 @@ QRegExp RegExpObject::toQRegExp() const
QString RegExpObject::toString() const
{
- QString result = QChar('/') + source();
- result += QChar('/');
+ QString result = QLatin1Char('/') + source();
+ result += QLatin1Char('/');
if (global)
- result += QChar('g');
+ result += QLatin1Char('g');
if (value->ignoreCase())
- result += QChar('i');
+ result += QLatin1Char('i');
if (value->multiLine())
- result += QChar('m');
+ result += QLatin1Char('m');
return result;
}
@@ -249,7 +250,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData)
Scoped<RegExpObject> re(scope, r);
if (re) {
if (!f->isUndefined())
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scoped<RegExp> newRe(scope, re->value);
return Encode(ctx->engine->newRegExpObject(newRe, re->global));
@@ -258,29 +259,33 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData)
QString pattern;
if (!r->isUndefined())
pattern = r->toString(ctx)->toQString();
+ if (scope.hasException())
+ return Encode::undefined();
bool global = false;
bool ignoreCase = false;
bool multiLine = false;
if (!f->isUndefined()) {
- f = __qmljs_to_string(f, ctx);
+ f = __qmljs_to_string(ctx, f);
+ if (scope.hasException())
+ return Encode::undefined();
QString str = f->stringValue()->toQString();
for (int i = 0; i < str.length(); ++i) {
- if (str.at(i) == QChar('g') && !global) {
+ if (str.at(i) == QLatin1Char('g') && !global) {
global = true;
- } else if (str.at(i) == QChar('i') && !ignoreCase) {
+ } else if (str.at(i) == QLatin1Char('i') && !ignoreCase) {
ignoreCase = true;
- } else if (str.at(i) == QChar('m') && !multiLine) {
+ } else if (str.at(i) == QLatin1Char('m') && !multiLine) {
multiLine = true;
} else {
- ctx->throwSyntaxError(0);
+ return ctx->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor"));
}
}
}
Scoped<RegExp> regexp(scope, RegExp::create(ctx->engine, pattern, ignoreCase, multiLine));
if (!regexp->isValid())
- ctx->throwSyntaxError(0);
+ return ctx->throwSyntaxError(QStringLiteral("Invalid regular expression"));
return Encode(ctx->engine->newRegExpObject(regexp, global));
}
@@ -309,15 +314,17 @@ void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
defineDefaultProperty(QStringLiteral("compile"), method_compile, 2);
}
-ReturnedValue RegExpPrototype::method_exec(SimpleCallContext *ctx)
+ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
{
Scope scope(ctx);
Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedValue arg(scope, ctx->argument(0));
- arg = __qmljs_to_string(arg, ctx);
+ arg = __qmljs_to_string(ctx, arg);
+ if (scope.hasException())
+ return Encode::undefined();
QString s = arg->stringValue()->toQString();
int offset = r->global ? r->lastIndexProperty(ctx)->value.toInt32() : 0;
@@ -354,29 +361,29 @@ ReturnedValue RegExpPrototype::method_exec(SimpleCallContext *ctx)
return array.asReturnedValue();
}
-ReturnedValue RegExpPrototype::method_test(SimpleCallContext *ctx)
+ReturnedValue RegExpPrototype::method_test(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue r(scope, method_exec(ctx));
return Encode(!r->isNull());
}
-ReturnedValue RegExpPrototype::method_toString(SimpleCallContext *ctx)
+ReturnedValue RegExpPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return ctx->engine->newString(r->toString())->asReturnedValue();
}
-ReturnedValue RegExpPrototype::method_compile(SimpleCallContext *ctx)
+ReturnedValue RegExpPrototype::method_compile(CallContext *ctx)
{
Scope scope(ctx);
Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
ScopedCallData callData(scope, ctx->callData->argc);
memcpy(callData->args, ctx->callData->args, ctx->callData->argc*sizeof(SafeValue));
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 0ef95a36e2..0129f8d396 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct RegExp;
+class RegExp;
struct RegExpObject: Object {
Q_MANAGED
@@ -97,7 +97,7 @@ struct RegExpObject: Object {
protected:
RegExpObject(InternalClass *ic);
static void destroy(Managed *that);
- static void markObjects(Managed *that);
+ static void markObjects(Managed *that, ExecutionEngine *e);
};
@@ -115,10 +115,10 @@ struct RegExpPrototype: RegExpObject
RegExpPrototype(InternalClass *ic): RegExpObject(ic) {}
void init(ExecutionEngine *engine, ObjectRef ctor);
- static ReturnedValue method_exec(SimpleCallContext *ctx);
- static ReturnedValue method_test(SimpleCallContext *ctx);
- static ReturnedValue method_toString(SimpleCallContext *ctx);
- static ReturnedValue method_compile(SimpleCallContext *ctx);
+ static ReturnedValue method_exec(CallContext *ctx);
+ static ReturnedValue method_test(CallContext *ctx);
+ static ReturnedValue method_toString(CallContext *ctx);
+ static ReturnedValue method_compile(CallContext *ctx);
};
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 6f914fa3c2..a5a93e1f84 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -51,6 +51,8 @@
#include "qv4function_p.h"
#include "private/qlocale_tools_p.h"
#include "qv4scopedvalue_p.h"
+#include <private/qqmlcontextwrapper_p.h>
+#include "qv4qobjectwrapper_p.h"
#include <QtCore/qmath.h>
#include <QtCore/qnumeric.h>
@@ -284,6 +286,8 @@ ReturnedValue __qmljs_delete_member(ExecutionContext *ctx, const ValueRef base,
{
Scope scope(ctx);
ScopedObject obj(scope, base->toObject(ctx));
+ if (scope.engine->hasException)
+ return Encode::undefined();
return Encode(obj->deleteProperty(name));
}
@@ -293,29 +297,11 @@ ReturnedValue __qmljs_delete_name(ExecutionContext *ctx, const StringRef name)
return Encode(ctx->deleteProperty(name));
}
-QV4::ReturnedValue __qmljs_add_helper(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
-{
- Scope scope(ctx);
-
- ScopedValue pleft(scope, __qmljs_to_primitive(left, PREFERREDTYPE_HINT));
- ScopedValue pright(scope, __qmljs_to_primitive(right, PREFERREDTYPE_HINT));
- if (pleft->isString() || pright->isString()) {
- if (!pleft->isString())
- pleft = __qmljs_to_string(pleft, ctx);
- if (!pright->isString())
- pright = __qmljs_to_string(pright, ctx);
- return __qmljs_string_concat(ctx, pleft->stringValue(), pright->stringValue())->asReturnedValue();
- }
- double x = __qmljs_to_number(pleft);
- double y = __qmljs_to_number(pright);
- return Encode(x + y);
-}
-
QV4::ReturnedValue __qmljs_instanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
{
Object *o = right->asObject();
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
bool r = o->hasInstance(left);
return Encode(r);
@@ -324,9 +310,11 @@ QV4::ReturnedValue __qmljs_instanceof(ExecutionContext *ctx, const ValueRef left
QV4::ReturnedValue __qmljs_in(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
{
if (!right->isObject())
- ctx->throwTypeError();
+ return ctx->throwTypeError();
Scope scope(ctx);
ScopedString s(scope, left->toString(ctx));
+ if (scope.hasException())
+ return Encode::undefined();
bool r = right->objectValue()->__hasProperty__(s);
return Encode(r);
}
@@ -359,19 +347,6 @@ Returned<String> *__qmljs_string_from_number(ExecutionContext *ctx, double numbe
return ctx->engine->newString(qstr);
}
-Returned<String> *__qmljs_string_concat(ExecutionContext *ctx, String *first, String *second)
-{
- const QString &a = first->toQString();
- const QString &b = second->toQString();
- QString newStr(a.length() + b.length(), Qt::Uninitialized);
- QChar *data = newStr.data();
- memcpy(data, a.constData(), a.length()*sizeof(QChar));
- data += a.length();
- memcpy(data, b.constData(), b.length()*sizeof(QChar));
-
- return ctx->engine->newString(newStr);
-}
-
ReturnedValue __qmljs_object_default_value(Object *object, int typeHint)
{
if (typeHint == PREFERREDTYPE_HINT) {
@@ -382,6 +357,9 @@ ReturnedValue __qmljs_object_default_value(Object *object, int typeHint)
}
ExecutionEngine *engine = object->internalClass->engine;
+ if (engine->hasException)
+ return Encode::undefined();
+
SafeString *meth1 = &engine->id_toString;
SafeString *meth2 = &engine->id_valueOf;
@@ -400,6 +378,9 @@ ReturnedValue __qmljs_object_default_value(Object *object, int typeHint)
return r->asReturnedValue();
}
+ if (engine->hasException)
+ return Encode::undefined();
+
conv = object->get(*meth2);
if (FunctionObject *o = conv->asFunctionObject()) {
ScopedValue r(scope, o->call(callData));
@@ -407,8 +388,7 @@ ReturnedValue __qmljs_object_default_value(Object *object, int typeHint)
return r->asReturnedValue();
}
- ctx->throwTypeError();
- return Encode::undefined();
+ return ctx->throwTypeError();
}
Bool __qmljs_to_boolean(const ValueRef value)
@@ -424,6 +404,7 @@ Returned<Object> *__qmljs_convert_to_object(ExecutionContext *ctx, const ValueRe
case Value::Undefined_Type:
case Value::Null_Type:
ctx->throwTypeError();
+ return 0;
case Value::Boolean_Type:
return ctx->engine->newBooleanObject(value);
case Value::Managed_Type:
@@ -464,10 +445,96 @@ Returned<String> *__qmljs_convert_to_string(ExecutionContext *ctx, const ValueRe
} // switch
}
+// This is slightly different from the method above, as
+// the + operator requires a slightly different conversion
+static Returned<String> *convert_to_string_add(ExecutionContext *ctx, const ValueRef value)
+{
+ switch (value->type()) {
+ case Value::Empty_Type:
+ Q_ASSERT(!"empty Value encountered");
+ case Value::Undefined_Type:
+ return ctx->engine->id_undefined.ret();
+ case Value::Null_Type:
+ return ctx->engine->id_null.ret();
+ case Value::Boolean_Type:
+ if (value->booleanValue())
+ return ctx->engine->id_true.ret();
+ else
+ return ctx->engine->id_false.ret();
+ case Value::Managed_Type:
+ if (value->isString())
+ return value->stringValue()->asReturned<String>();
+ {
+ Scope scope(ctx);
+ ScopedValue prim(scope, __qmljs_to_primitive(value, PREFERREDTYPE_HINT));
+ return __qmljs_convert_to_string(ctx, prim);
+ }
+ case Value::Integer_Type:
+ return __qmljs_string_from_number(ctx, value->int_32);
+ default: // double
+ return __qmljs_string_from_number(ctx, value->doubleValue());
+ } // switch
+}
+
+QV4::ReturnedValue __qmljs_add_helper(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
+{
+ Scope scope(ctx);
+
+ ScopedValue pleft(scope, __qmljs_to_primitive(left, PREFERREDTYPE_HINT));
+ ScopedValue pright(scope, __qmljs_to_primitive(right, PREFERREDTYPE_HINT));
+ if (pleft->isString() || pright->isString()) {
+ if (!pleft->isString())
+ pleft = convert_to_string_add(ctx, pleft);
+ if (!pright->isString())
+ pright = convert_to_string_add(ctx, pright);
+ if (scope.engine->hasException)
+ return Encode::undefined();
+ if (!pleft->stringValue()->length())
+ return pright->asReturnedValue();
+ if (!pright->stringValue()->length())
+ return pleft->asReturnedValue();
+ return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue();
+ }
+ double x = __qmljs_to_number(pleft);
+ double y = __qmljs_to_number(pright);
+ return Encode(x + y);
+}
+
+QV4::ReturnedValue __qmljs_add_string(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right)
+{
+ Q_ASSERT(left->isString() || right->isString());
+
+ if (left->isString() && right->isString()) {
+ if (!left->stringValue()->length())
+ return right->asReturnedValue();
+ if (!right->stringValue()->length())
+ return left->asReturnedValue();
+ return (new (ctx->engine->memoryManager) String(ctx->engine, left->stringValue(), right->stringValue()))->asReturnedValue();
+ }
+
+ Scope scope(ctx);
+ ScopedValue pleft(scope, *left);
+ ScopedValue pright(scope, *right);
+
+ if (!pleft->isString())
+ pleft = convert_to_string_add(ctx, left);
+ if (!pright->isString())
+ pright = convert_to_string_add(ctx, right);
+ if (scope.engine->hasException)
+ return Encode::undefined();
+ if (!pleft->stringValue()->length())
+ return pright->asReturnedValue();
+ if (!pright->stringValue()->length())
+ return pleft->asReturnedValue();
+ return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue();
+}
+
void __qmljs_set_property(ExecutionContext *ctx, const ValueRef object, const StringRef name, const ValueRef value)
{
Scope scope(ctx);
ScopedObject o(scope, object->toObject(ctx));
+ if (!o)
+ return;
o->put(name, value);
}
@@ -490,10 +557,12 @@ ReturnedValue __qmljs_get_element(ExecutionContext *ctx, const ValueRef object,
if (object->isNullOrUndefined()) {
QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index->toQStringNoThrow()).arg(object->toQStringNoThrow());
- ctx->throwTypeError(message);
+ return ctx->throwTypeError(message);
}
o = __qmljs_convert_to_object(ctx, object);
+ if (!o) // type error
+ return Encode::undefined();
}
if (idx < UINT_MAX) {
@@ -509,6 +578,8 @@ ReturnedValue __qmljs_get_element(ExecutionContext *ctx, const ValueRef object,
}
ScopedString name(scope, index->toString(ctx));
+ if (scope.hasException())
+ return Encode::undefined();
return o->get(name);
}
@@ -516,6 +587,8 @@ void __qmljs_set_element(ExecutionContext *ctx, const ValueRef object, const Val
{
Scope scope(ctx);
ScopedObject o(scope, object->toObject(ctx));
+ if (scope.engine->hasException)
+ return;
uint idx = index->asArrayIndex();
if (idx < UINT_MAX) {
@@ -592,10 +665,12 @@ ReturnedValue __qmljs_get_property(ExecutionContext *ctx, const ValueRef object,
if (object->isNullOrUndefined()) {
QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()).arg(object->toQStringNoThrow());
- ctx->throwTypeError(message);
+ return ctx->throwTypeError(message);
}
o = __qmljs_convert_to_object(ctx, object);
+ if (!o) // type error
+ return Encode::undefined();
return o->get(name);
}
@@ -647,8 +722,8 @@ Bool __qmljs_strict_equal(const ValueRef x, const ValueRef y)
if (x->isNumber())
return y->isNumber() && x->asDouble() == y->asDouble();
- if (x->isString())
- return y->isString() && x->stringValue()->isEqualTo(y->stringValue());
+ if (x->isManaged())
+ return y->isManaged() && x->managed()->isEqualTo(y->managed());
return false;
}
@@ -753,7 +828,7 @@ ReturnedValue __qmljs_call_global_lookup(ExecutionContext *context, uint index,
Lookup *l = context->lookups + index;
Scoped<FunctionObject> o(scope, l->globalGetter(l, context));
if (!o)
- context->throwTypeError();
+ return context->throwTypeError();
if (o.getPointer() == context->engine->evalFunction && l->name->equals(context->engine->id_eval))
return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true);
@@ -769,6 +844,9 @@ ReturnedValue __qmljs_call_activation_property(ExecutionContext *context, const
ScopedObject base(scope);
ScopedValue func(scope, context->getPropertyAndBase(name, base));
+ if (context->engine->hasException)
+ return Encode::undefined();
+
if (base)
callData->thisObject = base;
@@ -778,7 +856,7 @@ ReturnedValue __qmljs_call_activation_property(ExecutionContext *context, const
if (base)
objectAsString = ScopedValue(scope, base.asReturnedValue())->toQStringNoThrow();
QString msg = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString()).arg(objectAsString);
- context->throwTypeError(msg);
+ return context->throwTypeError(msg);
}
if (o == context->engine->evalFunction && name->equals(context->engine->id_eval)) {
@@ -796,17 +874,19 @@ ReturnedValue __qmljs_call_property(ExecutionContext *context, const StringRef n
Q_ASSERT(!callData->thisObject.isEmpty());
if (callData->thisObject.isNullOrUndefined()) {
QString message = QStringLiteral("Cannot call method '%1' of %2").arg(name->toQString()).arg(callData->thisObject.toQStringNoThrow());
- context->throwTypeError(message);
+ return context->throwTypeError(message);
}
baseObject = __qmljs_convert_to_object(context, ValueRef(&callData->thisObject));
+ if (!baseObject) // type error
+ return Encode::undefined();
callData->thisObject = baseObject.asReturnedValue();
}
Scoped<FunctionObject> o(scope, baseObject->get(name));
if (!o) {
- QString error = QString("Property '%1' of object %2 is not a function").arg(name->toQString(), callData->thisObject.toQStringNoThrow());
- context->throwTypeError(error);
+ QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString(), callData->thisObject.toQStringNoThrow());
+ return context->throwTypeError(error);
}
return o->call(callData);
@@ -814,37 +894,38 @@ ReturnedValue __qmljs_call_property(ExecutionContext *context, const StringRef n
ReturnedValue __qmljs_call_property_lookup(ExecutionContext *context, uint index, CallDataRef callData)
{
- Scope scope(context);
-
Lookup *l = context->lookups + index;
- Scoped<Object> o(scope, l->getter(l, callData->thisObject));
- if (!o)
- context->throwTypeError();
+ SafeValue v;
+ v = l->getter(l, callData->thisObject);
+ if (!v.isManaged())
+ return context->throwTypeError();
- return o->call(callData);
+ return v.managed()->call(callData);
}
ReturnedValue __qmljs_call_element(ExecutionContext *context, const ValueRef index, CallDataRef callData)
{
Scope scope(context);
ScopedObject baseObject(scope, callData->thisObject.toObject(context));
+ ScopedString s(scope, index->toString(context));
+
+ if (scope.engine->hasException)
+ return Encode::undefined();
callData->thisObject = baseObject;
- ScopedString s(scope, index->toString(context));
ScopedObject o(scope, baseObject->get(s));
if (!o)
- context->throwTypeError();
+ return context->throwTypeError();
return o->call(callData);
}
ReturnedValue __qmljs_call_value(ExecutionContext *context, const ValueRef func, CallDataRef callData)
{
- Object *o = func->asObject();
- if (!o)
- context->throwTypeError();
+ if (!func->isManaged())
+ return context->throwTypeError();
- return o->call(callData);
+ return func->managed()->call(callData);
}
@@ -856,7 +937,7 @@ ReturnedValue __qmljs_construct_global_lookup(ExecutionContext *context, uint in
Lookup *l = context->lookups + index;
Scoped<Object> f(scope, l->globalGetter(l, context));
if (!f)
- context->throwTypeError();
+ return context->throwTypeError();
return f->construct(callData);
}
@@ -866,9 +947,12 @@ ReturnedValue __qmljs_construct_activation_property(ExecutionContext *context, c
{
Scope scope(context);
ScopedValue func(scope, context->getProperty(name));
+ if (context->engine->hasException)
+ return Encode::undefined();
+
Object *f = func->asObject();
if (!f)
- context->throwTypeError();
+ return context->throwTypeError();
return f->construct(callData);
}
@@ -877,26 +961,41 @@ ReturnedValue __qmljs_construct_value(ExecutionContext *context, const ValueRef
{
Object *f = func->asObject();
if (!f)
- context->throwTypeError();
+ return context->throwTypeError();
return f->construct(callData);
}
-ReturnedValue __qmljs_construct_property(ExecutionContext *context, const ValueRef base, const StringRef name, CallDataRef callData)
+ReturnedValue __qmljs_construct_property(ExecutionContext *context, const StringRef name, CallDataRef callData)
{
Scope scope(context);
- ScopedObject thisObject(scope, base->toObject(context));
+ ScopedObject thisObject(scope, callData->thisObject.toObject(context));
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<Object> f(scope, thisObject->get(name));
if (!f)
- context->throwTypeError();
+ return context->throwTypeError();
return f->construct(callData);
}
+ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData)
+{
+ Lookup *l = context->lookups + index;
+ SafeValue v;
+ v = l->getter(l, callData->thisObject);
+ if (!v.isManaged())
+ return context->throwTypeError();
+
+ return v.managed()->construct(callData);
+}
+
+
void __qmljs_throw(ExecutionContext *context, const ValueRef value)
{
- context->throwError(value);
+ if (!value->isEmpty())
+ context->throwError(value);
}
ReturnedValue __qmljs_builtin_typeof(ExecutionContext *ctx, const ValueRef value)
@@ -931,7 +1030,9 @@ ReturnedValue __qmljs_builtin_typeof(ExecutionContext *ctx, const ValueRef value
QV4::ReturnedValue __qmljs_builtin_typeof_name(ExecutionContext *context, const StringRef name)
{
Scope scope(context);
- ScopedValue prop(scope, context->getPropertyNoThrow(name));
+ ScopedValue prop(scope, context->getProperty(name));
+ // typeof doesn't throw. clear any possible exception
+ context->engine->hasException = false;
return __qmljs_builtin_typeof(context, prop);
}
@@ -939,6 +1040,8 @@ QV4::ReturnedValue __qmljs_builtin_typeof_member(ExecutionContext *context, cons
{
Scope scope(context);
ScopedObject obj(scope, base->toObject(context));
+ if (scope.engine->hasException)
+ return Encode::undefined();
ScopedValue prop(scope, obj->get(name));
return __qmljs_builtin_typeof(context, prop);
}
@@ -948,6 +1051,8 @@ QV4::ReturnedValue __qmljs_builtin_typeof_element(ExecutionContext *context, con
Scope scope(context);
ScopedString name(scope, index->toString(context));
ScopedObject obj(scope, base->toObject(context));
+ if (scope.engine->hasException)
+ return Encode::undefined();
ScopedValue prop(scope, obj->get(name));
return __qmljs_builtin_typeof(context, prop);
}
@@ -959,9 +1064,18 @@ ExecutionContext *__qmljs_builtin_push_with_scope(const ValueRef o, ExecutionCon
return ctx->newWithContext(obj);
}
-ExecutionContext *__qmljs_builtin_push_catch_scope(const StringRef exceptionVarName, const ValueRef exceptionValue, ExecutionContext *ctx)
+ReturnedValue __qmljs_builtin_unwind_exception(ExecutionContext *ctx)
+{
+ if (!ctx->engine->hasException)
+ return Primitive::emptyValue().asReturnedValue();
+ return ctx->engine->catchException(ctx, 0);
+}
+
+ExecutionContext *__qmljs_builtin_push_catch_scope(ExecutionContext *ctx, const StringRef exceptionVarName)
{
- return ctx->newCatchContext(exceptionVarName, exceptionValue);
+ Scope scope(ctx);
+ ScopedValue v(scope, ctx->engine->catchException(ctx, 0));
+ return ctx->newCatchContext(exceptionVarName, v);
}
ExecutionContext *__qmljs_builtin_pop_scope(ExecutionContext *ctx)
@@ -1023,7 +1137,7 @@ ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx,
QV4::InternalClass *klass = ctx->compilationUnit->runtimeClasses[classId];
Scoped<Object> o(scope, ctx->engine->newObject(klass));
- for (int i = 0; i < klass->size; ++i) {
+ for (uint i = 0; i < klass->size; ++i) {
if (klass->propertyData[i].isData())
o->memberData[i].value = *args++;
else {
@@ -1068,7 +1182,7 @@ QV4::ReturnedValue __qmljs_decrement(const QV4::ValueRef value)
}
}
-QV4::ReturnedValue __qmljs_to_string(const QV4::ValueRef value, QV4::ExecutionContext *ctx)
+QV4::ReturnedValue __qmljs_to_string(QV4::ExecutionContext *ctx, const QV4::ValueRef value)
{
if (value->isString())
return value.asReturnedValue();
@@ -1079,7 +1193,12 @@ QV4::ReturnedValue __qmljs_to_object(QV4::ExecutionContext *ctx, const QV4::Valu
{
if (value->isObject())
return value.asReturnedValue();
- return Encode(__qmljs_convert_to_object(ctx, value));
+
+ Returned<Object> *o = __qmljs_convert_to_object(ctx, value);
+ if (!o) // type error
+ return Encode::undefined();
+
+ return Encode(o);
}
ReturnedValue __qmljs_value_to_double(const ValueRef value)
@@ -1123,6 +1242,69 @@ ReturnedValue __qmljs_lookup_runtime_regexp(ExecutionContext *ctx, int id)
return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
}
+ReturnedValue __qmljs_get_id_array(NoThrowContext *ctx)
+{
+ return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->idObjectsArray();
+}
+
+ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx)
+{
+ QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
+ return QObjectWrapper::wrap(ctx->engine, context->contextObject);
+}
+
+ReturnedValue __qmljs_get_scope_object(NoThrowContext *ctx)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
+ return QObjectWrapper::wrap(ctx->engine, c->getScopeObject());
+}
+
+ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QObjectWrapper> wrapper(scope, object);
+ if (!wrapper) {
+ ctx->throwTypeError(QStringLiteral("Cannot read property of null"));
+ return Encode::undefined();
+ }
+ return wrapper->getProperty(ctx, propertyIndex, captureRequired);
+}
+
+void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QObjectWrapper> wrapper(scope, object);
+ if (!wrapper) {
+ ctx->throwTypeError(QStringLiteral("Cannot write property of null"));
+ return;
+ }
+ wrapper->setProperty(ctx, propertyIndex, value);
+}
+
+ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx)
+{
+ QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
+ return context->importedScripts.value();
+}
+
+QV4::ReturnedValue __qmljs_get_qml_singleton(QV4::NoThrowContext *ctx, const QV4::StringRef name)
+{
+ return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(name);
+}
+
+void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx)
+{
+ SafeValue *t = &ctx->callData->thisObject;
+ if (t->isObject())
+ return;
+ if (t->isNullOrUndefined()) {
+ *t = ctx->engine->globalObject->asReturnedValue();
+ } else {
+ *t = t->toObject(ctx)->asReturnedValue();
+ }
+}
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 4ede7ae991..da596b180c 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -111,6 +111,12 @@ struct ErrorObject;
struct ExecutionEngine;
struct InternalClass;
+// This is a trick to tell the code generators that functions taking a NoThrowContext won't
+// throw exceptions and therefore don't need a check after the call.
+struct NoThrowContext : public ExecutionContext
+{
+};
+
// context
QV4::ReturnedValue __qmljs_call_activation_property(QV4::ExecutionContext *, const QV4::StringRef name, CallDataRef callData);
QV4::ReturnedValue __qmljs_call_property(QV4::ExecutionContext *context, const QV4::StringRef name, CallDataRef callData);
@@ -119,7 +125,8 @@ QV4::ReturnedValue __qmljs_call_element(ExecutionContext *context, const ValueRe
QV4::ReturnedValue __qmljs_call_value(QV4::ExecutionContext *context, const QV4::ValueRef func, CallDataRef callData);
QV4::ReturnedValue __qmljs_construct_activation_property(QV4::ExecutionContext *, const QV4::StringRef name, CallDataRef callData);
-QV4::ReturnedValue __qmljs_construct_property(QV4::ExecutionContext *context, const QV4::ValueRef base, const QV4::StringRef name, CallDataRef callData);
+QV4::ReturnedValue __qmljs_construct_property(QV4::ExecutionContext *context, const QV4::StringRef name, CallDataRef callData);
+QV4::ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData);
QV4::ReturnedValue __qmljs_construct_value(QV4::ExecutionContext *context, const QV4::ValueRef func, CallDataRef callData);
QV4::ReturnedValue __qmljs_builtin_typeof(QV4::ExecutionContext *ctx, const QV4::ValueRef val);
@@ -127,16 +134,18 @@ QV4::ReturnedValue __qmljs_builtin_typeof_name(QV4::ExecutionContext *context, c
QV4::ReturnedValue __qmljs_builtin_typeof_member(QV4::ExecutionContext* context, const QV4::ValueRef base, const QV4::StringRef name);
QV4::ReturnedValue __qmljs_builtin_typeof_element(QV4::ExecutionContext* context, const QV4::ValueRef base, const QV4::ValueRef index);
-void Q_NORETURN __qmljs_builtin_rethrow(QV4::ExecutionContext *context);
+void __qmljs_builtin_rethrow(QV4::ExecutionContext *context);
QV4::ExecutionContext *__qmljs_builtin_push_with_scope(const QV4::ValueRef o, QV4::ExecutionContext *ctx);
-QV4::ExecutionContext *__qmljs_builtin_push_catch_scope(const QV4::StringRef exceptionVarName, const QV4::ValueRef exceptionValue, QV4::ExecutionContext *ctx);
+QV4::ExecutionContext *__qmljs_builtin_push_catch_scope(QV4::ExecutionContext *ctx, const QV4::StringRef exceptionVarName);
QV4::ExecutionContext *__qmljs_builtin_pop_scope(QV4::ExecutionContext *ctx);
+ReturnedValue __qmljs_builtin_unwind_exception(ExecutionContext *ctx);
void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, const QV4::StringRef name);
void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, QV4::ValueRef val);
QV4::ReturnedValue __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::Value *values, uint length);
void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, const QV4::ValueRef getter, const QV4::ValueRef setter);
QV4::ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId);
QV4::ReturnedValue __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx);
+void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx);
QV4::ReturnedValue __qmljs_value_from_string(QV4::String *string);
QV4::ReturnedValue __qmljs_lookup_runtime_regexp(QV4::ExecutionContext *ctx, int id);
@@ -147,7 +156,6 @@ QV4::ReturnedValue __qmljs_init_closure(QV4::ExecutionContext *ctx, int function
// strings
Q_QML_EXPORT double __qmljs_string_to_number(const QString &s);
Returned<String> *__qmljs_string_from_number(QV4::ExecutionContext *ctx, double number);
-Returned<String> *__qmljs_string_concat(QV4::ExecutionContext *ctx, QV4::String *first, QV4::String *second);
// objects
Q_QML_EXPORT ReturnedValue __qmljs_object_default_value(QV4::Object *object, int typeHint);
@@ -163,6 +171,14 @@ QV4::ReturnedValue __qmljs_construct_global_lookup(QV4::ExecutionContext *contex
QV4::ReturnedValue __qmljs_get_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index);
void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index, const QV4::ValueRef value);
+QV4::ReturnedValue __qmljs_get_id_array(NoThrowContext *ctx);
+QV4::ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx);
+QV4::ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx);
+QV4::ReturnedValue __qmljs_get_scope_object(NoThrowContext *ctx);
+QV4::ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired);
+void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value);
+QV4::ReturnedValue __qmljs_get_qml_singleton(NoThrowContext *ctx, const QV4::StringRef name);
+
// For each
QV4::ReturnedValue __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, const QV4::ValueRef in);
QV4::ReturnedValue __qmljs_foreach_next_property_name(const ValueRef foreach_iterator);
@@ -171,7 +187,7 @@ QV4::ReturnedValue __qmljs_foreach_next_property_name(const ValueRef foreach_ite
QV4::ReturnedValue __qmljs_to_primitive(const ValueRef value, int typeHint);
Q_QML_EXPORT QV4::Bool __qmljs_to_boolean(const QV4::ValueRef value);
double __qmljs_to_number(const QV4::ValueRef value);
-QV4::ReturnedValue __qmljs_to_string(const ValueRef value, QV4::ExecutionContext *ctx);
+QV4::ReturnedValue __qmljs_to_string(QV4::ExecutionContext *ctx, const ValueRef value);
Q_QML_EXPORT Returned<String> *__qmljs_convert_to_string(QV4::ExecutionContext *ctx, const ValueRef value);
void __qmljs_numberToString(QString *result, double num, int radix = 10);
ReturnedValue __qmljs_to_object(QV4::ExecutionContext *ctx, const ValueRef value);
@@ -199,7 +215,7 @@ QV4::ReturnedValue __qmljs_delete_subscript(QV4::ExecutionContext *ctx, const QV
ReturnedValue __qmljs_delete_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::StringRef name);
ReturnedValue __qmljs_delete_name(QV4::ExecutionContext *ctx, const QV4::StringRef name);
-void Q_NORETURN __qmljs_throw(QV4::ExecutionContext*, const QV4::ValueRef value);
+void __qmljs_throw(QV4::ExecutionContext*, const QV4::ValueRef value);
// binary operators
typedef QV4::ReturnedValue (*BinOp)(const QV4::ValueRef left, const QV4::ValueRef right);
@@ -208,6 +224,7 @@ typedef QV4::ReturnedValue (*BinOpContext)(QV4::ExecutionContext *ctx, const QV4
QV4::ReturnedValue __qmljs_instanceof(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right);
QV4::ReturnedValue __qmljs_in(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right);
QV4::ReturnedValue __qmljs_add(ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right);
+QV4::ReturnedValue __qmljs_add_string(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right);
QV4::ReturnedValue __qmljs_bit_or(const QV4::ValueRef left, const QV4::ValueRef right);
QV4::ReturnedValue __qmljs_bit_xor(const QV4::ValueRef left, const QV4::ValueRef right);
QV4::ReturnedValue __qmljs_bit_and(const QV4::ValueRef left, const QV4::ValueRef right);
@@ -261,10 +278,12 @@ inline QV4::ReturnedValue __qmljs_uplus(const QV4::ValueRef value)
{
TRACE1(value);
+ if (value->isNumber())
+ return value.asReturnedValue();
if (value->integerCompatible())
return Encode(value->int_32);
- double n = value->toNumber();
+ double n = value->toNumberImpl();
return Encode(n);
}
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 2e76eb453e..17a19b5201 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -86,14 +86,20 @@ struct Scope {
return ptr;
}
+ bool hasException() const {
+ return engine->hasException;
+ }
+
ExecutionEngine *engine;
SafeValue *mark;
#ifndef QT_NO_DEBUG
mutable int size;
#endif
+
+private:
+ Q_DISABLE_COPY(Scope)
};
-struct ScopedValue;
struct ValueRef;
struct ScopedValue
@@ -735,7 +741,7 @@ inline WeakValue &WeakValue::operator=(Returned<T> *obj)
return operator=(QV4::Value::fromManaged(obj->getPointer()).asReturnedValue());
}
-inline ReturnedValue SimpleCallContext::argument(int i) {
+inline ReturnedValue CallContext::argument(int i) {
return i < callData->argc ? callData->args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index d30132140b..c65f1baf2b 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -51,6 +51,7 @@
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmlengine_p.h>
#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
@@ -62,11 +63,18 @@ using namespace QV4;
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml)
: FunctionObject(scope, scope->engine->id_eval)
, qml(qml)
+ , qmlContext(0)
{
+ Q_ASSERT(scope->inUse);
+
vtbl = &static_vtbl;
function = f;
function->compilationUnit->ref();
needsActivation = function->needsActivation();
+
+ Scope s(scope);
+ ScopedValue protectThis(s, this);
+
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
qmlContext = scope->engine->current->newQmlContext(this, qml);
@@ -76,10 +84,17 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
: FunctionObject(scope, scope->engine->id_eval)
, qml(qml)
+ , qmlContext(0)
{
+ Q_ASSERT(scope->inUse);
+
vtbl = &static_vtbl;
function = 0;
needsActivation = false;
+
+ Scope s(scope);
+ ScopedValue protectThis(s, this);
+
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
qmlContext = scope->engine->current->newQmlContext(this, qml);
@@ -89,6 +104,8 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
{
ExecutionEngine *engine = that->engine();
+ CHECK_STACK_LIMITS(engine);
+
Scope scope(engine);
QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
Q_ASSERT(This->function);
@@ -102,13 +119,14 @@ ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
return result.asReturnedValue();
}
-void QmlBindingWrapper::markObjects(Managed *m)
+void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e)
{
QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m);
if (wrapper->qml)
- wrapper->qml->mark();
- FunctionObject::markObjects(m);
- wrapper->qmlContext->mark();
+ wrapper->qml->mark(e);
+ FunctionObject::markObjects(m, e);
+ if (wrapper->qmlContext)
+ wrapper->qmlContext->mark(e);
}
DEFINE_MANAGED_VTABLE(QmlBindingWrapper);
@@ -173,7 +191,7 @@ void Script::parse()
MemoryManager::GCBlocker gcBlocker(v4->memoryManager);
- V4IR::Module module;
+ V4IR::Module module(v4->debugger != 0);
QQmlJS::Engine ee, *engine = &ee;
Lexer lexer(engine);
@@ -185,6 +203,7 @@ void Script::parse()
foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
if (m.isError()) {
scope->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
+ return;
} else {
qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn
<< ": warning: " << m.message;
@@ -206,10 +225,12 @@ void Script::parse()
inheritedLocals.append(*i ? (*i)->toQString() : QString());
RuntimeCodegen cg(scope, strictMode);
- cg.generateFromProgram(sourceFile, sourceCode, program, &module,
- parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals);
+ cg.generateFromProgram(sourceFile, sourceCode, program, &module, QQmlJS::Codegen::EvalCode, inheritedLocals);
+ if (v4->hasException)
+ return;
+
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator));
+ QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
if (inheritContext)
isel->setUseFastLookups(false);
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
@@ -220,7 +241,7 @@ void Script::parse()
if (!vmFunction) {
// ### FIX file/line number
- Scoped<Object> error(valueScope, v4->newSyntaxErrorObject("Syntax error"));
+ Scoped<Object> error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error")));
v4->current->throwError(error);
}
}
@@ -282,33 +303,12 @@ Function *Script::function()
return vmFunction;
}
-struct PrecompilingCodeGen : public QQmlJS::Codegen
-{
- struct CompileError {};
-
- PrecompilingCodeGen(bool strict)
- : QQmlJS::Codegen(strict)
- {}
-
- virtual void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail)
- {
- QQmlJS::Codegen::throwSyntaxError(loc, detail);
- throw CompileError();
- }
-
- virtual void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail)
- {
- QQmlJS::Codegen::throwReferenceError(loc, detail);
- throw CompileError();
- }
-};
-
-CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, bool parseAsBinding, QList<QQmlError> *reportedErrors)
+CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors)
{
using namespace QQmlJS;
using namespace QQmlJS::AST;
- QQmlJS::V4IR::Module module;
+ QQmlJS::V4IR::Module module(engine->debugger != 0);
QQmlJS::Engine ee;
QQmlJS::Lexer lexer(&ee);
@@ -346,17 +346,17 @@ CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const
return 0;
}
- PrecompilingCodeGen cg(/*strict mode*/false);
- try {
- cg.generateFromProgram(url.toString(), source, program, &module, parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::GlobalCode);
- } catch (const PrecompilingCodeGen::CompileError &) {
+ QQmlJS::Codegen cg(/*strict mode*/false);
+ cg.generateFromProgram(url.toString(), source, program, &module, QQmlJS::Codegen::EvalCode);
+ errors = cg.errors();
+ if (!errors.isEmpty()) {
if (reportedErrors)
*reportedErrors << cg.errors();
return 0;
}
Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(engine->executableAllocator, &module, &jsGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, &module, &jsGenerator));
isel->setUseFastLookups(false);
return isel->compile();
}
@@ -378,11 +378,13 @@ QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &scr
QV4::Script qmlScript(engine, scopeObject, script, QString());
QV4::ExecutionContext *ctx = engine->current;
- try {
- qmlScript.parse();
- return qmlScript.run();
- } catch (...) {
+ qmlScript.parse();
+ QV4::ScopedValue result(scope);
+ if (!scope.engine->hasException)
+ result = qmlScript.run();
+ if (scope.engine->hasException) {
ctx->catchException();
+ return Encode::undefined();
}
- return Encode::undefined();
+ return result.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 52ad4dd78c..8e11eddb8f 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -61,7 +61,7 @@ struct QmlBindingWrapper : FunctionObject {
QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml);
static ReturnedValue call(Managed *that, CallData *);
- static void markObjects(Managed *m);
+ static void markObjects(Managed *m, ExecutionEngine *e);
CallContext *context() const { return qmlContext; }
@@ -100,9 +100,7 @@ struct Q_QML_EXPORT Script {
Function *function();
- static CompiledData::CompilationUnit *precompile(ExecutionEngine *engine, const QUrl &url, const QString &source,
- bool parseAsBinding,
- QList<QQmlError> *reportedErrors = 0);
+ static CompiledData::CompilationUnit *precompile(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/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 320646805b..26e4dcb8a2 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -178,6 +178,7 @@ public:
flags &= ~SimpleArray;
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
+ Q_UNUSED(protectThis);
init();
}
@@ -192,6 +193,7 @@ public:
flags &= ~SimpleArray;
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
+ Q_UNUSED(protectThis);
loadReference();
init();
}
@@ -231,6 +233,9 @@ public:
void containerPutIndexed(uint index, const QV4::ValueRef value)
{
+ if (internalClass->engine->hasException)
+ return;
+
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
generateWarning(engine()->current, QLatin1String("Index out of range during indexed set"));
@@ -294,7 +299,7 @@ public:
loadReference();
}
- if (it->arrayIndex < m_container.count()) {
+ if (it->arrayIndex < static_cast<uint>(m_container.count())) {
if (attrs)
*attrs = QV4::Attr_Data;
*index = it->arrayIndex;
@@ -374,7 +379,7 @@ public:
QV4::ValueRef m_compareFn;
};
- void sort(QV4::SimpleCallContext *ctx)
+ void sort(QV4::CallContext *ctx)
{
if (m_isReference) {
if (!m_object)
@@ -395,12 +400,12 @@ public:
storeReference();
}
- static QV4::ReturnedValue method_get_length(QV4::SimpleCallContext *ctx)
+ static QV4::ReturnedValue method_get_length(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (This->m_isReference) {
if (!This->m_object)
@@ -410,12 +415,12 @@ public:
return QV4::Encode(This->m_container.count());
}
- static QV4::ReturnedValue method_set_length(QV4::SimpleCallContext* ctx)
+ static QV4::ReturnedValue method_set_length(QV4::CallContext* ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
quint32 newLength = ctx->callData->args[0].toUInt32();
/* Qt containers have int (rather than uint) allowable indexes. */
@@ -548,12 +553,12 @@ void SequencePrototype::init()
defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0);
}
-QV4::ReturnedValue SequencePrototype::method_sort(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue SequencePrototype::method_sort(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::ScopedObject o(scope, ctx->callData->thisObject);
if (!o || !o->isListType())
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (ctx->callData->argc >= 2)
return o.asReturnedValue();
@@ -566,6 +571,7 @@ QV4::ReturnedValue SequencePrototype::method_sort(QV4::SimpleCallContext *ctx)
FOREACH_QML_SEQUENCE_TYPE(CALL_SORT)
#undef CALL_SORT
+ {}
return o.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 3bbb86f231..54a96863df 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -69,12 +69,12 @@ struct SequencePrototype : public QV4::Object
void init();
- static ReturnedValue method_valueOf(QV4::SimpleCallContext *ctx)
+ static ReturnedValue method_valueOf(QV4::CallContext *ctx)
{
return ctx->callData->thisObject.toString(ctx)->asReturnedValue();
}
- static ReturnedValue method_sort(QV4::SimpleCallContext *ctx);
+ static ReturnedValue method_sort(QV4::CallContext *ctx);
static bool isSequenceType(int sequenceTypeId);
static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index 53d7e4701a..06a2603280 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -280,12 +280,10 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en
serialize(data, s, engine);
QV4::ExecutionContext *ctx = v4->current;
- try {
- str = s;
- val = o->get(str);
- } catch (...) {
+ str = s;
+ val = o->get(str);
+ if (scope.hasException())
ctx->catchException();
- }
serialize(data, val, engine);
}
@@ -373,7 +371,7 @@ ReturnedValue Serialize::deserialize(const char *&data, QV8Engine *engine)
QQmlListModelWorkerAgent::VariantRef ref(agent);
QVariant var = qVariantFromValue(ref);
QV4::ScopedValue v(scope, engine->fromVariant((var)));
- QV4::ScopedString s(scope, v4->newString("__qml:hidden:ref"));
+ QV4::ScopedString s(scope, v4->newString(QStringLiteral("__qml:hidden:ref")));
rv->asObject()->defineReadonlyProperty(s, v);
agent->release();
diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp
index ec6b0f5ad1..3ee89d5b53 100644
--- a/src/qml/jsruntime/qv4sparsearray.cpp
+++ b/src/qml/jsruntime/qv4sparsearray.cpp
@@ -57,9 +57,9 @@ bool ArrayElementLessThan::operator()(const Property &p1, const Property &p2) co
{
Scope scope(m_context);
- if (p1.value.isUndefined())
+ if (p1.value.isUndefined() || p1.value.isEmpty())
return false;
- if (p2.value.isUndefined())
+ if (p2.value.isUndefined() || p2.value.isEmpty())
return true;
ScopedObject o(scope, m_comparefn);
if (o) {
@@ -71,7 +71,7 @@ bool ArrayElementLessThan::operator()(const Property &p1, const Property &p2) co
callData->args[1] = p2.value;
result = __qmljs_call_value(m_context, m_comparefn, callData);
- return result->toNumber() <= 0;
+ return result->toNumber() < 0;
}
ScopedString p1s(scope, p1.value.toString(m_context));
ScopedString p2s(scope, p2.value.toString(m_context));
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index fd366d26ac..0e43d03987 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -105,7 +105,7 @@ const ManagedVTable String::static_vtbl =
{
call,
construct,
- 0 /*markObjects*/,
+ markObjects,
destroy,
0 /*collectDeletables*/,
hasInstance,
@@ -129,6 +129,15 @@ void String::destroy(Managed *that)
static_cast<String*>(that)->~String();
}
+void String::markObjects(Managed *that, ExecutionEngine *e)
+{
+ String *s = static_cast<String *>(that);
+ if (s->largestSubLength) {
+ s->left->mark(e);
+ s->right->mark(e);
+ }
+}
+
ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
{
ExecutionEngine *v4 = m->engine();
@@ -138,7 +147,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
if (name->equals(v4->id_length)) {
if (hasProperty)
*hasProperty = true;
- return Primitive::fromInt32(that->_text.length()).asReturnedValue();
+ return Primitive::fromInt32(that->_text->size).asReturnedValue();
}
PropertyAttributes attrs;
Property *pd = v4->stringClass->prototype->__getPropertyDescriptor__(name, &attrs);
@@ -158,7 +167,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
Scope scope(engine);
ScopedString that(scope, static_cast<String *>(m));
- if (index < that->_text.length()) {
+ if (index < static_cast<uint>(that->_text->size)) {
if (hasProperty)
*hasProperty = true;
return Encode(engine->newString(that->toQString().mid(index, 1)));
@@ -178,6 +187,8 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
void String::put(Managed *m, const StringRef name, const ValueRef value)
{
Scope scope(m->engine());
+ if (scope.hasException())
+ return;
ScopedString that(scope, static_cast<String *>(m));
Scoped<Object> o(scope, that->engine()->newStringObject(that));
o->put(name, value);
@@ -186,6 +197,9 @@ void String::put(Managed *m, const StringRef name, const ValueRef value)
void String::putIndexed(Managed *m, uint index, const ValueRef value)
{
Scope scope(m->engine());
+ if (scope.hasException())
+ return;
+
ScopedString that(scope, static_cast<String *>(m));
Scoped<Object> o(scope, that->engine()->newStringObject(that));
o->putIndexed(index, value);
@@ -202,7 +216,7 @@ PropertyAttributes String::query(const Managed *m, StringRef name)
PropertyAttributes String::queryIndexed(const Managed *m, uint index)
{
const String *that = static_cast<const String *>(m);
- return (index < that->_text.length()) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid;
+ return (index < static_cast<uint>(that->_text->size)) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid;
}
bool String::deleteProperty(Managed *, const StringRef)
@@ -210,7 +224,7 @@ bool String::deleteProperty(Managed *, const StringRef)
return false;
}
-bool String::deleteIndexedProperty(Managed *m, uint index)
+bool String::deleteIndexedProperty(Managed *, uint)
{
return false;
}
@@ -220,7 +234,10 @@ bool String::isEqualTo(Managed *t, Managed *o)
if (t == o)
return true;
- Q_ASSERT(t->type == Type_String && o->type == Type_String);
+ if (o->type != Type_String)
+ return false;
+
+ Q_ASSERT(t->type == Type_String);
String *that = static_cast<String *>(t);
String *other = static_cast<String *>(o);
if (that->hashValue() != other->hashValue())
@@ -235,13 +252,37 @@ bool String::isEqualTo(Managed *t, Managed *o)
String::String(ExecutionEngine *engine, const QString &text)
- : Managed(engine ? engine->emptyClass : 0), _text(text), identifier(0), stringHash(UINT_MAX)
+ : Managed(engine ? engine->emptyClass : 0), _text(const_cast<QString &>(text).data_ptr())
+ , identifier(0), stringHash(UINT_MAX)
+ , largestSubLength(0)
{
+ _text->ref.ref();
+ len = _text->size;
vtbl = &static_vtbl;
type = Type_String;
subtype = StringType_Unknown;
}
+String::String(ExecutionEngine *engine, String *l, String *r)
+ : Managed(engine ? engine->emptyClass : 0)
+ , left(l), right(r)
+ , stringHash(UINT_MAX), largestSubLength(qMax(l->largestSubLength, r->largestSubLength))
+ , len(l->len + r->len)
+{
+ vtbl = &static_vtbl;
+ type = Type_String;
+ subtype = StringType_Unknown;
+
+ if (!l->largestSubLength && l->len > largestSubLength)
+ largestSubLength = l->len;
+ if (!r->largestSubLength && r->len > largestSubLength)
+ largestSubLength = r->len;
+
+ // make sure we don't get excessive depth in our strings
+ if (len > 256 && len >= 2*largestSubLength)
+ simplifyString();
+}
+
uint String::toUInt(bool *ok) const
{
*ok = true;
@@ -276,13 +317,46 @@ bool String::equals(const StringRef other) const
void String::makeIdentifierImpl() const
{
+ if (largestSubLength)
+ simplifyString();
+ Q_ASSERT(!largestSubLength);
engine()->identifierTable->identifier(this);
}
+void String::simplifyString() const
+{
+ Q_ASSERT(largestSubLength);
+
+ int l = length();
+ QString result(l, Qt::Uninitialized);
+ QChar *ch = const_cast<QChar *>(result.constData());
+ recursiveAppend(ch);
+ _text = result.data_ptr();
+ _text->ref.ref();
+ identifier = 0;
+ largestSubLength = 0;
+}
+
+QChar *String::recursiveAppend(QChar *ch) const
+{
+ if (largestSubLength) {
+ ch = left->recursiveAppend(ch);
+ ch = right->recursiveAppend(ch);
+ } else {
+ memcpy(ch, _text->data(), _text->size*sizeof(QChar));
+ ch += _text->size;
+ }
+ return ch;
+}
+
+
void String::createHashValue() const
{
- const QChar *ch = _text.constData();
- const QChar *end = ch + _text.length();
+ if (largestSubLength)
+ simplifyString();
+ Q_ASSERT(!largestSubLength);
+ const QChar *ch = reinterpret_cast<const QChar *>(_text->data());
+ const QChar *end = ch + _text->size;
// array indices get their number as hash value
bool ok;
@@ -333,7 +407,7 @@ uint String::createHashValue(const char *ch, int length)
uint h = 0xffffffff;
while (ch < end) {
- if (*ch >= 0x80)
+ if ((uchar)(*ch) >= 0x80)
return UINT_MAX;
h = 31 * h + *ch;
++ch;
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 1e2aba32a9..bb6f1d2279 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -60,10 +60,17 @@ struct Q_QML_EXPORT String : public Managed {
StringType_ArrayIndex
};
- String() : Managed(0), identifier(0), stringHash(UINT_MAX)
+ String()
+ : Managed(0), _text(QStringData::sharedNull()), identifier(0)
+ , stringHash(UINT_MAX), largestSubLength(0), len(0)
{ vtbl = &static_vtbl; type = Type_String; subtype = StringType_Unknown; }
String(ExecutionEngine *engine, const QString &text);
- ~String() { _data = 0; }
+ String(ExecutionEngine *engine, String *l, String *n);
+ ~String() {
+ if (!largestSubLength && !_text->ref.deref())
+ QStringData::deallocate(_text);
+ _data = 0;
+ }
bool equals(const StringRef other) const;
inline bool isEqualTo(const String *other) const {
@@ -71,6 +78,7 @@ struct Q_QML_EXPORT String : public Managed {
return true;
if (hashValue() != other->hashValue())
return false;
+ Q_ASSERT(!largestSubLength);
if (identifier && identifier == other->identifier)
return true;
if (subtype >= StringType_UInt && subtype == other->subtype)
@@ -82,20 +90,27 @@ struct Q_QML_EXPORT String : public Managed {
return toQString() < other->toQString();
}
- inline bool isEmpty() const { return _text.isEmpty(); }
- inline const QString &toQString() const {
- return _text;
+ inline QString toQString() const {
+ if (largestSubLength)
+ simplifyString();
+ QStringDataPtr ptr = { _text };
+ _text->ref.ref();
+ return QString(ptr);
}
+ void simplifyString() const;
+
inline unsigned hashValue() const {
if (subtype == StringType_Unknown)
createHashValue();
+ Q_ASSERT(!largestSubLength);
return stringHash;
}
uint asArrayIndex() const {
if (subtype == StringType_Unknown)
createHashValue();
+ Q_ASSERT(!largestSubLength);
if (subtype == StringType_ArrayIndex)
return stringHash;
return UINT_MAX;
@@ -115,19 +130,32 @@ struct Q_QML_EXPORT String : public Managed {
static uint createHashValue(const char *ch, int length);
bool startsWithUpper() const {
- return _text.length() && _text.at(0).isUpper();
+ const String *l = this;
+ while (l->largestSubLength)
+ l = l->left;
+ return l->_text->size && QChar::isUpper(l->_text->data()[0]);
}
int length() const {
- return _text.length();
+ Q_ASSERT((largestSubLength && (len == left->len + right->len)) || len == (uint)_text->size);
+ return len;
}
- QString _text;
- mutable Identifier *identifier;
+ union {
+ mutable QStringData *_text;
+ mutable String *left;
+ };
+ union {
+ mutable Identifier *identifier;
+ mutable String *right;
+ };
mutable uint stringHash;
+ mutable uint largestSubLength;
+ uint len;
protected:
static void destroy(Managed *);
+ static void markObjects(Managed *that, ExecutionEngine *e);
static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
static void put(Managed *m, const StringRef name, const ValueRef value);
@@ -137,6 +165,9 @@ protected:
static bool deleteProperty(Managed *, const StringRef);
static bool deleteIndexedProperty(Managed *m, uint index);
static bool isEqualTo(Managed *that, Managed *o);
+
+private:
+ QChar *recursiveAppend(QChar *ch) const;
};
template<>
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 25e1ea55c2..bff8f1f9cd 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -86,7 +86,7 @@ StringObject::StringObject(InternalClass *ic)
Scope scope(engine());
ScopedObject protectThis(scope, this);
- value = ic->engine->newString("")->asReturnedValue();
+ value = ic->engine->newString(QStringLiteral(""))->asReturnedValue();
tmpProperty.value = Primitive::undefinedValue();
@@ -124,10 +124,12 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index)
ExecutionEngine *v4 = m->engine();
Scope scope(v4);
Scoped<StringObject> o(scope, m->asStringObject());
- if (!o)
+ if (!o) {
v4->current->throwTypeError();
+ return false;
+ }
- if (index < o->value.stringValue()->toQString().length()) {
+ if (index < static_cast<uint>(o->value.stringValue()->toQString().length())) {
if (v4->current->strictMode)
v4->current->throwTypeError();
return false;
@@ -157,12 +159,12 @@ Property *StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRe
return Object::advanceIterator(m, it, name, index, attrs);
}
-void StringObject::markObjects(Managed *that)
+void StringObject::markObjects(Managed *that, ExecutionEngine *e)
{
StringObject *o = static_cast<StringObject *>(that);
- o->value.stringValue()->mark();
- o->tmpProperty.value.mark();
- Object::markObjects(that);
+ o->value.stringValue()->mark(e);
+ o->tmpProperty.value.mark(e);
+ Object::markObjects(that, e);
}
DEFINE_MANAGED_VTABLE(StringCtor);
@@ -237,25 +239,29 @@ static QString getThisString(ExecutionContext *ctx)
return t->stringValue()->toQString();
if (StringObject *thisString = t->asStringObject())
return thisString->value.stringValue()->toQString();
- if (t->isUndefined() || t->isNull())
+ if (t->isUndefined() || t->isNull()) {
ctx->throwTypeError();
+ return QString();
+ }
return t->toQString();
}
-ReturnedValue StringPrototype::method_toString(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_toString(CallContext *context)
{
if (context->callData->thisObject.isString())
return context->callData->thisObject.asReturnedValue();
StringObject *o = context->callData->thisObject.asStringObject();
if (!o)
- context->throwTypeError();
+ return context->throwTypeError();
return o->value.asReturnedValue();
}
-ReturnedValue StringPrototype::method_charAt(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_charAt(CallContext *context)
{
const QString str = getThisString(context);
+ if (context->engine->hasException)
+ return Encode::undefined();
int pos = 0;
if (context->callData->argc > 0)
@@ -268,9 +274,11 @@ ReturnedValue StringPrototype::method_charAt(SimpleCallContext *context)
return context->engine->newString(result)->asReturnedValue();
}
-ReturnedValue StringPrototype::method_charCodeAt(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_charCodeAt(CallContext *context)
{
const QString str = getThisString(context);
+ if (context->engine->hasException)
+ return Encode::undefined();
int pos = 0;
if (context->callData->argc > 0)
@@ -283,25 +291,31 @@ ReturnedValue StringPrototype::method_charCodeAt(SimpleCallContext *context)
return Encode(qSNaN());
}
-ReturnedValue StringPrototype::method_concat(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_concat(CallContext *context)
{
Scope scope(context);
QString value = getThisString(context);
+ if (scope.engine->hasException)
+ return Encode::undefined();
ScopedValue v(scope);
for (int i = 0; i < context->callData->argc; ++i) {
- v = __qmljs_to_string(ValueRef(&context->callData->args[i]), context);
- assert(v->isString());
+ v = __qmljs_to_string(context, ValueRef(&context->callData->args[i]));
+ if (scope.hasException())
+ return Encode::undefined();
+ Q_ASSERT(v->isString());
value += v->stringValue()->toQString();
}
return context->engine->newString(value)->asReturnedValue();
}
-ReturnedValue StringPrototype::method_indexOf(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_indexOf(CallContext *context)
{
QString value = getThisString(context);
+ if (context->engine->hasException)
+ return Encode::undefined();
QString searchString;
if (context->callData->argc)
@@ -318,11 +332,13 @@ ReturnedValue StringPrototype::method_indexOf(SimpleCallContext *context)
return Encode(index);
}
-ReturnedValue StringPrototype::method_lastIndexOf(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context)
{
Scope scope(context);
const QString value = getThisString(context);
+ if (scope.engine->hasException)
+ return Encode::undefined();
QString searchString;
if (context->callData->argc)
@@ -344,19 +360,22 @@ ReturnedValue StringPrototype::method_lastIndexOf(SimpleCallContext *context)
return Encode(index);
}
-ReturnedValue StringPrototype::method_localeCompare(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_localeCompare(CallContext *context)
{
Scope scope(context);
const QString value = getThisString(context);
+ if (scope.engine->hasException)
+ return Encode::undefined();
+
ScopedValue v(scope, context->callData->argument(0));
const QString that = v->toQString();
return Encode(QString::localeAwareCompare(value, that));
}
-ReturnedValue StringPrototype::method_match(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_match(CallContext *context)
{
if (context->callData->thisObject.isUndefined() || context->callData->thisObject.isNull())
- context->throwTypeError();
+ return context->throwTypeError();
Scope scope(context);
ScopedString s(scope, context->callData->thisObject.toString(context));
@@ -371,7 +390,7 @@ ReturnedValue StringPrototype::method_match(SimpleCallContext *context)
if (!rx)
// ### CHECK
- context->throwTypeError();
+ return context->throwTypeError();
bool global = rx->global;
@@ -427,7 +446,7 @@ static void appendReplacementString(QString *result, const QString &input, const
uint substStart = JSC::Yarr::offsetNoMatch;
uint substEnd = JSC::Yarr::offsetNoMatch;
if (ch == '$') {
- *result += ch;
+ *result += QLatin1Char(ch);
continue;
} else if (ch == '&') {
substStart = matchOffsets[0];
@@ -440,7 +459,7 @@ 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 < captureCount) {
+ if (capture > 0 && capture < static_cast<uint>(captureCount)) {
substStart = matchOffsets[capture * 2];
substEnd = matchOffsets[capture * 2 + 1];
}
@@ -463,7 +482,7 @@ static void appendReplacementString(QString *result, const QString &input, const
}
}
-ReturnedValue StringPrototype::method_replace(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_replace(CallContext *ctx)
{
Scope scope(ctx);
QString string;
@@ -540,7 +559,7 @@ ReturnedValue StringPrototype::method_replace(SimpleCallContext *ctx)
callData->args[k] = entry;
}
uint matchStart = matchOffsets[i * numCaptures * 2];
- Q_ASSERT(matchStart >= lastEnd);
+ Q_ASSERT(matchStart >= static_cast<uint>(lastEnd));
uint matchEnd = matchOffsets[i * numCaptures * 2 + 1];
callData->args[numCaptures] = Primitive::fromUInt32(matchStart);
callData->args[numCaptures + 1] = ctx->engine->newString(string);
@@ -576,17 +595,20 @@ ReturnedValue StringPrototype::method_replace(SimpleCallContext *ctx)
return ctx->engine->newString(result)->asReturnedValue();
}
-ReturnedValue StringPrototype::method_search(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_search(CallContext *ctx)
{
Scope scope(ctx);
QString string = getThisString(ctx);
-
ScopedValue regExpValue(scope, ctx->argument(0));
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<RegExpObject> regExp(scope, regExpValue->as<RegExpObject>());
if (!regExp) {
ScopedCallData callData(scope, 1);
callData->args[0] = regExpValue;
regExpValue = ctx->engine->regExpCtor.asFunctionObject()->construct(callData);
+ if (scope.engine->hasException)
+ return Encode::undefined();
regExp = regExpValue->as<RegExpObject>();
Q_ASSERT(regExp);
}
@@ -597,9 +619,12 @@ ReturnedValue StringPrototype::method_search(SimpleCallContext *ctx)
return Encode(result);
}
-ReturnedValue StringPrototype::method_slice(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_slice(CallContext *ctx)
{
const QString text = getThisString(ctx);
+ if (ctx->engine->hasException)
+ return Encode::undefined();
+
const double length = text.length();
double start = ctx->callData->argc ? ctx->callData->args[0].toInteger() : 0;
@@ -623,10 +648,12 @@ ReturnedValue StringPrototype::method_slice(SimpleCallContext *ctx)
return ctx->engine->newString(text.mid(intStart, count))->asReturnedValue();
}
-ReturnedValue StringPrototype::method_split(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_split(CallContext *ctx)
{
Scope scope(ctx);
QString text = getThisString(ctx);
+ if (scope.engine->hasException)
+ return Encode::undefined();
ScopedValue separatorValue(scope, ctx->argument(0));
ScopedValue limitValue(scope, ctx->argument(1));
@@ -702,9 +729,11 @@ ReturnedValue StringPrototype::method_split(SimpleCallContext *ctx)
return array.asReturnedValue();
}
-ReturnedValue StringPrototype::method_substr(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_substr(CallContext *context)
{
const QString value = getThisString(context);
+ if (context->engine->hasException)
+ return Encode::undefined();
double start = 0;
if (context->callData->argc > 0)
@@ -725,9 +754,11 @@ ReturnedValue StringPrototype::method_substr(SimpleCallContext *context)
return context->engine->newString(value.mid(x, y))->asReturnedValue();
}
-ReturnedValue StringPrototype::method_substring(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_substring(CallContext *context)
{
QString value = getThisString(context);
+ if (context->engine->hasException)
+ return Encode::undefined();
int length = value.length();
double start = 0;
@@ -764,29 +795,33 @@ ReturnedValue StringPrototype::method_substring(SimpleCallContext *context)
return context->engine->newString(value.mid(x, y))->asReturnedValue();
}
-ReturnedValue StringPrototype::method_toLowerCase(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_toLowerCase(CallContext *ctx)
{
QString value = getThisString(ctx);
+ if (ctx->engine->hasException)
+ return Encode::undefined();
return ctx->engine->newString(value.toLower())->asReturnedValue();
}
-ReturnedValue StringPrototype::method_toLocaleLowerCase(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_toLocaleLowerCase(CallContext *ctx)
{
return method_toLowerCase(ctx);
}
-ReturnedValue StringPrototype::method_toUpperCase(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_toUpperCase(CallContext *ctx)
{
QString value = getThisString(ctx);
+ if (ctx->engine->hasException)
+ return Encode::undefined();
return ctx->engine->newString(value.toUpper())->asReturnedValue();
}
-ReturnedValue StringPrototype::method_toLocaleUpperCase(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_toLocaleUpperCase(CallContext *ctx)
{
return method_toUpperCase(ctx);
}
-ReturnedValue StringPrototype::method_fromCharCode(SimpleCallContext *context)
+ReturnedValue StringPrototype::method_fromCharCode(CallContext *context)
{
QString str(context->callData->argc, Qt::Uninitialized);
QChar *ch = str.data();
@@ -797,9 +832,11 @@ ReturnedValue StringPrototype::method_fromCharCode(SimpleCallContext *context)
return context->engine->newString(str)->asReturnedValue();
}
-ReturnedValue StringPrototype::method_trim(SimpleCallContext *ctx)
+ReturnedValue StringPrototype::method_trim(CallContext *ctx)
{
QString s = getThisString(ctx);
+ if (ctx->engine->hasException)
+ return Encode::undefined();
const QChar *chars = s.constData();
int start, end;
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index e6777380a4..e8e46b85e7 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -63,7 +63,7 @@ struct StringObject: Object {
protected:
StringObject(InternalClass *ic);
static Property *advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attrs);
- static void markObjects(Managed *that);
+ static void markObjects(Managed *that, ExecutionEngine *e);
};
struct StringCtor: FunctionObject
@@ -80,26 +80,26 @@ struct StringPrototype: StringObject
StringPrototype(InternalClass *ic): StringObject(ic) {}
void init(ExecutionEngine *engine, ObjectRef ctor);
- static ReturnedValue method_toString(SimpleCallContext *context);
- static ReturnedValue method_charAt(SimpleCallContext *context);
- static ReturnedValue method_charCodeAt(SimpleCallContext *context);
- static ReturnedValue method_concat(SimpleCallContext *context);
- static ReturnedValue method_indexOf(SimpleCallContext *context);
- static ReturnedValue method_lastIndexOf(SimpleCallContext *context);
- static ReturnedValue method_localeCompare(SimpleCallContext *context);
- static ReturnedValue method_match(SimpleCallContext *context);
- static ReturnedValue method_replace(SimpleCallContext *ctx);
- static ReturnedValue method_search(SimpleCallContext *ctx);
- static ReturnedValue method_slice(SimpleCallContext *ctx);
- static ReturnedValue method_split(SimpleCallContext *ctx);
- static ReturnedValue method_substr(SimpleCallContext *context);
- static ReturnedValue method_substring(SimpleCallContext *context);
- static ReturnedValue method_toLowerCase(SimpleCallContext *ctx);
- static ReturnedValue method_toLocaleLowerCase(SimpleCallContext *ctx);
- static ReturnedValue method_toUpperCase(SimpleCallContext *ctx);
- static ReturnedValue method_toLocaleUpperCase(SimpleCallContext *ctx);
- static ReturnedValue method_fromCharCode(SimpleCallContext *context);
- static ReturnedValue method_trim(SimpleCallContext *ctx);
+ static ReturnedValue method_toString(CallContext *context);
+ static ReturnedValue method_charAt(CallContext *context);
+ static ReturnedValue method_charCodeAt(CallContext *context);
+ static ReturnedValue method_concat(CallContext *context);
+ static ReturnedValue method_indexOf(CallContext *context);
+ static ReturnedValue method_lastIndexOf(CallContext *context);
+ static ReturnedValue method_localeCompare(CallContext *context);
+ static ReturnedValue method_match(CallContext *context);
+ static ReturnedValue method_replace(CallContext *ctx);
+ static ReturnedValue method_search(CallContext *ctx);
+ static ReturnedValue method_slice(CallContext *ctx);
+ static ReturnedValue method_split(CallContext *ctx);
+ static ReturnedValue method_substr(CallContext *context);
+ static ReturnedValue method_substring(CallContext *context);
+ static ReturnedValue method_toLowerCase(CallContext *ctx);
+ static ReturnedValue method_toLocaleLowerCase(CallContext *ctx);
+ static ReturnedValue method_toUpperCase(CallContext *ctx);
+ static ReturnedValue method_toLocaleUpperCase(CallContext *ctx);
+ static ReturnedValue method_fromCharCode(CallContext *context);
+ static ReturnedValue method_trim(CallContext *ctx);
};
}
diff --git a/src/qml/jsruntime/qv4unwindhelper.cpp b/src/qml/jsruntime/qv4unwindhelper.cpp
deleted file mode 100644
index 47266c892c..0000000000
--- a/src/qml/jsruntime/qv4unwindhelper.cpp
+++ /dev/null
@@ -1,82 +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 <qv4unwindhelper_p.h>
-
-#include <wtf/Platform.h>
-
-#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X))
-# define USE_DW2_HELPER
-#elif CPU(X86) && COMPILER(GCC)
-# define USE_DW2_HELPER
-#elif CPU(ARM) && (OS(LINUX) || OS(QNX))
-# define USE_ARM_HELPER
-#elif OS(WINDOWS)
- // SJLJ will unwind on Windows
-# define USE_NULL_HELPER
-#elif OS(IOS)
- // SJLJ will unwind on iOS
-# define USE_NULL_HELPER
-#else
-# warning "Unsupported/untested platform!"
-# define USE_NULL_HELPER
-#endif
-
-#ifdef USE_DW2_HELPER
-# include <qv4unwindhelper_dw2_p.h>
-#endif // USE_DW2_HELPER
-
-#ifdef USE_ARM_HELPER
-# include <qv4unwindhelper_arm_p.h>
-#endif // USE_ARM_HELPER
-
-QT_BEGIN_NAMESPACE
-
-#ifdef USE_NULL_HELPER
-using namespace QV4;
-void UnwindHelper::prepareForUnwind(ExecutionContext *) {}
-void UnwindHelper::registerFunction(Function *function) {Q_UNUSED(function);}
-void UnwindHelper::registerFunctions(const QVector<Function *> &functions) {Q_UNUSED(functions);}
-void UnwindHelper::deregisterFunction(Function *function) {Q_UNUSED(function);}
-void UnwindHelper::deregisterFunctions(const QVector<Function *> &functions) {Q_UNUSED(functions);}
-#endif // USE_NULL_HELPER
-
-QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4unwindhelper_arm_p.h b/src/qml/jsruntime/qv4unwindhelper_arm_p.h
deleted file mode 100644
index e15dbb0f2b..0000000000
--- a/src/qml/jsruntime/qv4unwindhelper_arm_p.h
+++ /dev/null
@@ -1,234 +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 QV4UNWINDHELPER_ARM_P_H
-#define QV4UNWINDHELPER_ARM_P_H
-
-#include "qv4unwindhelper_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4function_p.h"
-#include <wtf/Platform.h>
-
-#include <QMap>
-#include <QMutex>
-
-#define __USE_GNU
-#include <dlfcn.h>
-
-#if USE(LIBUNWIND_DEBUG)
-#include <libunwind.h>
-#include <execinfo.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-static void *removeThumbBit(void *addr)
-{
- return reinterpret_cast<void*>(reinterpret_cast<qintptr>(addr) & ~1u);
-}
-
-static QMutex functionProtector;
-static QMap<quintptr, Function*> allFunctions;
-
-static Function *lookupFunction(void *pc)
-{
- quintptr key = reinterpret_cast<quintptr>(pc);
- QMap<quintptr, Function*>::Iterator it = allFunctions.lowerBound(key);
- if (it != allFunctions.begin() && allFunctions.count() > 0)
- --it;
- if (it == allFunctions.end())
- return 0;
-
- quintptr codeStart = reinterpret_cast<quintptr>(removeThumbBit((void*)(*it)->codePtr));
- if (key < codeStart || key >= codeStart + (*it)->codeSize)
- return 0;
- return *it;
-}
-
-
-/* Program:
-vsp = r4 (REG_TO_SP r4)
-vsp -= 8 * 4 -- > vsp = vsp - (7 << 2) - 4
-pop r12, r10, r9, r8, r7, r6, r5, r4
-pop r4
-pop lr
-pop r0, r1, r2, r3
-*/
-
-#define REG_TO_SP ((unsigned int) 0b10010000)
-#define VSP_MINUS ((unsigned int) 0b01000000)
-#define POP_REG_MULTI ((unsigned int) 0b10000000)
-#define POP_R4_MULTI ((unsigned int) 0b10100000)
-#define POP_R4_R14_MULTI ((unsigned int) 0b10101000)
-#define POP_R0_TO_R3 ((unsigned int) 0b10110001)
-#define FINISH ((unsigned int) 0b10110000)
-
-#define MK_UW_WORD(first, second, third, fourth) \
- (((first) << 24) | \
- ((second) << 16) | \
- ((third) << 8) | \
- (fourth))
-
-static unsigned int extbl[] = {
- MK_UW_WORD(0x80 | // High bit set to indicate that this isn't a PREL31
- 2, // Choose personality routine #2
- 2, // Number of 4 byte words used to encode remaining unwind instructions
- REG_TO_SP | 4, // Encoded program from above.
- VSP_MINUS | 7),
- MK_UW_WORD(POP_REG_MULTI | 1, 0b01111111,
- POP_R4_R14_MULTI,
- POP_R0_TO_R3),
- MK_UW_WORD(0b00001111,
- FINISH,
- FINISH,
- FINISH),
- 0 // no additional entries
-};
-
-static unsigned write_prel31(unsigned *addr, void *ptr)
-{
- int delta = (char *)ptr - (char*)addr;
- if (delta < 0)
- delta |= (1 << 30);
- else
- delta &= ~(1 << 30);
- *addr = ((unsigned)delta) & 0x7fffffffU;
-}
-
-void UnwindHelper::deregisterFunction(Function *function)
-{
- QMutexLocker locker(&functionProtector);
- allFunctions.remove(reinterpret_cast<quintptr>(function->codePtr));
-}
-
-void UnwindHelper::deregisterFunctions(const QVector<Function *> &functions)
-{
- QMutexLocker locker(&functionProtector);
- foreach (Function *f, functions)
- allFunctions.remove(reinterpret_cast<quintptr>(f->codePtr));
-}
-
-void UnwindHelper::registerFunction(Function *function)
-{
- QMutexLocker locker(&functionProtector);
- allFunctions.insert(reinterpret_cast<quintptr>(function->codePtr), function);
-}
-
-void UnwindHelper::registerFunctions(const QVector<Function *> &functions)
-{
- QMutexLocker locker(&functionProtector);
- foreach (Function *f, functions)
- allFunctions.insert(reinterpret_cast<quintptr>(f->codePtr), f);
-}
-
-void UnwindHelper::prepareForUnwind(ExecutionContext *)
-{
-}
-
-int UnwindHelper::unwindInfoSize()
-{
- return 2 * sizeof(unsigned int) // 2 extbl entries
- + sizeof(extbl);
-}
-
-void UnwindHelper::writeARMUnwindInfo(void *codeAddr, int codeSize)
-{
- unsigned int *exidx = (unsigned int *)((char *)codeAddr + codeSize);
-
- unsigned char *exprog = (unsigned char *)((unsigned char *)codeAddr + codeSize + 8);
-
- write_prel31(exidx, codeAddr);
- exidx[1] = 4; // PREL31 offset to extbl, which follows right afterwards
-
- memcpy(exprog, extbl, sizeof(extbl));
-
-#if USE(LIBUNWIND_DEBUG)
- unw_dyn_info_t *info = (unw_dyn_info_t*)malloc(sizeof(unw_dyn_info_t));
- info->start_ip = (unw_word_t)codeAddr;
- info->end_ip = info->start_ip + codeSize;
- info->gp = 0;
- info->format = UNW_INFO_FORMAT_ARM_EXIDX;
- info->u.rti.name_ptr = 0;
- info->u.rti.segbase = 0;
- info->u.rti.table_len = 8;
- info->u.rti.table_data = (unw_word_t)exidx;
- _U_dyn_register(info);
-#endif
-}
-
-}
-
-QT_END_NAMESPACE
-
-#if defined(Q_OS_ANDROID)
-extern "C" void *dl_unwind_find_exidx(void *pc, int *entryCount);
-#endif
-
-extern "C" Q_DECL_EXPORT void *__gnu_Unwind_Find_exidx(void *pc, int *entryCount)
-{
-#if !defined(Q_OS_ANDROID)
- typedef void *(*Old_Unwind_Find_exidx)(void*, int*);
- static Old_Unwind_Find_exidx oldFunction = 0;
- if (!oldFunction)
- oldFunction = (Old_Unwind_Find_exidx)dlsym(RTLD_NEXT, "__gnu_Unwind_Find_exidx");
-#endif
-
- {
- QMutexLocker locker(&QT_PREPEND_NAMESPACE(QV4::functionProtector));
- QV4::Function *function = QT_PREPEND_NAMESPACE(QV4::lookupFunction(pc));
- if (function) {
- *entryCount = 1;
- void * codeStart = QT_PREPEND_NAMESPACE(QV4::removeThumbBit((void*)function->codePtr));
- // At the end of the function we store our synthetic exception table entry.
- return (char *)codeStart + function->codeSize;
- }
- }
-
-#if defined(Q_OS_ANDROID)
- return dl_unwind_find_exidx(pc, entryCount);
-#else
- return oldFunction(pc, entryCount);
-#endif
-}
-
-#endif // QV4UNWINDHELPER_PDW2_H
diff --git a/src/qml/jsruntime/qv4unwindhelper_dw2_p.h b/src/qml/jsruntime/qv4unwindhelper_dw2_p.h
deleted file mode 100644
index 03533ba526..0000000000
--- a/src/qml/jsruntime/qv4unwindhelper_dw2_p.h
+++ /dev/null
@@ -1,191 +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 QV4UNWINDHELPER_PDW2_H
-#define QV4UNWINDHELPER_PDW2_H
-
-#include "qv4unwindhelper_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4function_p.h"
-#include <wtf/Platform.h>
-#include <wtf/PageAllocation.h>
-#include <ExecutableAllocator.h>
-#include <private/qv4isel_masm_p.h>
-
-#include <QMap>
-#include <QMutex>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-namespace {
-#if CPU(X86_64)
-// Generated by fdegen
-static const unsigned char cie_fde_data[] = {
- 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x1, 0x0, 0x8, 0x78, 0x10, 0xc, 0x7, 0x8,
- 0x90, 0x1, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
- 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x41, 0x13, 0x7e, 0x86,
- 0x2, 0x43, 0xd, 0x6, 0x8c, 0x3, 0x8e, 0x4,
- 0x0, 0x0, 0x0, 0x0
-};
-static const int fde_offset = 20;
-static const int initial_location_offset = 28;
-static const int address_range_offset = 36;
-#elif CPU(X86)
-static const unsigned char cie_fde_data[] = {
- 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x1, 0x0, 0x4, 0x7c, 0x8, 0xc, 0x4, 0x4,
- 0x88, 0x1, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
- 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x41, 0x13, 0x7e, 0x85,
- 0x2, 0x43, 0xd, 0x5, 0x86, 0x3, 0x87, 0x4,
- 0x0, 0x0, 0x0, 0x0,
-};
-static const int fde_offset = 20;
-static const int initial_location_offset = 28;
-static const int address_range_offset = 32;
-#endif
-
-void writeIntPtrValue(unsigned char *addr, qintptr val)
-{
- addr[0] = (val >> 0) & 0xff;
- addr[1] = (val >> 8) & 0xff;
- addr[2] = (val >> 16) & 0xff;
- addr[3] = (val >> 24) & 0xff;
-#if QT_POINTER_SIZE == 8
- addr[4] = (val >> 32) & 0xff;
- addr[5] = (val >> 40) & 0xff;
- addr[6] = (val >> 48) & 0xff;
- addr[7] = (val >> 56) & 0xff;
-#endif
-}
-} // anonymous namespace
-
-extern "C" void __register_frame(void *fde);
-extern "C" void __deregister_frame(void *fde);
-
-struct UnwindInfo : public ExecutableAllocator::PlatformUnwindInfo
-{
- UnwindInfo(const QByteArray &cieFde);
- virtual ~UnwindInfo();
- QByteArray data;
-};
-
-UnwindInfo::UnwindInfo(const QByteArray &cieFde)
- : data(cieFde)
-{
- __register_frame(data.data() + fde_offset);
-}
-
-UnwindInfo::~UnwindInfo()
-{
- __deregister_frame(data.data() + fde_offset);
-}
-
-static void ensureUnwindInfo(Function *f)
-{
- if (!f->codePtr)
- return; // Not a JIT generated function
-
- ExecutableAllocator::ChunkOfPages *chunk = f->compilationUnit->chunkForFunction(f->compiledFunction->index);
- if (!chunk)
- return;
-
- // Already registered?
- if (chunk->unwindInfo)
- return;
-
- QByteArray info;
- info.resize(sizeof(cie_fde_data));
-
- unsigned char *cie_and_fde = reinterpret_cast<unsigned char *>(info.data());
- memcpy(cie_and_fde, cie_fde_data, sizeof(cie_fde_data));
-
- qintptr ptr = static_cast<char *>(chunk->pages->base()) - static_cast<char *>(0);
- writeIntPtrValue(cie_and_fde + initial_location_offset, ptr);
-
- writeIntPtrValue(cie_and_fde + address_range_offset, chunk->pages->size());
-
- chunk->unwindInfo = new UnwindInfo(info);
-}
-
-void UnwindHelper::prepareForUnwind(ExecutionContext *context)
-{
- for (ExecutionContext *ctx = context; ctx; ctx = ctx->parent) {
- if (CallContext *callCtx = ctx->asCallContext())
- if (FunctionObject *fobj = callCtx->function)
- if (Function *fun = fobj->function)
- ensureUnwindInfo(fun);
- for (ExecutionContext::EvalCode *code = ctx->currentEvalCode;
- code; code = code->next)
- ensureUnwindInfo(code->function);
- }
-
- if (context->engine->globalCode)
- ensureUnwindInfo(context->engine->globalCode);
-}
-
-void UnwindHelper::registerFunction(Function *)
-{
-}
-
-void UnwindHelper::registerFunctions(const QVector<Function *>&)
-{
-}
-
-void UnwindHelper::deregisterFunction(Function *)
-{
-}
-
-void UnwindHelper::deregisterFunctions(const QVector<Function *> &)
-{
-}
-
-}
-
-QT_END_NAMESPACE
-
-#endif // QV4UNWINDHELPER_PDW2_H
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index ebd1894016..4ae570c8dc 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -125,22 +125,20 @@ QString Value::toQStringNoThrow() const
Scope scope(ctx);
ScopedValue ex(scope);
bool caughtException = false;
- try {
- ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), STRING_HINT));
- if (prim->isPrimitive())
- return prim->toQStringNoThrow();
- } catch (...) {
+ ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), STRING_HINT));
+ if (scope.hasException()) {
ex = ctx->catchException();
caughtException = true;
+ } else if (prim->isPrimitive()) {
+ return prim->toQStringNoThrow();
}
// Can't nest try/catch due to CXX ABI limitations for foreign exception nesting.
if (caughtException) {
- try {
- ScopedValue prim(scope, __qmljs_to_primitive(ex, STRING_HINT));
- if (prim->isPrimitive())
- return prim->toQStringNoThrow();
- } catch(...) {
- ctx->catchException();
+ ScopedValue prim(scope, __qmljs_to_primitive(ex, STRING_HINT));
+ if (scope.hasException()) {
+ ex = ctx->catchException();
+ } else if (prim->isPrimitive()) {
+ return prim->toQStringNoThrow();
}
}
return QString();
@@ -398,11 +396,11 @@ WeakValue::~WeakValue()
d->deref();
}
-void WeakValue::markOnce()
+void WeakValue::markOnce(ExecutionEngine *e)
{
if (!d)
return;
- d->value.mark();
+ d->value.mark(e);
}
PersistentValuePrivate::PersistentValuePrivate(ReturnedValue v, ExecutionEngine *e, bool weak)
diff --git a/src/qml/jsruntime/qv4value_def_p.h b/src/qml/jsruntime/qv4value_def_p.h
index 163aed9abc..cf351c125a 100644
--- a/src/qml/jsruntime/qv4value_def_p.h
+++ b/src/qml/jsruntime/qv4value_def_p.h
@@ -243,7 +243,7 @@ struct Q_QML_EXPORT Value
void setDouble(double d) { dbl = d; }
bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
#endif
- bool isString() const;
+ inline bool isString() const;
inline bool isObject() const;
inline bool isInt32() {
if (tag == _Integer_Type)
@@ -286,15 +286,15 @@ struct Q_QML_EXPORT Value
return val;
}
- static Value fromManaged(Managed *o);
+ static inline Value fromManaged(Managed *o);
int toUInt16() const;
- int toInt32() const;
- unsigned int toUInt32() const;
+ inline int toInt32() const;
+ inline unsigned int toUInt32() const;
- bool toBoolean() const;
+ inline bool toBoolean() const;
double toInteger() const;
- double toNumber() const;
+ inline double toNumber() const;
double toNumberImpl() const;
QString toQStringNoThrow() const;
QString toQString() const;
@@ -309,20 +309,20 @@ struct Q_QML_EXPORT Value
return b;
}
- String *asString() const;
- Managed *asManaged() const;
- Object *asObject() const;
- FunctionObject *asFunctionObject() const;
- NumberObject *asNumberObject() const;
- StringObject *asStringObject() const;
- DateObject *asDateObject() const;
- ArrayObject *asArrayObject() const;
- ErrorObject *asErrorObject() const;
+ inline String *asString() const;
+ inline Managed *asManaged() const;
+ inline Object *asObject() const;
+ inline FunctionObject *asFunctionObject() const;
+ inline NumberObject *asNumberObject() const;
+ inline StringObject *asStringObject() const;
+ inline DateObject *asDateObject() const;
+ inline ArrayObject *asArrayObject() const;
+ inline ErrorObject *asErrorObject() const;
template<typename T> inline T *as() const;
- uint asArrayIndex() const;
- uint asArrayLength(bool *ok) const;
+ inline uint asArrayIndex() const;
+ inline uint asArrayLength(bool *ok) const;
inline ExecutionEngine *engine() const;
@@ -335,7 +335,7 @@ struct Q_QML_EXPORT Value
// Section 9.12
bool sameValue(Value other) const;
- inline void mark() const;
+ inline void mark(ExecutionEngine *e) const;
};
inline Managed *Value::asManaged() const
@@ -354,13 +354,13 @@ inline String *Value::asString() const
struct Q_QML_EXPORT Primitive : public Value
{
- static Primitive emptyValue();
- static Primitive fromBoolean(bool b);
- static Primitive fromInt32(int i);
- static Primitive undefinedValue();
- static Primitive nullValue();
- static Primitive fromDouble(double d);
- static Primitive fromUInt32(uint i);
+ inline static Primitive emptyValue();
+ static inline Primitive fromBoolean(bool b);
+ static inline Primitive fromInt32(int i);
+ inline static Primitive undefinedValue();
+ static inline Primitive nullValue();
+ static inline Primitive fromDouble(double d);
+ static inline Primitive fromUInt32(uint i);
static double toInteger(double fromNumber);
static int toInt32(double value);
@@ -382,6 +382,14 @@ inline Primitive Primitive::undefinedValue()
return v;
}
+inline Primitive Primitive::emptyValue()
+{
+ Primitive v;
+ v.tag = Value::Empty_Type;
+ v.uint_32 = 0;
+ return v;
+}
+
inline Value Value::fromManaged(Managed *m)
{
if (!m)
@@ -445,7 +453,7 @@ struct Safe : public SafeValue
T *getPointer() const { return static_cast<T *>(managed()); }
Returned<T> *ret() const;
- void mark() { if (managed()) managed()->mark(); }
+ void mark(ExecutionEngine *e) { if (managed()) managed()->mark(e); }
};
typedef Safe<String> SafeString;
typedef Safe<Object> SafeObject;
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index a2137ee849..680c7465ca 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -49,6 +49,7 @@
#include "qv4string_p.h"
#include <QtCore/QDebug>
#include "qv4managed_p.h"
+#include "qv4engine_p.h"
#include <private/qtqmlglobal_p.h>
//#include <wtf/MathExtras.h>
@@ -77,17 +78,19 @@ inline bool Value::isPrimitive() const
return !isObject();
}
-inline ExecutionEngine *Value::engine() const {
+inline ExecutionEngine *Value::engine() const
+{
Managed *m = asManaged();
return m ? m->engine() : 0;
}
-inline void Value::mark() const {
+inline void Value::mark(ExecutionEngine *e) const
+{
if (!val)
return;
Managed *m = asManaged();
if (m)
- m->mark();
+ m->mark(e);
}
inline Primitive Primitive::nullValue()
@@ -102,15 +105,6 @@ inline Primitive Primitive::nullValue()
return v;
}
-inline Primitive Primitive::emptyValue()
-{
- Primitive v;
- v.tag = Value::Empty_Type;
- v.uint_32 = 0;
- return v;
-}
-
-
inline Primitive Primitive::fromBoolean(bool b)
{
Primitive v;
@@ -389,7 +383,7 @@ public:
*this = WeakValue();
}
- void markOnce();
+ void markOnce(ExecutionEngine *e);
private:
friend struct ValueRef;
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index a37da31782..470e8e206b 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -153,7 +153,7 @@ void VariantPrototype::init()
defineDefaultProperty(engine()->id_toString, method_toString, 0);
}
-QV4::ReturnedValue VariantPrototype::method_preserve(SimpleCallContext *ctx)
+QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx)
{
Scope scope(ctx);
Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>());
@@ -162,7 +162,7 @@ QV4::ReturnedValue VariantPrototype::method_preserve(SimpleCallContext *ctx)
return Encode::undefined();
}
-QV4::ReturnedValue VariantPrototype::method_destroy(SimpleCallContext *ctx)
+QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx)
{
Scope scope(ctx);
Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>());
@@ -174,7 +174,7 @@ QV4::ReturnedValue VariantPrototype::method_destroy(SimpleCallContext *ctx)
return Encode::undefined();
}
-QV4::ReturnedValue VariantPrototype::method_toString(SimpleCallContext *ctx)
+QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>());
@@ -186,7 +186,7 @@ QV4::ReturnedValue VariantPrototype::method_toString(SimpleCallContext *ctx)
return Encode(ctx->engine->newString(result));
}
-QV4::ReturnedValue VariantPrototype::method_valueOf(SimpleCallContext *ctx)
+QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx)
{
Scope scope(ctx);
Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>());
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index 4d852142aa..4e14839184 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -89,10 +89,10 @@ public:
void init();
- static ReturnedValue method_preserve(SimpleCallContext *ctx);
- static ReturnedValue method_destroy(SimpleCallContext *ctx);
- static ReturnedValue method_toString(SimpleCallContext *ctx);
- static ReturnedValue method_valueOf(SimpleCallContext *ctx);
+ static ReturnedValue method_preserve(CallContext *ctx);
+ static ReturnedValue method_destroy(CallContext *ctx);
+ static ReturnedValue method_toString(CallContext *ctx);
+ static ReturnedValue method_valueOf(CallContext *ctx);
};
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 64b49f9a05..00672fea0f 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -45,6 +45,7 @@
#include <private/qv4debugging_p.h>
#include <private/qv4math_p.h>
#include <private/qv4scopedvalue_p.h>
+#include <private/qv4lookup_p.h>
#include <iostream>
#include "qv4alloca_p.h"
@@ -63,8 +64,8 @@ using namespace QQmlJS::Moth;
#define MOTH_BEGIN_INSTR_COMMON(I) { \
const InstrMeta<(int)Instr::I>::DataType &instr = InstrMeta<(int)Instr::I>::data(*genericInstr); \
code += InstrMeta<(int)Instr::I>::Size; \
- if (context->engine->debugger && (instr.breakPoint || context->engine->debugger->pauseAtNextOpportunity())) \
- context->engine->debugger->maybeBreakAtInstruction(code, instr.breakPoint); \
+ if (debugger && (instr.breakPoint || debugger->pauseAtNextOpportunity())) \
+ debugger->maybeBreakAtInstruction(code, instr.breakPoint); \
Q_UNUSED(instr); \
TRACE_INSTR(I)
@@ -89,11 +90,11 @@ using namespace QQmlJS::Moth;
MOTH_BEGIN_INSTR_COMMON(I)
# define MOTH_NEXT_INSTR(I) { \
- break; \
+ continue; \
}
# define MOTH_END_INSTR(I) } \
- break;
+ continue;
#endif
@@ -133,17 +134,11 @@ static VMStats vmStats;
#define VMSTATS(what) {}
#endif // WITH_STATS
-static inline QV4::Value *getValueRef(QV4::ExecutionContext *context,
- QV4::SafeValue* stack,
- const Param &param
-#if !defined(QT_NO_DEBUG)
- , unsigned stackSize
-#endif
- )
-{
#ifdef DO_TRACE_INSTR
- if (param.isValue()) {
- fprintf(stderr, " value %s\n", param.value.toString(context)->toQString().toUtf8().constData());
+Param traceParam(const Param &param)
+{
+ if (param.isConstant()) {
+ fprintf(stderr, " constant\n");
} else if (param.isArgument()) {
fprintf(stderr, " argument %d@%d\n", param.index, param.scope);
} else if (param.isLocal()) {
@@ -155,70 +150,26 @@ static inline QV4::Value *getValueRef(QV4::ExecutionContext *context,
} else {
Q_ASSERT(!"INVALID");
}
-#endif // DO_TRACE_INSTR
-
- if (param.isValue()) {
- VMSTATS(paramIsValue);
- return const_cast<QV4::Value *>(&static_cast<const QV4::Value &>(param.value));
- } else if (param.isArgument()) {
- VMSTATS(paramIsArg);
- QV4::ExecutionContext *c = context;
- uint scope = param.scope;
- while (scope--)
- c = c->outer;
- QV4::CallContext *cc = static_cast<QV4::CallContext *>(c);
- const unsigned arg = param.index;
- Q_ASSERT(arg >= 0);
- Q_ASSERT((unsigned) arg < cc->callData->argc);
- Q_ASSERT(cc->callData->args);
- return cc->callData->args + arg;
- } else if (param.isLocal()) {
- VMSTATS(paramIsLocal);
- const unsigned index = param.index;
- QV4::CallContext *c = static_cast<QV4::CallContext *>(context);
- Q_ASSERT(index >= 0);
- Q_ASSERT(index < context->variableCount());
- Q_ASSERT(c->locals);
- return c->locals + index;
- } else if (param.isTemp()) {
- VMSTATS(paramIsTemp);
-#if !defined(QT_NO_DEBUG)
- Q_ASSERT(param.index < stackSize);
-#endif
- return stack + param.index;
- } else if (param.isScopedLocal()) {
- VMSTATS(paramIsScopedLocal);
- QV4::ExecutionContext *c = context;
- uint scope = param.scope;
- while (scope--)
- c = c->outer;
- const unsigned index = param.index;
- QV4::CallContext *cc = static_cast<QV4::CallContext *>(c);
- Q_ASSERT(index >= 0);
- Q_ASSERT(index < cc->variableCount());
- Q_ASSERT(cc->locals);
- return cc->locals + index;
- } else {
- Q_UNIMPLEMENTED();
- return 0;
- }
+ return Param
}
-
-#if defined(QT_NO_DEBUG)
# define VALUE(param) (*VALUEPTR(param))
-
-// The non-temp case might need some tweaking for QML: there it would probably be a value instead of a local.
-# define VALUEPTR(param) \
- (param.isTemp() ? stack + param.index \
- : (param.isLocal() ? static_cast<QV4::CallContext *>(context)->locals + param.index \
- : getValueRef(context, stack, param)))
+# define VALUEPTR(param) (scopes[traceParam(param).scope] + param.index)
#else
-# define VALUE(param) (*getValueRef(context, stack, param, stackSize))
-# define VALUEPTR(param) getValueRef(context, stack, param, stackSize)
+# define VALUE(param) (*VALUEPTR(param))
+# define VALUEPTR(param) (scopes[param.scope] + param.index)
#endif
-#define STOREVALUE(param, value) VALUE(param) = QV4::Value::fromReturnedValue((value))
-QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
+#define STOREVALUE(param, value) { \
+ QV4::ReturnedValue tmp = (value); \
+ if (context->engine->hasException) \
+ goto catchException; \
+ VALUE(param) = tmp; \
+ }
+#define CHECK_EXCEPTION \
+ if (context->engine->hasException) \
+ goto catchException
+
+QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
QV4::SafeValue *stack, unsigned stackSize
#ifdef MOTH_THREADED_INTERPRETER
, void ***storeJumpTable
@@ -241,31 +192,65 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
}
#endif
+ const uchar *exceptionHandler = 0;
+
+ QV4::Debugging::Debugger *debugger = context->engine->debugger;
+
+#ifdef DO_TRACE_INSTR
+ qDebug("Starting VME with context=%p and code=%p", context, code);
+#endif // DO_TRACE_INSTR
+
QV4::SafeString * const runtimeStrings = context->compilationUnit->runtimeStrings;
context->interpreterInstructionPointer = &code;
-#ifdef MOTH_THREADED_INTERPRETER
- const Instr *genericInstr = reinterpret_cast<const Instr *>(code);
- goto *genericInstr->common.code;
-#else
+ // setup lookup scopes
+ int scopeDepth = 0;
+ {
+ QV4::ExecutionContext *scope = context;
+ while (scope) {
+ ++scopeDepth;
+ scope = scope->outer;
+ }
+ }
+
+ QV4::SafeValue **scopes = static_cast<QV4::SafeValue **>(alloca(sizeof(QV4::SafeValue *)*(2 + 2*scopeDepth)));
+ {
+ scopes[0] = const_cast<QV4::SafeValue *>(context->compilationUnit->data->constants());
+ // stack gets setup in push instruction
+ scopes[1] = 0;
+ QV4::ExecutionContext *scope = context;
+ int i = 0;
+ while (scope) {
+ if (scope->type >= QV4::ExecutionContext::Type_SimpleCallContext) {
+ QV4::CallContext *cc = static_cast<QV4::CallContext *>(scope);
+ scopes[2*i + 2] = cc->callData->args;
+ scopes[2*i + 3] = cc->locals;
+ } else {
+ scopes[2*i + 2] = 0;
+ scopes[2*i + 3] = 0;
+ }
+ ++i;
+ scope = scope->outer;
+ }
+ }
+
+
for (;;) {
const Instr *genericInstr = reinterpret_cast<const Instr *>(code);
+#ifdef MOTH_THREADED_INTERPRETER
+ goto *genericInstr->common.code;
+#else
switch (genericInstr->common.instructionType) {
#endif
- MOTH_BEGIN_INSTR(MoveTemp)
+ MOTH_BEGIN_INSTR(Move)
VALUE(instr.result) = VALUE(instr.source);
- MOTH_END_INSTR(MoveTemp)
+ MOTH_END_INSTR(Move)
MOTH_BEGIN_INSTR(SwapTemps)
qSwap(VALUE(instr.left), VALUE(instr.right));
MOTH_END_INSTR(MoveTemp)
- MOTH_BEGIN_INSTR(LoadValue)
-// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
- VALUE(instr.result) = VALUE(instr.value);
- MOTH_END_INSTR(LoadValue)
-
MOTH_BEGIN_INSTR(LoadRuntimeString)
// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
VALUE(instr.result) = runtimeStrings[instr.stringId].asReturnedValue();
@@ -285,9 +270,16 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
STOREVALUE(instr.result, __qmljs_get_activation_property(context, runtimeStrings[instr.name]));
MOTH_END_INSTR(LoadName)
+ MOTH_BEGIN_INSTR(GetGlobalLookup)
+ TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
+ QV4::Lookup *l = context->lookups + instr.index;
+ STOREVALUE(instr.result, l->globalGetter(l, context));
+ MOTH_END_INSTR(GetGlobalLookup)
+
MOTH_BEGIN_INSTR(StoreName)
TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
__qmljs_set_activation_property(context, runtimeStrings[instr.name], VALUEPTR(instr.source));
+ CHECK_EXCEPTION;
MOTH_END_INSTR(StoreName)
MOTH_BEGIN_INSTR(LoadElement)
@@ -296,21 +288,44 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_BEGIN_INSTR(StoreElement)
__qmljs_set_element(context, VALUEPTR(instr.base), VALUEPTR(instr.index), VALUEPTR(instr.source));
+ CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
STOREVALUE(instr.result, __qmljs_get_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name]));
MOTH_END_INSTR(LoadProperty)
+ MOTH_BEGIN_INSTR(GetLookup)
+ QV4::Lookup *l = context->lookups + instr.index;
+ STOREVALUE(instr.result, l->getter(l, VALUEPTR(instr.base)));
+ MOTH_END_INSTR(GetLookup)
+
MOTH_BEGIN_INSTR(StoreProperty)
__qmljs_set_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name], VALUEPTR(instr.source));
+ CHECK_EXCEPTION;
MOTH_END_INSTR(StoreProperty)
+ MOTH_BEGIN_INSTR(SetLookup)
+ QV4::Lookup *l = context->lookups + instr.index;
+ l->setter(l, VALUEPTR(instr.base), VALUEPTR(instr.source));
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(SetLookup)
+
+ MOTH_BEGIN_INSTR(StoreQObjectProperty)
+ __qmljs_set_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex, VALUEPTR(instr.source));
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(StoreQObjectProperty)
+
+ MOTH_BEGIN_INSTR(LoadQObjectProperty)
+ STOREVALUE(instr.result, __qmljs_get_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex, instr.captureRequired));
+ MOTH_END_INSTR(LoadQObjectProperty)
+
MOTH_BEGIN_INSTR(Push)
TRACE(inline, "stack size: %u", instr.value);
stackSize = instr.value;
stack = context->engine->stackPush(stackSize);
memset(stack, 0, stackSize * sizeof(QV4::SafeValue));
+ scopes[1] = stack;
MOTH_END_INSTR(Push)
MOTH_BEGIN_INSTR(CallValue)
@@ -342,6 +357,16 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
STOREVALUE(instr.result, __qmljs_call_property(context, runtimeStrings[instr.name], callData));
MOTH_END_INSTR(CallProperty)
+ MOTH_BEGIN_INSTR(CallPropertyLookup)
+ TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+ callData->tag = QV4::Value::Integer_Type;
+ callData->argc = instr.argc;
+ callData->thisObject = VALUE(instr.base);
+ STOREVALUE(instr.result, __qmljs_call_property_lookup(context, instr.lookupIndex, callData));
+ MOTH_END_INSTR(CallPropertyLookup)
+
MOTH_BEGIN_INSTR(CallElement)
Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
@@ -361,43 +386,32 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
STOREVALUE(instr.result, __qmljs_call_activation_property(context, runtimeStrings[instr.name], callData));
MOTH_END_INSTR(CallActivationProperty)
+ MOTH_BEGIN_INSTR(CallGlobalLookup)
+ TRACE(args, "starting at %d, length %d", instr.args, instr.argc);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+ callData->tag = QV4::Value::Integer_Type;
+ callData->argc = instr.argc;
+ callData->thisObject = QV4::Primitive::undefinedValue();
+ STOREVALUE(instr.result, __qmljs_call_global_lookup(context, instr.index, callData));
+ MOTH_END_INSTR(CallGlobalLookup)
+
+ MOTH_BEGIN_INSTR(SetExceptionHandler)
+ exceptionHandler = instr.offset ? ((uchar *)&instr.offset) + instr.offset : 0;
+ MOTH_END_INSTR(SetExceptionHandler)
+
MOTH_BEGIN_INSTR(CallBuiltinThrow)
__qmljs_throw(context, VALUEPTR(instr.arg));
+ CHECK_EXCEPTION;
MOTH_END_INSTR(CallBuiltinThrow)
- MOTH_BEGIN_INSTR(EnterTry)
- VALUE(instr.exceptionVar) = QV4::Primitive::undefinedValue();
- bool caughtException = false;
- try {
- const uchar *tryCode = ((uchar *)&instr.tryOffset) + instr.tryOffset;
- run(context, tryCode, stack, stackSize);
- code = tryCode;
- context->interpreterInstructionPointer = &code;
- } catch (...) {
- STOREVALUE(instr.exceptionVar, context->catchException());
- caughtException = true;
- }
- if (caughtException) {
- try {
- QV4::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(runtimeStrings[instr.exceptionVarName], VALUEPTR(instr.exceptionVar), context);
- const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
- run(catchContext, catchCode, stack, stackSize);
- code = catchCode;
- context->interpreterInstructionPointer = &code;
- context = __qmljs_builtin_pop_scope(catchContext);
- } catch (...) {
- STOREVALUE(instr.exceptionVar, context->catchException());
- const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
- run(context, catchCode, stack, stackSize);
- code = catchCode;
- context->interpreterInstructionPointer = &code;
- }
- }
- MOTH_END_INSTR(EnterTry)
+ MOTH_BEGIN_INSTR(CallBuiltinUnwindException)
+ STOREVALUE(instr.result, __qmljs_builtin_unwind_exception(context));
+ MOTH_END_INSTR(CallBuiltinUnwindException)
- MOTH_BEGIN_INSTR(CallBuiltinFinishTry)
- return QV4::ReturnedValue(0);
- MOTH_END_INSTR(CallBuiltinFinishTry)
+ MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope)
+ context = __qmljs_builtin_push_catch_scope(context, runtimeStrings[instr.name]);
+ MOTH_END_INSTR(CallBuiltinPushCatchScope)
MOTH_BEGIN_INSTR(CallBuiltinPushScope)
context = __qmljs_builtin_push_with_scope(VALUEPTR(instr.arg), context);
@@ -470,6 +484,11 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
STOREVALUE(instr.result, __qmljs_builtin_setup_arguments_object(context));
MOTH_END_INSTR(CallBuiltinSetupArgumentsObject)
+ MOTH_BEGIN_INSTR(CallBuiltinConvertThisToObject)
+ __qmljs_builtin_convert_this_to_object(context);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CallBuiltinConvertThisToObject)
+
MOTH_BEGIN_INSTR(CreateValue)
Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
@@ -484,10 +503,19 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, __qmljs_construct_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name], callData));
+ callData->thisObject = VALUE(instr.base);
+ STOREVALUE(instr.result, __qmljs_construct_property(context, runtimeStrings[instr.name], callData));
MOTH_END_INSTR(CreateProperty)
+ MOTH_BEGIN_INSTR(ConstructPropertyLookup)
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+ callData->tag = QV4::Value::Integer_Type;
+ callData->argc = instr.argc;
+ callData->thisObject = VALUE(instr.base);
+ STOREVALUE(instr.result, __qmljs_construct_property_lookup(context, instr.index, callData));
+ MOTH_END_INSTR(ConstructPropertyLookup)
+
MOTH_BEGIN_INSTR(CreateActivationProperty)
TRACE(inline, "property name = %s, args = %d, argc = %d", runtimeStrings[instr.name]->toQString().toUtf8().constData(), instr.args, instr.argc);
Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
@@ -498,6 +526,16 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
STOREVALUE(instr.result, __qmljs_construct_activation_property(context, runtimeStrings[instr.name], callData));
MOTH_END_INSTR(CreateActivationProperty)
+ MOTH_BEGIN_INSTR(ConstructGlobalLookup)
+ TRACE(inline, "property name = %s, args = %d, argc = %d", runtimeStrings[instr.name]->toQString().toUtf8().constData(), instr.args, instr.argc);
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+ callData->tag = QV4::Value::Integer_Type;
+ callData->argc = instr.argc;
+ callData->thisObject = QV4::Primitive::undefinedValue();
+ STOREVALUE(instr.result, __qmljs_construct_global_lookup(context, instr.index, callData));
+ MOTH_END_INSTR(ConstructGlobalLookup)
+
MOTH_BEGIN_INSTR(Jump)
code = ((uchar *)&instr.offset) + instr.offset;
MOTH_END_INSTR(Jump)
@@ -511,14 +549,82 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
code = ((uchar *)&instr.offset) + instr.offset;
MOTH_END_INSTR(CJump)
- MOTH_BEGIN_INSTR(Unop)
- STOREVALUE(instr.result, instr.alu(VALUEPTR(instr.source)));
- MOTH_END_INSTR(Unop)
+ MOTH_BEGIN_INSTR(UNot)
+ STOREVALUE(instr.result, __qmljs_not(VALUEPTR(instr.source)));
+ MOTH_END_INSTR(UNot)
+
+ MOTH_BEGIN_INSTR(UNotBool)
+ bool b = VALUE(instr.source).booleanValue();
+ VALUE(instr.result) = QV4::Encode(!b);
+ MOTH_END_INSTR(UNotBool)
+
+ MOTH_BEGIN_INSTR(UPlus)
+ STOREVALUE(instr.result, __qmljs_uplus(VALUEPTR(instr.source)));
+ MOTH_END_INSTR(UPlus)
+
+ MOTH_BEGIN_INSTR(UMinus)
+ STOREVALUE(instr.result, __qmljs_uminus(VALUEPTR(instr.source)));
+ MOTH_END_INSTR(UMinus)
+
+ MOTH_BEGIN_INSTR(UCompl)
+ STOREVALUE(instr.result, __qmljs_compl(VALUEPTR(instr.source)));
+ MOTH_END_INSTR(UCompl)
+
+ MOTH_BEGIN_INSTR(UComplInt)
+ VALUE(instr.result) = QV4::Encode((int)~VALUE(instr.source).integerValue());
+ MOTH_END_INSTR(UComplInt)
+
+ MOTH_BEGIN_INSTR(Increment)
+ STOREVALUE(instr.result, __qmljs_increment(VALUEPTR(instr.source)));
+ MOTH_END_INSTR(Increment)
+
+ MOTH_BEGIN_INSTR(Decrement)
+ STOREVALUE(instr.result, __qmljs_decrement(VALUEPTR(instr.source)));
+ MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Binop)
STOREVALUE(instr.result, instr.alu(VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
MOTH_END_INSTR(Binop)
+ MOTH_BEGIN_INSTR(Add)
+ STOREVALUE(instr.result, __qmljs_add(context, VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
+ MOTH_END_INSTR(Add)
+
+ MOTH_BEGIN_INSTR(BitAnd)
+ STOREVALUE(instr.result, __qmljs_bit_and(VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
+ MOTH_END_INSTR(BitAnd)
+
+ MOTH_BEGIN_INSTR(BitOr)
+ STOREVALUE(instr.result, __qmljs_bit_or(VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
+ MOTH_END_INSTR(BitOr)
+
+ MOTH_BEGIN_INSTR(BitXor)
+ STOREVALUE(instr.result, __qmljs_bit_xor(VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
+ MOTH_END_INSTR(BitXor)
+
+ MOTH_BEGIN_INSTR(BitAndConst)
+ int lhs = VALUEPTR(instr.lhs)->toInt32();
+ STOREVALUE(instr.result, QV4::Encode((int)(lhs & instr.rhs)));
+ MOTH_END_INSTR(BitAnd)
+
+ MOTH_BEGIN_INSTR(BitOrConst)
+ int lhs = VALUEPTR(instr.lhs)->toInt32();
+ STOREVALUE(instr.result, QV4::Encode((int)(lhs | instr.rhs)));
+ MOTH_END_INSTR(BitOr)
+
+ MOTH_BEGIN_INSTR(BitXorConst)
+ int lhs = VALUEPTR(instr.lhs)->toInt32();
+ STOREVALUE(instr.result, QV4::Encode((int)(lhs ^ instr.rhs)));
+ MOTH_END_INSTR(BitXor)
+
+ MOTH_BEGIN_INSTR(Mul)
+ STOREVALUE(instr.result, __qmljs_mul(VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
+ MOTH_END_INSTR(Mul)
+
+ MOTH_BEGIN_INSTR(Sub)
+ STOREVALUE(instr.result, __qmljs_sub(VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
+ MOTH_END_INSTR(Sub)
+
MOTH_BEGIN_INSTR(BinopContext)
STOREVALUE(instr.result, instr.alu(context, VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)));
MOTH_END_INSTR(BinopContext)
@@ -551,6 +657,26 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
VALUE(instr.result) = context->callData->thisObject;
MOTH_END_INSTR(LoadThis)
+ MOTH_BEGIN_INSTR(LoadQmlIdArray)
+ VALUE(instr.result) = __qmljs_get_id_array(static_cast<QV4::NoThrowContext*>(context));
+ MOTH_END_INSTR(LoadQmlIdArray)
+
+ MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
+ VALUE(instr.result) = __qmljs_get_imported_scripts(static_cast<QV4::NoThrowContext*>(context));
+ MOTH_END_INSTR(LoadQmlImportedScripts)
+
+ MOTH_BEGIN_INSTR(LoadQmlContextObject)
+ VALUE(instr.result) = __qmljs_get_context_object(static_cast<QV4::NoThrowContext*>(context));
+ MOTH_END_INSTR(LoadContextObject)
+
+ MOTH_BEGIN_INSTR(LoadQmlScopeObject)
+ VALUE(instr.result) = __qmljs_get_scope_object(static_cast<QV4::NoThrowContext*>(context));
+ MOTH_END_INSTR(LoadScopeObject)
+
+ MOTH_BEGIN_INSTR(LoadQmlSingleton)
+ VALUE(instr.result) = __qmljs_get_qml_singleton(static_cast<QV4::NoThrowContext*>(context), runtimeStrings[instr.name]);
+ MOTH_END_INSTR(LoadQmlSingleton)
+
#ifdef MOTH_THREADED_INTERPRETER
// nothing to do
#else
@@ -558,9 +684,19 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
qFatal("QQmlJS::Moth::VME: Internal error - unknown instruction %d", genericInstr->common.instructionType);
break;
}
- }
#endif
+ Q_ASSERT(false);
+ catchException:
+ Q_ASSERT(context->engine->hasException);
+ if (!exceptionHandler) {
+ context->engine->stackPop(stackSize);
+ return QV4::Encode::undefined();
+ }
+ code = exceptionHandler;
+ }
+
+
}
#ifdef MOTH_THREADED_INTERPRETER
@@ -578,5 +714,11 @@ void **VME::instructionJumpTable()
QV4::ReturnedValue VME::exec(QV4::ExecutionContext *ctxt, const uchar *code)
{
VME vme;
- return vme.run(ctxt, code);
+ QV4::Debugging::Debugger *debugger = ctxt->engine->debugger;
+ if (debugger)
+ debugger->enteringFunction();
+ QV4::ReturnedValue retVal = vme.run(ctxt, code);
+ if (debugger)
+ debugger->leavingFunction(retVal);
+ return retVal;
}
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 68d8086f52..974dfdd615 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -60,7 +60,7 @@ public:
#endif
private:
- QV4::ReturnedValue run(QV4::ExecutionContext *, const uchar *&code,
+ QV4::ReturnedValue run(QV4::ExecutionContext *, const uchar *code,
QV4::SafeValue *stack = 0, unsigned stackSize = 0
#ifdef MOTH_THREADED_INTERPRETER
, void ***storeJumpTable = 0
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 6d26d9cb38..08bda0bce7 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -7,6 +7,9 @@ win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS
solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
+MODULE_PLUGIN_TYPES = \
+ qmltooling
+
exists("qqml_enable_gcov") {
QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors
LIBS += -lgcov
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 40caaf379f..321e6ccb41 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -209,137 +209,6 @@ static inline bool isUnicodeNonCharacter(uint ucs4)
|| (ucs4 - 0xfdd0U) < 16;
}
-static int utf8LengthFromUtf16(const QChar *uc, int len)
-{
- int length = 0;
-
- int surrogate_high = -1;
-
- const QChar *ch = uc;
- int invalid = 0;
-
- const QChar *end = ch + len;
- while (ch < end) {
- uint u = ch->unicode();
- if (surrogate_high >= 0) {
- if (u >= 0xdc00 && u < 0xe000) {
- u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000;
- surrogate_high = -1;
- } else {
- // high surrogate without low
- ++ch;
- ++invalid;
- surrogate_high = -1;
- continue;
- }
- } else if (u >= 0xdc00 && u < 0xe000) {
- // low surrogate without high
- ++ch;
- ++invalid;
- continue;
- } else if (u >= 0xd800 && u < 0xdc00) {
- surrogate_high = u;
- ++ch;
- continue;
- }
-
- if (u < 0x80) {
- ++length;
- } else {
- if (u < 0x0800) {
- ++length;
- } else {
- // is it one of the Unicode non-characters?
- if (isUnicodeNonCharacter(u)) {
- ++length;
- ++ch;
- ++invalid;
- continue;
- }
-
- if (u > 0xffff) {
- ++length;
- ++length;
- } else {
- ++length;
- }
- ++length;
- }
- ++length;
- }
- ++ch;
- }
-
- return length;
-}
-
-// Writes the utf8 version of uc to output. uc is of length len.
-// There must be at least utf8LengthFromUtf16(uc, len) bytes in output.
-// A null terminator is not written.
-static void utf8FromUtf16(char *output, const QChar *uc, int len)
-{
- uchar replacement = '?';
- int surrogate_high = -1;
-
- uchar* cursor = (uchar*)output;
- const QChar *ch = uc;
- int invalid = 0;
-
- const QChar *end = ch + len;
- while (ch < end) {
- uint u = ch->unicode();
- if (surrogate_high >= 0) {
- if (u >= 0xdc00 && u < 0xe000) {
- u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000;
- surrogate_high = -1;
- } else {
- // high surrogate without low
- *cursor = replacement;
- ++ch;
- ++invalid;
- surrogate_high = -1;
- continue;
- }
- } else if (u >= 0xdc00 && u < 0xe000) {
- // low surrogate without high
- *cursor = replacement;
- ++ch;
- ++invalid;
- continue;
- } else if (u >= 0xd800 && u < 0xdc00) {
- surrogate_high = u;
- ++ch;
- continue;
- }
-
- if (u < 0x80) {
- *cursor++ = (uchar)u;
- } else {
- if (u < 0x0800) {
- *cursor++ = 0xc0 | ((uchar) (u >> 6));
- } else {
- // is it one of the Unicode non-characters?
- if (isUnicodeNonCharacter(u)) {
- *cursor++ = replacement;
- ++ch;
- ++invalid;
- continue;
- }
-
- if (u > 0xffff) {
- *cursor++ = 0xf0 | ((uchar) (u >> 18));
- *cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f);
- } else {
- *cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f);
- }
- *cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f);
- }
- *cursor++ = 0x80 | ((uchar) (u&0x3f));
- }
- ++ch;
- }
-}
-
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
Q_ASSERT(offset < m_length);
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 3bba6f8e83..f969f5c644 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -126,7 +126,7 @@ HEADERS += \
$$PWD/qqmlplatform_p.h \
$$PWD/qqmlbinding_p.h \
$$PWD/qqmlextensionplugin_p.h \
- $$PWD/qqmlabstracturlinterceptor.h \
+ $$PWD/qqmlabstracturlinterceptor_p.h \
$$PWD/qqmlapplicationengine_p.h \
$$PWD/qqmlapplicationengine.h \
$$PWD/qqmllistwrapper_p.h \
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 6082fcda08..b6c6fe840d 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -485,6 +485,24 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
+inline int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ if (url.isRelative()) {
+ // User input check must go here, because QQmlPrivate::qmlregister is also used internally for composite types
+ qWarning("qmlRegisterSingletonType requires absolute URLs.");
+ return 0;
+ }
+
+ QQmlPrivate::RegisterCompositeSingletonType type = {
+ url,
+ uri,
+ versionMajor,
+ versionMinor,
+ qmlName
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, &type);
+}
inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp
index c01981b3d2..32762a46bf 100644
--- a/src/qml/qml/qqmlabstractbinding.cpp
+++ b/src/qml/qml/qqmlabstractbinding.cpp
@@ -56,9 +56,8 @@ QQmlAbstractBinding::VTable *QQmlAbstractBinding::vTables[] = {
};
QQmlAbstractBinding::QQmlAbstractBinding(BindingType bt)
-: m_nextBindingPtr(bt)
+ : m_nextBindingPtr(bt)
{
- Q_ASSERT(bt <= 0x03);
}
QQmlAbstractBinding::~QQmlAbstractBinding()
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp
index 127dad86ce..321698ad8e 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.cpp
+++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp
@@ -44,6 +44,9 @@
\inmodule QtQml
\brief allows you to control QML file loading.
+ \note This class is not currently public API, due to the risk of being affected
+ by planned engine changes in upcoming releases.
+
QQmlAbstractUrlInterceptor is an interface which can be used to alter URLs
before they are used by the QML engine. This is primarily useful for altering
file urls into other file urls, such as selecting different graphical assets
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.h b/src/qml/qml/qqmlabstracturlinterceptor_p.h
index 4bcaa89b4a..471c837eed 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.h
+++ b/src/qml/qml/qqmlabstracturlinterceptor_p.h
@@ -43,11 +43,11 @@
#define QQMLABSTRACTURLINTERCEPTOR_H
#include <QtCore/qurl.h>
-#include <QtQml/qtqmlglobal.h>
+#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
-class Q_QML_EXPORT QQmlAbstractUrlInterceptor
+class Q_QML_PRIVATE_EXPORT QQmlAbstractUrlInterceptor
{
Q_FLAGS(InterceptionPoint)
public:
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 3f13f8a140..b4ace17738 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -77,7 +77,7 @@ void QQmlApplicationEnginePrivate::init()
QCoreApplication::installTranslator(qtTranslator);
translators << qtTranslator;
#endif
- q->setUrlInterceptor(new QQmlFileSelector(q));
+ new QQmlFileSelector(q,q);
QCoreApplication::instance()->setProperty("__qml_using_qqmlapplicationengine", QVariant(true));
}
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index a388178952..557267d808 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -194,16 +194,6 @@ QQmlBinding::~QQmlBinding()
{
}
-void QQmlBinding::setEvaluateFlags(EvaluateFlags flags)
-{
- setRequiresThisObject(flags & RequiresThisObject);
-}
-
-QQmlBinding::EvaluateFlags QQmlBinding::evaluateFlags() const
-{
- return requiresThisObject()?RequiresThisObject:None;
-}
-
void QQmlBinding::setNotifyOnValueChanged(bool v)
{
QQmlJavaScriptExpression::setNotifyOnValueChanged(v);
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index e872482373..9dd63a6e9c 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -76,9 +76,6 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
public QQmlAbstractBinding
{
public:
- enum EvaluateFlag { None = 0x00, RequiresThisObject = 0x01 };
- Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag)
-
QQmlBinding(const QString &, QObject *, QQmlContext *);
QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *);
QQmlBinding(const QString &, QObject *, QQmlContextData *);
@@ -91,9 +88,6 @@ public:
void setTarget(QObject *, const QQmlPropertyData &, QQmlContextData *);
QQmlProperty property() const;
- void setEvaluateFlags(EvaluateFlags flags);
- EvaluateFlags evaluateFlags() const;
-
void setNotifyOnValueChanged(bool);
// Inherited from QQmlAbstractExpression
@@ -177,8 +171,6 @@ void QQmlBinding::setEnabledFlag(bool v)
m_ctxt.setFlag2Value(v);
}
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlBinding::EvaluateFlags)
-
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQmlBinding*)
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 2cfb074aae..54fd002f7b 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -61,7 +61,7 @@
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
#include "qqmlbinding_p.h"
-#include "qqmlabstracturlinterceptor.h"
+#include "qqmlabstracturlinterceptor_p.h"
#include "qqmlcodegenerator_p.h"
#include <QDebug>
@@ -583,8 +583,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
Instruction::StoreTime instr;
QTime time = QQmlStringConverters::timeFromString(v->value.asString());
instr.propertyIndex = prop->index;
- Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
- ::memcpy(&instr.time, &time, sizeof(QTime));
+ instr.time = time.msecsSinceStartOfDay();
output->addInstruction(instr);
}
break;
@@ -595,8 +594,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
QTime time = dateTime.time();
instr.propertyIndex = prop->index;
instr.date = dateTime.date().toJulianDay();
- Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
- ::memcpy(&instr.time, &time, sizeof(QTime));
+ instr.time = time.msecsSinceStartOfDay();
output->addInstruction(instr);
}
break;
@@ -810,7 +808,7 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
this->unit = unit;
this->unitRoot = root;
this->output = out;
- this->jsModule.reset(new QQmlJS::V4IR::Module);
+ this->jsModule.reset(new QQmlJS::V4IR::Module(enginePrivate->v4engine()->debugger));
this->jsModule->isQmlModule = true;
// Compile types
@@ -921,7 +919,7 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
if (!jsModule->functions.isEmpty()) {
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Compiler::JSUnitGenerator jsUnitGenerator(jsModule.data());
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, jsModule.data(), &jsUnitGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, jsModule.data(), &jsUnitGenerator));
isel->setUseFastLookups(false);
QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/true);
output->compilationUnit = jsUnit;
@@ -1336,7 +1334,7 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
} else if (v->type == Value::SignalExpression) {
Instruction::StoreSignal store;
- store.runtimeFunctionIndex = compileState->runtimeFunctionIndices.at(v->signalData.functionIndex);
+ store.runtimeFunctionIndex = compileState->jsCompileData[v->signalData.signalScopeObject].runtimeFunctionIndices.at(v->signalData.functionIndex);
store.handlerName = output->indexForString(prop->name().toString());
store.parameters = output->indexForString(obj->metatype->signalParameterStringForJS(prop->index));
store.signalIndex = prop->index;
@@ -1738,12 +1736,15 @@ bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *o
//to ensure all parameters are available (see qqmlboundsignal constructor for more details)
prop->index = obj->metatype->originalClone(prop->index);
prop->values.first()->signalData.signalExpressionContextStack = ctxt.stack;
+ prop->values.first()->signalData.signalScopeObject = ctxt.object;
QList<QByteArray> parameters = obj->metatype->signalParameterNames(prop->index);
AST::FunctionDeclaration *funcDecl = convertSignalHandlerExpressionToFunctionDeclaration(unit->parser().jsEngine(), prop->values.first()->value.asAST(), propName.toString(), parameters);
- compileState->functionsToCompile.append(funcDecl);
- prop->values.first()->signalData.functionIndex = compileState->functionsToCompile.count() - 1;
+
+ ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[ctxt.object];
+ cd->functionsToCompile.append(funcDecl);
+ prop->values.first()->signalData.functionIndex = cd->functionsToCompile.count() - 1;
QString errorString;
obj->metatype->signalParameterStringForJS(prop->index, &errorString);
@@ -3250,12 +3251,13 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
vmd->methodCount++;
md = methodData;
- QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod cmm;
- cmm.obj = obj;
+ ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[obj];
+
+ ComponentCompileState::CompiledMetaMethod cmm;
cmm.methodIndex = vmd->methodCount - 1;
- compileState->functionsToCompile.append(s->funcDecl);
- cmm.compiledFunctionIndex = compileState->functionsToCompile.count() - 1;
- compileState->compiledMetaMethods.append(cmm);
+ cd->functionsToCompile.append(s->funcDecl);
+ cmm.compiledFunctionIndex = cd->functionsToCompile.count() - 1;
+ cd->compiledMetaMethods.append(cmm);
}
if (aliasCount)
@@ -3641,32 +3643,60 @@ bool QQmlCompiler::completeComponentBuild()
node = new (pool) AST::ExpressionStatement(expr);
}
- compileState->functionsToCompile.append(node);
- binding.compiledIndex = compileState->functionsToCompile.count() - 1;
+ ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[b->bindingContext.object];
+ cd->functionsToCompile.append(node);
+ binding.compiledIndex = cd->functionsToCompile.count() - 1;
+ cd->expressionNames.insert(binding.compiledIndex, binding.property->name().toString().prepend(QStringLiteral("expression for ")));
if (componentStats)
componentStats->componentStat.scriptBindings.append(b->value->location);
}
- if (!compileState->functionsToCompile.isEmpty()) {
- JSCodeGen jsCodeGen;
-
+ if (!compileState->jsCompileData.isEmpty()) {
const QString &sourceCode = jsEngine->code();
AST::UiProgram *qmlRoot = parser.qmlRoot();
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, compileState->functionsToCompile);
- compileState->runtimeFunctionIndices = runtimeFunctionIndices;
+ JSCodeGen jsCodeGen(enginePrivate, unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache);
- for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
- JSBindingReference &binding = *b;
- binding.compiledIndex = runtimeFunctionIndices[binding.compiledIndex];
+ JSCodeGen::ObjectIdMapping idMapping;
+ if (compileState->ids.count() > 0) {
+ idMapping.reserve(compileState->ids.count());
+ for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) {
+ JSCodeGen::IdMapping m;
+ m.name = o->id;
+ m.idIndex = o->idIndex;
+ m.type = o->metatype;
+ idMapping << m;
+ }
+ }
+
+ jsCodeGen.beginContextScope(idMapping, compileState->root->metatype);
+
+ for (QHash<QQmlScript::Object *, ComponentCompileState::PerObjectCompileData>::Iterator it = compileState->jsCompileData.begin();
+ it != compileState->jsCompileData.end(); ++it) {
+ QQmlScript::Object *scopeObject = it.key();
+ ComponentCompileState::PerObjectCompileData *cd = &it.value();
+
+ jsCodeGen.beginObjectScope(scopeObject->metatype);
+
+ cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile, cd->expressionNames);
+ QList<QQmlError> errors = jsCodeGen.errors();
+ if (!errors.isEmpty()) {
+ exceptions << errors;
+ return false;
+ }
+
+ foreach (const QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod &cmm, cd->compiledMetaMethods) {
+ typedef QQmlVMEMetaData VMD;
+ VMD *vmd = (QQmlVMEMetaData *)scopeObject->synthdata.data();
+ VMD::MethodData &md = *(vmd->methodData() + cmm.methodIndex);
+ md.runtimeFunctionIndex = cd->runtimeFunctionIndices.at(cmm.compiledFunctionIndex);
+ }
}
- foreach (const QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod &cmm, compileState->compiledMetaMethods) {
- typedef QQmlVMEMetaData VMD;
- VMD *vmd = (QQmlVMEMetaData *)cmm.obj->synthdata.data();
- VMD::MethodData &md = *(vmd->methodData() + cmm.methodIndex);
- md.runtimeFunctionIndex = runtimeFunctionIndices.at(cmm.compiledFunctionIndex);
+ for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
+ JSBindingReference &binding = *b;
+ binding.compiledIndex = compileState->jsCompileData[binding.bindingContext.object].runtimeFunctionIndices[binding.compiledIndex];
}
}
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 142d8c68b1..3ca4566e41 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -302,16 +302,22 @@ namespace QQmlCompilerTypes {
typedef QFieldList<O, &O::nextAliasingObject> AliasingObjectsList;
AliasingObjectsList aliasingObjects;
QQmlScript::Object *root;
- QList<QQmlJS::AST::Node*> functionsToCompile;
- QVector<int> runtimeFunctionIndices;
struct CompiledMetaMethod
{
- QQmlScript::Object *obj;
int methodIndex;
int compiledFunctionIndex; // index in functionToCompile
};
+
QList<CompiledMetaMethod> compiledMetaMethods;
+ struct PerObjectCompileData
+ {
+ QList<QQmlJS::AST::Node*> functionsToCompile;
+ QVector<int> runtimeFunctionIndices;
+ QVector<CompiledMetaMethod> compiledMetaMethods;
+ QHash<int, QString> expressionNames;
+ };
+ QHash<QQmlScript::Object *, PerObjectCompileData> jsCompileData;
};
};
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index ab08fb78e3..2973944215 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -218,7 +218,7 @@ static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
Components are often defined by \l {{QML Documents}}{component files} -
that is, \c .qml files. The \e Component type essentially allows QML components
- to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
+ to be defined inline, within a \l {QML Documents}{QML document}, rather than as a separate QML file.
This may be useful for reusing a small component within a QML file, or for defining
a component that logically belongs with other QML components within a file.
@@ -235,7 +235,7 @@ static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
two \l Loader objects). Because Component is not derived from Item, you cannot
anchor anything to it.
- Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
+ Defining a \c Component is similar to defining a \l {QML Documents}{QML document}.
A QML document has a single top-level item that defines the behavior and
properties of that component, and cannot define properties or behavior outside
of that top-level item. In the same way, a \c Component definition contains a single
@@ -1113,14 +1113,14 @@ class QmlIncubatorObject : public QV4::Object
public:
QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
- static QV4::ReturnedValue method_get_statusChanged(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_statusChanged(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_status(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_object(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_forceCompletion(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_get_statusChanged(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_statusChanged(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_status(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_object(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_forceCompletion(QV4::CallContext *ctx);
static void destroy(Managed *that);
- static void markObjects(Managed *that);
+ static void markObjects(Managed *that, QV4::ExecutionEngine *e);
QScopedPointer<QQmlComponentIncubator> incubator;
QV8Engine *v8;
@@ -1265,7 +1265,6 @@ void QQmlComponent::createObject(QQmlV4Function *args)
Q_ASSERT(object->isObject());
if (!valuemap->isUndefined()) {
- QQmlComponentExtension *e = componentExtension(args->engine());
QV4::ScopedObject qmlglobal(scope, args->qmlGlobal());
QV4::ScopedValue f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlglobal));
Q_ASSERT(f->asFunctionObject());
@@ -1420,7 +1419,6 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Valu
Q_ASSERT(object->asObject());
if (!valuemap->isUndefined()) {
- QQmlComponentExtension *e = componentExtension(v8engine);
QV4::ScopedObject qmlGlobalObj(scope, qmlGlobal);
QV4::Scoped<QV4::FunctionObject> f(scope, QV4::Script::evaluate(QV8Engine::getV4(v8engine),
QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobalObj));
@@ -1446,54 +1444,54 @@ QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine)
incubationProto = proto;
}
-QV4::ReturnedValue QmlIncubatorObject::method_get_object(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QmlIncubatorObject::method_get_object(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return QV4::QObjectWrapper::wrap(ctx->engine, o->incubator->object());
}
-QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
o->incubator->forceCompletion();
return QV4::Encode::undefined();
}
-QV4::ReturnedValue QmlIncubatorObject::method_get_status(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QmlIncubatorObject::method_get_status(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return QV4::Encode(o->incubator->status());
}
-QV4::ReturnedValue QmlIncubatorObject::method_get_statusChanged(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QmlIncubatorObject::method_get_statusChanged(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return o->m_statusChanged.asReturnedValue();
}
-QV4::ReturnedValue QmlIncubatorObject::method_set_statusChanged(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QmlIncubatorObject::method_set_statusChanged(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
if (!o || ctx->callData->argc < 1)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
o->m_statusChanged = ctx->callData->args[0];
@@ -1521,8 +1519,6 @@ void QmlIncubatorObject::setInitialState(QObject *o)
QQmlComponent_setQmlParent(o, parent);
if (!valuemap.isUndefined()) {
- QQmlComponentExtension *e = componentExtension(v8);
-
QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8);
QV4::Scope scope(v4);
@@ -1542,14 +1538,14 @@ void QmlIncubatorObject::destroy(Managed *that)
o->~QmlIncubatorObject();
}
-void QmlIncubatorObject::markObjects(QV4::Managed *that)
+void QmlIncubatorObject::markObjects(QV4::Managed *that, QV4::ExecutionEngine *e)
{
QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
Q_ASSERT(o);
- o->valuemap.mark();
- o->qmlGlobal.mark();
- o->m_statusChanged.mark();
- Object::markObjects(that);
+ o->valuemap.mark(e);
+ o->qmlGlobal.mark(e);
+ o->m_statusChanged.mark(e);
+ Object::markObjects(that, e);
}
void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
@@ -1567,13 +1563,13 @@ void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QV4::ScopedFunctionObject f(scope, m_statusChanged);
if (f) {
QV4::ExecutionContext *ctx = scope.engine->current;
- try {
- QV4::ScopedCallData callData(scope, 1);
- callData->thisObject = this;
- callData->args[0] = QV4::Primitive::fromUInt32(s);
- f->call(callData);
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ QV4::ScopedCallData callData(scope, 1);
+ callData->thisObject = this;
+ callData->args[0] = QV4::Primitive::fromUInt32(s);
+ f->call(callData);
+ if (scope.hasException()) {
+ ctx->catchException();
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v8->engine()), error);
}
}
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 78e6650d02..7731935b75 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -48,7 +48,7 @@
#include "qqmlengine_p.h"
#include "qqmlengine.h"
#include "qqmlinfo.h"
-#include "qqmlabstracturlinterceptor.h"
+#include "qqmlabstracturlinterceptor_p.h"
#include <qjsengine.h>
#include <QtCore/qvarlengtharray.h>
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index a5c3886af1..26048b0217 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -158,7 +158,7 @@ public:
QObject *contextObject;
// Any script blocks that exist on this context
- QList<QV4::PersistentValue> importedScripts;
+ QV4::PersistentValue importedScripts; // This is a JS Array
// Context base url
QUrl url;
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index c867b6e126..0b3b282061 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -47,9 +47,10 @@
#include <private/qv4engine_p.h>
#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qv4mm_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4compileddata_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmllistwrapper_p.h>
@@ -62,7 +63,7 @@ DEFINE_MANAGED_VTABLE(QmlContextWrapper);
QmlContextWrapper::QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext)
: Object(QV8Engine::getV4(engine)),
v8(engine), readOnly(true), ownsContext(ownsContext), isNullWrapper(false),
- context(context), scopeObject(scopeObject)
+ context(context), scopeObject(scopeObject), idObjectsWrapper(0)
{
vtbl = &static_vtbl;
}
@@ -135,7 +136,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
QV4::Scope scope(v4);
QmlContextWrapper *resource = m->as<QmlContextWrapper>();
if (!resource)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
// In V8 the JS global object would come _before_ the QML global object,
// so simulate that here.
@@ -191,11 +192,8 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
if (hasProperty)
*hasProperty = true;
if (r.scriptIndex != -1) {
- int index = r.scriptIndex;
- if (index < context->importedScripts.count())
- return context->importedScripts.at(index).value();
- else
- return QV4::Primitive::undefinedValue().asReturnedValue();
+ QV4::ScopedObject scripts(scope, context->importedScripts);
+ return scripts->getIndexed(r.scriptIndex);
} else if (r.type) {
return QmlTypeWrapper::create(engine, scopeObject, r.type);
} else if (r.importNamespace) {
@@ -281,9 +279,13 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
{
ExecutionEngine *v4 = m->engine();
QV4::Scope scope(v4);
+ if (scope.hasException())
+ return;
QV4::Scoped<QmlContextWrapper> wrapper(scope, m->as<QmlContextWrapper>());
- if (!wrapper)
+ if (!wrapper) {
v4->current->throwTypeError();
+ return;
+ }
if (wrapper->isNullWrapper) {
if (wrapper && wrapper->readOnly) {
@@ -291,6 +293,7 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
QLatin1Char('"');
Scoped<String> e(scope, v4->current->engine->newString(error));
v4->current->throwError(e);
+ return;
}
Object::put(m, name, value);
@@ -341,6 +344,7 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
v4->current->throwError(error);
+ return;
}
Object::put(m, name, value);
@@ -351,4 +355,119 @@ void QmlContextWrapper::destroy(Managed *that)
static_cast<QmlContextWrapper *>(that)->~QmlContextWrapper();
}
+void QmlContextWrapper::markObjects(Managed *m, ExecutionEngine *engine)
+{
+ QmlContextWrapper *This = static_cast<QmlContextWrapper*>(m);
+ if (This->idObjectsWrapper)
+ This->idObjectsWrapper->mark(engine);
+ Object::markObjects(m, engine);
+}
+
+void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const CompiledData::Function *compiledFunction)
+{
+ // Let the caller check and avoid the function call :)
+ Q_ASSERT(compiledFunction->hasQmlDependencies());
+
+ QQmlEnginePrivate *ep = engine->v8Engine->engine() ? QQmlEnginePrivate::get(engine->v8Engine->engine()) : 0;
+ if (!ep)
+ return;
+ QQmlEnginePrivate::PropertyCapture *capture = ep->propertyCapture;
+ if (!capture)
+ return;
+
+ QV4::Scope scope(engine);
+ QV4::Scoped<QmlContextWrapper> contextWrapper(scope, engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
+ QQmlContextData *qmlContext = contextWrapper->getContext();
+
+ const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
+ const int idObjectDependencyCount = compiledFunction->nDependingIdObjects;
+ for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency)
+ capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings);
+
+ const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
+ const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
+ for (int i = 0; i < contextPropertyDependencyCount; ++i) {
+ const int propertyIndex = *contextPropertyDependency++;
+ const int notifyIndex = *contextPropertyDependency++;
+ capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex);
+ }
+
+ QObject *scopeObject = contextWrapper->getScopeObject();
+ const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
+ const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties;
+ for (int i = 0; i < scopePropertyDependencyCount; ++i) {
+ const int propertyIndex = *scopePropertyDependency++;
+ const int notifyIndex = *scopePropertyDependency++;
+ capture->captureProperty(scopeObject, propertyIndex, notifyIndex);
+ }
+
+}
+
+ReturnedValue QmlContextWrapper::idObjectsArray()
+{
+ if (!idObjectsWrapper) {
+ ExecutionEngine *v4 = engine();
+ idObjectsWrapper = new (v4->memoryManager) QQmlIdObjectsArray(v4, this);
+ }
+ return idObjectsWrapper->asReturnedValue();
+}
+
+ReturnedValue QmlContextWrapper::qmlSingletonWrapper(const StringRef &name)
+{
+ if (!context->imports)
+ return Encode::undefined();
+ // Search for attached properties, enums and imported scripts
+ QQmlTypeNameCache::Result r = context->imports->query(name);
+
+ Q_ASSERT(r.isValid());
+ Q_ASSERT(r.type);
+ Q_ASSERT(r.type->isSingleton());
+
+ QQmlEngine *e = v8->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
+ siinfo->init(e);
+
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ return QV4::QObjectWrapper::wrap(engine(), qobjectSingleton);
+}
+
+DEFINE_MANAGED_VTABLE(QQmlIdObjectsArray);
+
+QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper)
+ : Object(engine)
+ , contextWrapper(contextWrapper)
+{
+ vtbl = &static_vtbl;
+}
+
+ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(m);
+ QQmlContextData *context = This->contextWrapper->getContext();
+ if (!context) {
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+ }
+ if (index >= (uint)context->idValueCount) {
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+ }
+
+ ExecutionEngine *v4 = m->engine();
+ QQmlEnginePrivate *ep = v4->v8Engine->engine() ? QQmlEnginePrivate::get(v4->v8Engine->engine()) : 0;
+ if (ep)
+ ep->captureProperty(&context->idValues[index].bindings);
+
+ return QObjectWrapper::wrap(This->engine(), context->idValues[index].data());
+}
+
+void QQmlIdObjectsArray::markObjects(Managed *that, ExecutionEngine *engine)
+{
+ QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(that);
+ This->contextWrapper->mark(engine);
+ Object::markObjects(that, engine);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h
index 86ad4e5616..89ace7090c 100644
--- a/src/qml/qml/qqmlcontextwrapper_p.h
+++ b/src/qml/qml/qqmlcontextwrapper_p.h
@@ -59,11 +59,18 @@
#include <private/qv4value_p.h>
#include <private/qv4object_p.h>
#include <private/qqmlcontext_p.h>
+#include <private/qv4functionobject_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
+namespace CompiledData {
+struct Function;
+}
+
+struct QQmlIdObjectsArray;
+
struct Q_QML_EXPORT QmlContextWrapper : Object
{
Q_MANAGED
@@ -85,7 +92,12 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
static void put(Managed *m, const StringRef name, const ValueRef value);
static void destroy(Managed *that);
+ static void markObjects(Managed *m, ExecutionEngine *engine);
+ static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction);
+
+ ReturnedValue idObjectsArray();
+ ReturnedValue qmlSingletonWrapper(const StringRef &name);
QV8Engine *v8; // ### temporary, remove
bool readOnly;
@@ -94,6 +106,19 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
QQmlGuardedContextData context;
QPointer<QObject> scopeObject;
+private:
+ QQmlIdObjectsArray *idObjectsWrapper;
+};
+
+struct QQmlIdObjectsArray : public Object
+{
+ Q_MANAGED
+ QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper);
+
+ static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void markObjects(Managed *that, ExecutionEngine *engine);
+
+ QmlContextWrapper *contextWrapper;
};
}
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 76d03f011e..621b3d3c2e 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -79,7 +79,7 @@ class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData
{
public:
QQmlData()
- : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
+ : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
hasTaintedV8Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
hasVMEMetaObject(false), parentFrozen(false), notifyList(0), context(0), outerContext(0),
bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0),
@@ -113,6 +113,7 @@ public:
if (!explicitIndestructibleSet) indestructible = false;
}
+ quint32 ownedByQml1:1; // This bit is shared with QML1's QDeclarativeData.
quint32 ownMemory:1;
quint32 ownContext:1;
quint32 indestructible:1;
@@ -126,7 +127,7 @@ public:
quint32 rootObjectInCreation:1;
quint32 hasVMEMetaObject:1;
quint32 parentFrozen:1;
- quint32 dummy:23;
+ quint32 dummy:22;
struct NotifyList {
quint64 connectionMask;
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index b23b760b78..c1d0132c61 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -142,7 +142,7 @@ bool QQmlDirParser::parse(const QString &source)
if (invalidLine) {
reportError(lineNumber, 0,
- QString::fromUtf8("invalid qmldir directive contains too many tokens"));
+ QString::fromLatin1("invalid qmldir directive contains too many tokens"));
continue;
} else if (sectionCount == 0) {
continue; // no sections, no party.
@@ -150,17 +150,17 @@ bool QQmlDirParser::parse(const QString &source)
} else if (sections[0] == QLatin1String("module")) {
if (sectionCount != 2) {
reportError(lineNumber, 0,
- QString::fromUtf8("module identifier directive requires one argument, but %1 were provided").arg(sectionCount - 1));
+ QString::fromLatin1("module identifier directive requires one argument, but %1 were provided").arg(sectionCount - 1));
continue;
}
if (!_typeNamespace.isEmpty()) {
reportError(lineNumber, 0,
- QString::fromUtf8("only one module identifier directive may be defined in a qmldir file"));
+ QString::fromLatin1("only one module identifier directive may be defined in a qmldir file"));
continue;
}
if (!firstLine) {
reportError(lineNumber, 0,
- QString::fromUtf8("module identifier directive must be the first directive in a qmldir file"));
+ QString::fromLatin1("module identifier directive must be the first directive in a qmldir file"));
continue;
}
@@ -169,7 +169,7 @@ bool QQmlDirParser::parse(const QString &source)
} else if (sections[0] == QLatin1String("plugin")) {
if (sectionCount < 2 || sectionCount > 3) {
reportError(lineNumber, 0,
- QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
+ QString::fromLatin1("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
@@ -181,7 +181,7 @@ bool QQmlDirParser::parse(const QString &source)
} else if (sections[0] == QLatin1String("internal")) {
if (sectionCount != 3) {
reportError(lineNumber, 0,
- QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1));
+ QString::fromLatin1("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
Component entry(sections[1], sections[2], -1, -1);
@@ -190,7 +190,7 @@ bool QQmlDirParser::parse(const QString &source)
} else if (sections[0] == QLatin1String("singleton")) {
if (sectionCount < 3 || sectionCount > 4) {
reportError(lineNumber, 0,
- QString::fromUtf8("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1));
+ QString::fromLatin1("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1));
continue;
} else if (sectionCount == 3) {
// handle qmldir directory listing case where singleton is defined in the following pattern:
@@ -227,7 +227,7 @@ bool QQmlDirParser::parse(const QString &source)
} else if (sections[0] == QLatin1String("typeinfo")) {
if (sectionCount != 2) {
reportError(lineNumber, 0,
- QString::fromUtf8("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
+ QString::fromLatin1("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
continue;
}
#ifdef QT_CREATOR
@@ -270,7 +270,7 @@ bool QQmlDirParser::parse(const QString &source)
}
} else {
reportError(lineNumber, 0,
- QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));
+ QString::fromLatin1("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));
}
firstLine = false;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 64cde85913..1eec710c84 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -66,7 +66,7 @@
#include <private/qv4debugservice_p.h>
#include <private/qdebugmessageservice_p.h>
#include "qqmlincubator.h"
-#include "qqmlabstracturlinterceptor.h"
+#include "qqmlabstracturlinterceptor_p.h"
#include <private/qv8profilerservice_p.h>
#include <private/qqmlboundsignal_p.h>
@@ -556,7 +556,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
workerScriptEngine(0), activeVME(0),
activeObjectCreator(0),
networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0),
- scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), uniqueId(1),
incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
{
useNewCompiler = qmlUseNewCompiler();
@@ -615,12 +615,18 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
{
- static_cast<QQmlData *>(d)->destroyed(o);
+ QQmlData *ddata = static_cast<QQmlData *>(d);
+ if (ddata->ownedByQml1)
+ return;
+ ddata->destroyed(o);
}
void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
{
- static_cast<QQmlData *>(d)->parentChanged(o, p);
+ QQmlData *ddata = static_cast<QQmlData *>(d);
+ if (ddata->ownedByQml1)
+ return;
+ ddata->parentChanged(o, p);
}
class QQmlThreadNotifierProxyObject : public QObject
@@ -649,6 +655,7 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
{
QQmlData *ddata = QQmlData::get(object, false);
if (!ddata) return; // Probably being deleted
+ if (ddata->ownedByQml1) return;
// In general, QML only supports QObject's that live on the same thread as the QQmlEngine
// that they're exposed to. However, to make writing "worker objects" that calculate data
@@ -706,12 +713,18 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
{
- return static_cast<QQmlData *>(d)->endpointCount(index);
+ QQmlData *ddata = static_cast<QQmlData *>(d);
+ if (ddata->ownedByQml1)
+ return 0;
+ return ddata->endpointCount(index);
}
bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index)
{
- return static_cast<QQmlData *>(d)->signalHasEndpoint(index);
+ QQmlData *ddata = static_cast<QQmlData *>(d);
+ if (ddata->ownedByQml1)
+ return false;
+ return ddata->signalHasEndpoint(index);
}
int QQmlData::endpointCount(int index)
@@ -1761,7 +1774,6 @@ void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
void QQmlEnginePrivate::warning(QQmlDelayedError *error)
{
- Q_Q(QQmlEngine);
warning(error->error());
}
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 5a2d6c4e00..19eb320fbe 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -186,8 +186,8 @@ public:
void referenceScarceResources();
void dereferenceScarceResources();
- QQmlTypeLoader typeLoader;
QQmlImportDatabase importDatabase;
+ QQmlTypeLoader typeLoader;
QString offlineStoragePath;
@@ -257,6 +257,7 @@ public:
inline static QQmlEnginePrivate *get(QQmlContext *c);
inline static QQmlEnginePrivate *get(QQmlContextData *c);
inline static QQmlEngine *get(QQmlEnginePrivate *p);
+ inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e);
static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor);
@@ -516,7 +517,17 @@ QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
{
Q_ASSERT(p);
- return p->q_func();
+ return p->q_func();
+}
+
+QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
+{
+ if (!e->v8Engine)
+ return 0;
+ QQmlEngine *qmlEngine = e->v8Engine->engine();
+ if (!qmlEngine)
+ return 0;
+ return get(qmlEngine);
}
void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index 5810e269eb..7f2007ec00 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -40,26 +40,30 @@
****************************************************************************/
#include <QtCore/QFileSelector>
+#include <qobjectdefs.h>
#include "qqmlfileselector.h"
#include "qqmlfileselector_p.h"
+#include "qqmlabstracturlinterceptor_p.h"
+#include <QDebug>
QT_BEGIN_NAMESPACE
+typedef QHash<QQmlAbstractUrlInterceptor*, QQmlFileSelector*> interceptorSelectorMap;
+Q_GLOBAL_STATIC(interceptorSelectorMap, interceptorInstances);
/*!
\class QQmlFileSelector
\since 5.2
\inmodule QtQml
- \brief A convenience class for applying a QFileSelector to QML file loading
+ \brief A class for applying a QFileSelector to QML file loading
- QQmlFileSelector is a QQmlAbstractUrlInterceptor which will automatically apply a QFileSelector to
+ QQmlFileSelector will automatically apply a QFileSelector to
qml file and asset paths.
It is used as follows:
\code
QQmlEngine engine;
- QQmlFileSelector selector;
- engine.setUrlInterceptor(&selector);
+ QQmlFileSelector* selector = new QQmlFileSelector(&engine);
\endcode
Then you can swap out files like so:
@@ -86,15 +90,34 @@ QT_BEGIN_NAMESPACE
Your platform may also provide additional selectors for you to use. As specified by QFileSelector,
directories used for selection must start with a '+' character, so you will not accidentally
trigger this feature unless you have directories with such names inside your project.
+
+ If a new QQmlFileSelector is set on the engine, the old one will be replaced. Use
+ \l QQmlFileSelector::get to query or use the existing instance.
*/
/*!
Creates a new QQmlFileSelector, which includes its own QFileSelector.
+ \a engine is the QQmlEngine you wish to apply file selectors too. It will
+ also take ownership of the QQmlFileSelector.
*/
-QQmlFileSelector::QQmlFileSelector(QObject* parent)
+QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent)
: QObject(*(new QQmlFileSelectorPrivate), parent)
{
+ Q_D(QQmlFileSelector);
+ d->engine = engine;
+ interceptorInstances()->insert(d->myInstance, this);
+ d->engine->setUrlInterceptor(d->myInstance);
+}
+
+QQmlFileSelector::~QQmlFileSelector()
+{
+ Q_D(QQmlFileSelector);
+ if (d->engine && QQmlFileSelector::get(d->engine) == this) {
+ d->engine->setUrlInterceptor(0);
+ d->engine = 0;
+ }
+ interceptorInstances()->remove(d->myInstance);
}
QQmlFileSelectorPrivate::QQmlFileSelectorPrivate()
@@ -102,6 +125,7 @@ QQmlFileSelectorPrivate::QQmlFileSelectorPrivate()
Q_Q(QQmlFileSelector);
ownSelector = true;
selector = new QFileSelector(q);
+ myInstance = new QQmlFileSelectorInterceptor(this);
}
/*!
@@ -127,9 +151,42 @@ void QQmlFileSelector::setSelector(QFileSelector *selector)
}
}
-QUrl QQmlFileSelector::intercept(const QUrl &path, DataType type)
+/*!
+ 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
+ QFileSelector instance.
+*/
+void QQmlFileSelector::setExtraSelectors(QStringList &strings)
{
Q_D(QQmlFileSelector);
+ d->selector->setExtraSelectors(strings);
+}
+
+/*!
+ Gets the QQmlFileSelector currently active on the target engine.
+*/
+QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine)
+{
+ //Since I think we still can't use dynamic_cast inside Qt...
+ QQmlAbstractUrlInterceptor* current = engine->urlInterceptor();
+ if (current && interceptorInstances()->contains(current))
+ return interceptorInstances()->value(current);
+ return 0;
+}
+
+/*!
+ \internal
+*/
+QQmlFileSelectorInterceptor::QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate* pd)
+ : d(pd)
+{
+}
+
+/*!
+ \internal
+*/
+QUrl QQmlFileSelectorInterceptor::intercept(const QUrl &path, DataType type)
+{
if ( type == QQmlAbstractUrlInterceptor::QmldirFile ) //Don't intercept qmldir files, to prevent double interception
return path;
return d->selector->select(path);
diff --git a/src/qml/qml/qqmlfileselector.h b/src/qml/qml/qqmlfileselector.h
index 2be221e0e4..ec9bbc77db 100644
--- a/src/qml/qml/qqmlfileselector.h
+++ b/src/qml/qml/qqmlfileselector.h
@@ -44,23 +44,23 @@
#include <QtCore/QObject>
#include <QtCore/QUrl>
-#include <QtQml/QQmlAbstractUrlInterceptor>
+#include <QtQml/QQmlEngine>
#include <QtQml/qtqmlglobal.h>
QT_BEGIN_NAMESPACE
class QFileSelector;
class QQmlFileSelectorPrivate;
-class Q_QML_EXPORT QQmlFileSelector : public QObject, public QQmlAbstractUrlInterceptor
+class Q_QML_EXPORT QQmlFileSelector : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlFileSelector)
public:
- QQmlFileSelector(QObject* parent=0);
+ QQmlFileSelector(QQmlEngine* engine, QObject* parent=0);
+ ~QQmlFileSelector();
void setSelector(QFileSelector *selector);
-
-protected:
- virtual QUrl intercept(const QUrl &path, DataType type);
+ void setExtraSelectors(QStringList &strings);
+ static QQmlFileSelector* get(QQmlEngine*);
private:
Q_DISABLE_COPY(QQmlFileSelector)
diff --git a/src/qml/qml/qqmlfileselector_p.h b/src/qml/qml/qqmlfileselector_p.h
index 60d6072c8c..fe3679e08d 100644
--- a/src/qml/qml/qqmlfileselector_p.h
+++ b/src/qml/qml/qqmlfileselector_p.h
@@ -54,19 +54,33 @@
//
#include "qqmlfileselector.h"
+#include "qqmlabstracturlinterceptor_p.h"
+#include <QSet>
#include <private/qobject_p.h>
#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
class QFileSelector;
+class QQmlFileSelectorInterceptor;
class Q_QML_PRIVATE_EXPORT QQmlFileSelectorPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlFileSelector)
public:
QQmlFileSelectorPrivate();
QFileSelector* selector;
+ QPointer<QQmlEngine> engine;
bool ownSelector;
+ QQmlFileSelectorInterceptor* myInstance;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlFileSelectorInterceptor : public QQmlAbstractUrlInterceptor
+{
+public:
+ QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate* pd);
+ QQmlFileSelectorPrivate* d;
+protected:
+ virtual QUrl intercept(const QUrl &path, DataType type);
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 63151b18bf..30b5abb383 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -839,11 +839,12 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
foreach (const QStaticPlugin &plugin, plugins) {
// Since a module can list more than one plugin, we keep iterating even after we found a match.
if (QQmlExtensionPlugin *instance = qobject_cast<QQmlExtensionPlugin *>(plugin.instance())) {
- const QJsonArray metaTagsUriList = plugin.metaData().value("uri").toArray();
+ const QJsonArray metaTagsUriList = plugin.metaData().value(QStringLiteral("uri")).toArray();
if (metaTagsUriList.isEmpty()) {
if (errors) {
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("static plugin for module \"%1\" with name \"%2\" has no metadata URI").arg(uri).arg(instance->metaObject()->className()));
+ error.setDescription(QQmlImportDatabase::tr("static plugin for module \"%1\" with name \"%2\" has no metadata URI")
+ .arg(uri).arg(QString::fromUtf8(instance->metaObject()->className())));
error.setUrl(QUrl::fromLocalFile(qmldirPath));
errors->prepend(error);
}
@@ -945,7 +946,8 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
if (errors) {
QQmlError poppedError = errors->takeFirst();
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("static plugin for module \"%1\" with name \"%2\" cannot be loaded: %3").arg(uri).arg(instance->metaObject()->className()).arg(poppedError.description()));
+ error.setDescription(QQmlImportDatabase::tr("static plugin for module \"%1\" with name \"%2\" cannot be loaded: %3")
+ .arg(uri).arg(QString::fromUtf8(instance->metaObject()->className())).arg(poppedError.description()));
error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
errors->prepend(error);
}
@@ -1021,7 +1023,8 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
dir.chop(1);
QStringList paths = database->fileImportPath;
- std::sort(paths.begin(), paths.end(), I::greaterThan); // Ensure subdirs preceed their parents.
+ if (!paths.isEmpty())
+ std::sort(paths.begin(), paths.end(), I::greaterThan); // Ensure subdirs preceed their parents.
QString stableRelativePath = dir;
foreach(const QString &path, paths) {
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
index 01b6fa41a4..150ee8df19 100644
--- a/src/qml/qml/qqmlinstruction_p.h
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -345,18 +345,13 @@ union QQmlInstruction
struct instr_storeTime {
QML_INSTR_HEADER
int propertyIndex;
- struct QTime {
- int mds;
-#if defined(Q_OS_WINCE)
- int startTick;
-#endif
- } time;
+ int time; // QTime::fromMSecsSinceStartOfDay
};
struct instr_storeDateTime {
QML_INSTR_HEADER
int propertyIndex;
int date;
- instr_storeTime::QTime time;
+ int time;
};
struct instr_storeRect {
QML_INSTR_HEADER
@@ -540,7 +535,7 @@ struct QQmlInstructionMeta {
enum { Size = QML_INSTR_SIZE(I, FMT) }; \
typedef QQmlInstruction::instr_##FMT DataType; \
static const DataType &data(const QQmlInstruction &instr) { return instr.FMT; } \
- static void setData(QQmlInstruction &instr, const DataType &v) { instr.FMT = v; } \
+ static void setData(QQmlInstruction &instr, const DataType &v) { memcpy(&instr.FMT, &v, Size); } \
};
FOR_EACH_QML_INSTR(QML_INSTR_META_TEMPLATE);
#undef QML_INSTR_META_TEMPLATE
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 37a9e398f8..3fd0003656 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -86,7 +86,7 @@ void QQmlDelayedError::setErrorObject(QObject *object)
void QQmlDelayedError::catchJavaScriptException(QV4::ExecutionContext *context)
{
- m_error = QV4::ExecutionEngine::convertJavaScriptException(context);
+ m_error = QV4::ExecutionEngine::catchExceptionAsQmlError(context);
}
@@ -148,9 +148,6 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
if (notifyOnValueChanged())
capture.guards.copyAndClearPrepend(activeGuards);
- QQmlContextData *lastSharedContext = 0;
- QObject *lastSharedScope = 0;
-
// All code that follows must check with watcher before it accesses data members
// incase we have been deleted.
DeleteWatcher watcher(this);
@@ -159,28 +156,27 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
QV4::Scope scope(v4);
QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue());
QV4::ExecutionContext *ctx = v4->current;
- try {
- callData->thisObject = ep->v8engine()->global();
- if (scopeObject() && requiresThisObject()) {
- QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->engine, scopeObject()));
- if (value->isObject())
- callData->thisObject = value;
- }
-
- result = function->asFunctionObject()->call(callData);
-
- if (isUndefined)
- *isUndefined = result->isUndefined();
+ callData->thisObject = v4->globalObject;
+ if (scopeObject()) {
+ QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->engine, scopeObject()));
+ if (value->isObject())
+ callData->thisObject = value;
+ }
- if (!watcher.wasDeleted() && hasDelayedError())
- delayedError()->clearError();
- } catch (...) {
+ result = function->asFunctionObject()->call(callData);
+ if (scope.hasException()) {
if (watcher.wasDeleted())
ctx->catchException(); // ignore exception
else
delayedError()->catchJavaScriptException(ctx);
if (isUndefined)
*isUndefined = true;
+ } else {
+ if (isUndefined)
+ *isUndefined = result->isUndefined();
+
+ if (!watcher.wasDeleted() && hasDelayedError())
+ delayedError()->clearError();
}
if (capture.errorString) {
@@ -276,6 +272,8 @@ void QQmlJavaScriptExpression::clearError()
QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const
{
+ Q_UNUSED(engine);
+
if (m_vtable.hasValue())
return m_vtable.constValue()->error();
else
@@ -302,11 +300,11 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje
QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, scopeObject));
QV4::Script script(v4, qmlScopeObject, code, filename, line);
QV4::ScopedValue result(scope);
- try {
- script.parse();
+ script.parse();
+ if (!v4->hasException)
result = script.run();
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ if (v4->hasException) {
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
if (error.description().isEmpty())
error.setDescription(QLatin1String("Exception occurred during function evaluation"));
if (error.line() == -1)
@@ -336,11 +334,11 @@ QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, Q
QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, qmlScope));
QV4::Script script(v4, qmlScopeObject, code, filename, line);
QV4::ScopedValue result(scope);
- try {
- script.parse();
+ script.parse();
+ if (!v4->hasException)
result = script.qmlBinding();
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ if (v4->hasException) {
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
if (error.description().isEmpty())
error.setDescription(QLatin1String("Exception occurred during function evaluation"));
if (error.line() == -1)
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 44357046ee..7d65f1c9cc 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -117,8 +117,6 @@ public:
QV4::ReturnedValue evaluate(QQmlContextData *, const QV4::ValueRef function, bool *isUndefined);
QV4::ReturnedValue evaluate(QQmlContextData *, const QV4::ValueRef function, QV4::CallData *callData, bool *isUndefined);
- inline bool requiresThisObject() const;
- inline void setRequiresThisObject(bool v);
inline bool notifyOnValueChanged() const;
void setNotifyOnValueChanged(bool v);
@@ -183,7 +181,6 @@ private:
QPointerValuePair<VTable, QQmlDelayedError> m_vtable;
// We store some flag bits in the following flag pointers.
- // m_scopeObject:flag1 - requiresThisObject
// activeGuards:flag1 - notifyOnValueChanged
// activeGuards:flag2 - useSharedContext
QBiPointer<QObject, DeleteWatcher> m_scopeObject;
@@ -215,16 +212,6 @@ bool QQmlJavaScriptExpression::DeleteWatcher::wasDeleted() const
return *_w == 0;
}
-bool QQmlJavaScriptExpression::requiresThisObject() const
-{
- return m_scopeObject.flag();
-}
-
-void QQmlJavaScriptExpression::setRequiresThisObject(bool v)
-{
- m_scopeObject.setFlagValue(v);
-}
-
bool QQmlJavaScriptExpression::notifyOnValueChanged() const
{
return activeGuards.flag();
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 0364659ecc..73dc3192aa 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -106,7 +106,7 @@ ReturnedValue QmlListWrapper::get(Managed *m, const StringRef name, bool *hasPro
QV4::ExecutionEngine *v4 = m->engine();
QmlListWrapper *w = m->as<QmlListWrapper>();
if (!w)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
if (name->equals(v4->id_length) && !w->object.isNull()) {
quint32 count = w->property.count ? w->property.count(&w->property) : 0;
@@ -122,10 +122,12 @@ ReturnedValue QmlListWrapper::get(Managed *m, const StringRef name, bool *hasPro
ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProperty)
{
+ Q_UNUSED(hasProperty);
+
QV4::ExecutionEngine *e = m->engine();
QmlListWrapper *w = m->as<QmlListWrapper>();
if (!w)
- e->current->throwTypeError();
+ return e->current->throwTypeError();
quint32 count = w->property.count ? w->property.count(&w->property) : 0;
if (index < count && w->property.at)
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index aca18d8ef4..5e8130f407 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -67,40 +67,42 @@ public:
QLocale locale;
- static QLocale &getThisLocale(QV4::SimpleCallContext *ctx) {
+ static QLocale *getThisLocale(QV4::CallContext *ctx) {
QQmlLocaleData *thisObject = ctx->callData->thisObject.asObject()->as<QQmlLocaleData>();
- if (!thisObject)
+ if (!thisObject) {
ctx->throwTypeError();
- return thisObject->locale;
+ return 0;
+ }
+ return &thisObject->locale;
}
- static QV4::ReturnedValue method_currencySymbol(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_dateTimeFormat(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_timeFormat(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_dateFormat(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_monthName(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_standaloneMonthName(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_dayName(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_standaloneDayName(QV4::SimpleCallContext *ctx);
-
- static QV4::ReturnedValue method_get_firstDayOfWeek(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_measurementSystem(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_textDirection(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_weekDays(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_uiLanguages(QV4::SimpleCallContext *ctx);
-
- static QV4::ReturnedValue method_get_name(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_nativeLanguageName(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_nativeCountryName(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_decimalPoint(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_groupSeparator(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_percent(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_zeroDigit(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_negativeSign(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_positiveSign(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_exponential(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_amText(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_pmText(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_dateTimeFormat(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_timeFormat(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_dateFormat(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_monthName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_standaloneMonthName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_dayName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_standaloneDayName(QV4::CallContext *ctx);
+
+ static QV4::ReturnedValue method_get_firstDayOfWeek(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_measurementSystem(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_textDirection(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_weekDays(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_uiLanguages(QV4::CallContext *ctx);
+
+ static QV4::ReturnedValue method_get_name(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_nativeLanguageName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_nativeCountryName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_decimalPoint(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_groupSeparator(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_percent(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_zeroDigit(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_negativeSign(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_positiveSign(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_exponential(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_amText(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_pmText(QV4::CallContext *ctx);
private:
static void destroy(Managed *that)
@@ -135,7 +137,7 @@ void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine)
engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated);
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx)
{
if (ctx->callData->argc > 2)
return QV4::DatePrototype::method_toLocaleString(ctx);
@@ -179,7 +181,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::SimpleCallConte
return ctx->engine->newString(formattedDt)->asReturnedValue();
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext *ctx)
{
if (ctx->callData->argc > 2)
return QV4::DatePrototype::method_toLocaleTimeString(ctx);
@@ -224,7 +226,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::SimpleCallC
return ctx->engine->newString(formattedTime)->asReturnedValue();
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext *ctx)
{
if (ctx->callData->argc > 2)
return QV4::DatePrototype::method_toLocaleDateString(ctx);
@@ -269,7 +271,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::SimpleCallC
return ctx->engine->newString(formattedDate)->asReturnedValue();
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext *ctx)
{
QV4::ExecutionEngine * const engine = ctx->engine;
if (ctx->callData->argc == 1 && ctx->callData->args[0].isString()) {
@@ -307,7 +309,7 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::SimpleCallCon
return QV4::Encode(engine->newDateObject(dt));
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallContext *ctx)
{
QV4::ExecutionEngine * const engine = ctx->engine;
@@ -351,7 +353,7 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::SimpleCal
return QV4::Encode(engine->newDateObject(dt));
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallContext *ctx)
{
QV4::ExecutionEngine * const engine = ctx->engine;
@@ -390,7 +392,7 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::SimpleCal
return QV4::Encode(engine->newDateObject(QDateTime(dt)));
}
-QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 0)
V4THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
@@ -410,7 +412,7 @@ void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine)
engine->numberCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString);
}
-QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx)
{
if (ctx->callData->argc > 3)
V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
@@ -435,7 +437,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::SimpleCallCon
if (!ctx->callData->args[1].isString())
V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
QV4::String *fs = ctx->callData->args[1].toString(ctx);
- if (!fs->isEmpty())
+ if (fs->length())
format = fs->toQString().at(0).unicode();
}
int prec = 2;
@@ -448,7 +450,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::SimpleCallCon
return ctx->engine->newString(r->locale.toString(number, (char)format, prec))->asReturnedValue();
}
-QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallContext *ctx)
{
if (ctx->callData->argc > 2)
V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
@@ -478,7 +480,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::Simpl
return ctx->engine->newString(r->locale.toCurrencyString(number, symbol))->asReturnedValue();
}
-QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext *ctx)
{
if (ctx->callData->argc < 1 || ctx->callData->argc > 2)
V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
@@ -499,7 +501,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::SimpleCallC
}
QV4::String *ns = ctx->callData->args[numberIdx].toString(ctx);
- if (ns->isEmpty())
+ if (!ns->length())
return QV4::Encode(Q_QNAN);
bool ok = false;
@@ -514,32 +516,42 @@ QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::SimpleCallC
//--------------
// Locale object
-QV4::ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(QV4::CallContext *ctx)
{
- QLocale locale = getThisLocale(ctx);
- int fdow = int(locale.firstDayOfWeek());
+ QLocale *locale = getThisLocale(ctx);
+ if (!locale)
+ return QV4::Encode::undefined();
+ int fdow = int(locale->firstDayOfWeek());
if (fdow == 7)
fdow = 0; // Qt::Sunday = 7, but Sunday is 0 in JS Date
return QV4::Encode(fdow);
}
-QV4::ReturnedValue QQmlLocaleData::method_get_measurementSystem(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlLocaleData::method_get_measurementSystem(QV4::CallContext *ctx)
{
- QLocale locale = getThisLocale(ctx);
- return QV4::Encode(locale.measurementSystem());
+ QLocale *locale = getThisLocale(ctx);
+ if (!locale)
+ return QV4::Encode::undefined();
+ return QV4::Encode(locale->measurementSystem());
}
-QV4::ReturnedValue QQmlLocaleData::method_get_textDirection(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlLocaleData::method_get_textDirection(QV4::CallContext *ctx)
{
- QLocale locale = getThisLocale(ctx);
- return QV4::Encode(locale.textDirection());
+ QLocale *locale = getThisLocale(ctx);
+ if (!locale)
+ return QV4::Encode::undefined();
+
+ return QV4::Encode(locale->textDirection());
}
-QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QLocale locale = getThisLocale(ctx);
- QList<Qt::DayOfWeek> days = locale.weekdays();
+ QLocale *locale = getThisLocale(ctx);
+ if (!locale)
+ return QV4::Encode::undefined();
+
+ QList<Qt::DayOfWeek> days = locale->weekdays();
QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject());
result->arrayReserve(days.size());
@@ -555,11 +567,14 @@ QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::SimpleCallContext *c
return result.asReturnedValue();
}
-QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QLocale locale = getThisLocale(ctx);
- QStringList langs = locale.uiLanguages();
+ QLocale *locale = getThisLocale(ctx);
+ if (!locale)
+ return QV4::Encode::undefined();
+
+ QStringList langs = locale->uiLanguages();
QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject());
result->arrayReserve(langs.size());
for (int i = 0; i < langs.size(); ++i) {
@@ -572,9 +587,12 @@ QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::SimpleCallContext
return result.asReturnedValue();
}
-QV4::ReturnedValue QQmlLocaleData::method_currencySymbol(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlLocaleData::method_currencySymbol(QV4::CallContext *ctx)
{
- QLocale locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(ctx);
+ if (!locale)
+ return QV4::Encode::undefined();
+
if (ctx->callData->argc > 1)
V4THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
@@ -584,12 +602,14 @@ QV4::ReturnedValue QQmlLocaleData::method_currencySymbol(QV4::SimpleCallContext
format = QLocale::CurrencySymbolFormat(intFormat);
}
- return ctx->engine->newString(locale.currencySymbol(format))->asReturnedValue();
+ return ctx->engine->newString(locale->currencySymbol(format))->asReturnedValue();
}
#define LOCALE_FORMAT(FUNC) \
-QV4::ReturnedValue QQmlLocaleData::method_ ##FUNC (QV4::SimpleCallContext *ctx) { \
- QLocale locale = getThisLocale(ctx); \
+QV4::ReturnedValue QQmlLocaleData::method_ ##FUNC (QV4::CallContext *ctx) { \
+ QLocale *locale = getThisLocale(ctx); \
+ if (!locale) \
+ return QV4::Encode::undefined(); \
if (ctx->callData->argc > 1) \
V4THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
QLocale::FormatType format = QLocale::LongFormat;\
@@ -597,7 +617,7 @@ QV4::ReturnedValue QQmlLocaleData::method_ ##FUNC (QV4::SimpleCallContext *ctx)
quint32 intFormat = ctx->callData->args[0].toUInt32(); \
format = QLocale::FormatType(intFormat); \
} \
- return ctx->engine->newString(locale. FUNC (format))->asReturnedValue(); \
+ return ctx->engine->newString(locale-> FUNC (format))->asReturnedValue(); \
}
LOCALE_FORMAT(dateTimeFormat)
@@ -606,8 +626,10 @@ LOCALE_FORMAT(dateFormat)
// +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
#define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \
-QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::SimpleCallContext *ctx) {\
- QLocale locale = getThisLocale(ctx); \
+QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {\
+ QLocale *locale = getThisLocale(ctx); \
+ if (!locale) \
+ return QV4::Encode::undefined(); \
if (ctx->callData->argc < 1 || ctx->callData->argc > 2) \
V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
@@ -619,20 +641,22 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::SimpleCallContext *
if (ctx->callData->args[1].isNumber()) { \
quint32 intFormat = ctx->callData->args[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
- name = locale. VARIABLE(idx, format); \
+ name = locale-> VARIABLE(idx, format); \
} else { \
V4THROW_ERROR("Locale: Invalid datetime format"); \
} \
} else { \
- name = locale. VARIABLE(idx, enumFormat); \
+ name = locale-> VARIABLE(idx, enumFormat); \
} \
return ctx->engine->newString(name)->asReturnedValue(); \
}
// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
#define LOCALE_FORMATTED_DAYNAME(VARIABLE) \
-QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::SimpleCallContext *ctx) {\
- QLocale locale = getThisLocale(ctx); \
+QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {\
+ QLocale *locale = getThisLocale(ctx); \
+ if (!locale) \
+ return QV4::Encode::undefined(); \
if (ctx->callData->argc < 1 || ctx->callData->argc > 2) \
V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
@@ -645,12 +669,12 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::SimpleCallContext *
if (ctx->callData->args[1].isNumber()) { \
quint32 intFormat = ctx->callData->args[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
- name = locale. VARIABLE(idx, format); \
+ name = locale-> VARIABLE(idx, format); \
} else { \
V4THROW_ERROR("Locale: Invalid datetime format"); \
} \
} else { \
- name = locale. VARIABLE(idx, enumFormat); \
+ name = locale-> VARIABLE(idx, enumFormat); \
} \
return ctx->engine->newString(name)->asReturnedValue(); \
}
@@ -660,10 +684,12 @@ LOCALE_FORMATTED_MONTHNAME(standaloneMonthName)
LOCALE_FORMATTED_DAYNAME(dayName)
LOCALE_FORMATTED_DAYNAME(standaloneDayName)
-#define LOCALE_STRING_PROPERTY(VARIABLE) QV4::ReturnedValue QQmlLocaleData::method_get_ ## VARIABLE (QV4::SimpleCallContext* ctx) \
+#define LOCALE_STRING_PROPERTY(VARIABLE) QV4::ReturnedValue QQmlLocaleData::method_get_ ## VARIABLE (QV4::CallContext* ctx) \
{ \
- QLocale locale = getThisLocale(ctx); \
- return ctx->engine->newString(locale. VARIABLE())->asReturnedValue();\
+ QLocale *locale = getThisLocale(ctx); \
+ if (!locale) \
+ return QV4::Encode::undefined(); \
+ return ctx->engine->newString(locale-> VARIABLE())->asReturnedValue();\
}
LOCALE_STRING_PROPERTY(name)
@@ -849,7 +875,7 @@ void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
engine->stringClass->prototype->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare);
}
-QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 1 || (!ctx->callData->args[0].isString() && !ctx->callData->args[0].asStringObject()))
return QV4::StringPrototype::method_localeCompare(ctx);
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 8075bd462f..8ca67a8c83 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -58,13 +58,13 @@ public:
static void registerExtension(QV4::ExecutionEngine *engine);
private:
- static QV4::ReturnedValue method_toLocaleString(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_toLocaleTimeString(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_toLocaleDateString(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleString(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleTimeString(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleDateString(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_timeZoneUpdated(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_toLocaleString(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_toLocaleTimeString(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_toLocaleDateString(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_fromLocaleString(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_fromLocaleTimeString(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_fromLocaleDateString(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_timeZoneUpdated(QV4::CallContext *ctx);
};
@@ -74,9 +74,9 @@ public:
static void registerExtension(QV4::ExecutionEngine *engine);
private:
- static QV4::ReturnedValue method_toLocaleString(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleString(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_toLocaleCurrencyString(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_toLocaleString(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_fromLocaleString(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_toLocaleCurrencyString(QV4::CallContext *ctx);
};
@@ -125,7 +125,7 @@ public:
private:
QQmlLocale();
- static QV4::ReturnedValue method_localeCompare(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_localeCompare(QV4::CallContext *ctx);
};
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 342d1dc69c..ed0c0afd6f 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -225,17 +225,21 @@ public:
void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
{
QV4::ExecutionEngine *v4 = QV8Engine::getV4(e->handle());
- v4->pushGlobalContext();
if (scriptCallback && scriptApi(e).isUndefined()) {
+ v4->pushGlobalContext();
setScriptApi(e, scriptCallback(e, e));
+ v4->popContext();
} else if (qobjectCallback && !qobjectApi(e)) {
+ v4->pushGlobalContext();
setQObjectApi(e, qobjectCallback(e, e));
+ v4->popContext();
} else if (!url.isEmpty() && !qobjectApi(e)) {
+ v4->pushGlobalContext();
QQmlComponent component(e, url, QQmlComponent::PreferSynchronous);
QObject *o = component.create();
setQObjectApi(e, o);
+ v4->popContext();
}
- v4->popContext();
}
void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 56776dcb82..3798129e8b 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -525,8 +525,14 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
context->setIdPropertyData(mapping);
if (subComponentIndex == -1) {
- foreach (QQmlScriptData *script, compiledData->scripts)
- context->importedScripts << script->scriptValueForContext(context);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Scope scope(v4);
+ QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count()));
+ for (int i = 0; i < compiledData->scripts.count(); ++i) {
+ QQmlScriptData *s = compiledData->scripts.at(i);
+ scripts->putIndexed(i, s->scriptValueForContext(context));
+ }
+ context->importedScripts = scripts;
} else if (parentContext) {
context->importedScripts = parentContext->importedScripts;
}
@@ -1004,8 +1010,7 @@ void QmlObjectCreator::setupBindings()
bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingIndex, const QV4::CompiledData::Binding *binding)
{
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(binding->value.objectIndex);
- Q_ASSERT(stringAt(obj->inheritedTypeNameIndex).isEmpty());
+ Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
QQmlType *attachedType = resolvedTypes.value(binding->propertyNameIndex).type;
const int id = attachedType->attachedPropertiesId();
QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject);
@@ -1260,7 +1265,7 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
}
QQmlData *ddata = QQmlData::get(instance, /*create*/true);
- if (index == qmlUnit->indexOfRootObject) {
+ if (static_cast<quint32>(index) == qmlUnit->indexOfRootObject) {
if (ddata->context) {
Q_ASSERT(ddata->context != context);
Q_ASSERT(ddata->outerContext);
@@ -1427,7 +1432,7 @@ bool QQmlComponentAndAliasResolver::resolve()
// when someProperty _is_ a QQmlComponent. In that case the Item {}
// should be implicitly surrounded by Component {}
- for (int i = 0; i < qmlUnit->nObjects; ++i) {
+ for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
continue;
@@ -1511,14 +1516,14 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
}
const QV4::CompiledData::Property *property = obj->propertyTable();
- for (int i = 0; i < obj->nProperties; ++i, ++property)
+ for (quint32 i = 0; i < obj->nProperties; ++i, ++property)
if (property->type == QV4::CompiledData::Property::Alias) {
_objectsWithAliases.append(objectIndex);
break;
}
const QV4::CompiledData::Binding *binding = obj->bindingTable();
- for (int i = 0; i < obj->nBindings; ++i, ++binding) {
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
if (binding->type != QV4::CompiledData::Binding::Type_Object
&& binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
@@ -1694,7 +1699,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(const QUrl &url, const QV4::Compile
bool QQmlPropertyValidator::validate()
{
- for (int i = 0; i < qmlUnit->nObjects; ++i) {
+ for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
continue;
@@ -1718,7 +1723,7 @@ bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj,
QQmlPropertyData *defaultProperty = propertyCache->defaultProperty();
const QV4::CompiledData::Binding *binding = obj->bindingTable();
- for (int i = 0; i < obj->nBindings; ++i, ++binding) {
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty
|| binding->type == QV4::CompiledData::Binding::Type_GroupProperty)
continue;
@@ -1754,4 +1759,6 @@ bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj,
}
}
}
+
+ return true;
}
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 7723404831..3975b88bb0 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1485,7 +1485,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
if (result->isInteger())
QUICK_STORE(int, result->integerValue())
else if (result->isNumber())
- QUICK_STORE(int, qRound(result->doubleValue()))
+ QUICK_STORE(int, result->doubleValue())
break;
case QMetaType::Double:
if (result->isNumber())
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 2cb944d824..6c40557886 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -1154,7 +1154,7 @@ QString QQmlPropertyCache::signalParameterStringForJS(QQmlEngine *engine, const
if (errorString)
*errorString = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter.");
return QString();
- } else if (illegalNames.contains(param)) {
+ } else if (illegalNames.contains(QString::fromUtf8(param))) {
if (errorString)
*errorString = QCoreApplication::translate("QQmlRewrite", "Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param));
return QString();
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
index 9fd06aa934..6cb23ec07c 100644
--- a/src/qml/qml/qqmlscript.cpp
+++ b/src/qml/qml/qqmlscript.cpp
@@ -500,7 +500,7 @@ public:
protected:
- QQmlScript::Object *defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment,
+ QQmlScript::Object *defineObjectBinding(AST::Node *node, AST::UiQualifiedId *propertyName, bool onAssignment,
const QString &objectType,
AST::SourceLocation typeLocation,
LocationSpan location,
@@ -659,7 +659,8 @@ QString ProcessAST::asString(AST::UiQualifiedId *node) const
}
QQmlScript::Object *
-ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName,
+ProcessAST::defineObjectBinding(AST::Node *node,
+ AST::UiQualifiedId *propertyName,
bool onAssignment,
const QString &objectType,
AST::SourceLocation typeLocation,
@@ -731,6 +732,7 @@ ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName,
obj->type = _parser->findOrCreateTypeId(objectType, obj);
obj->typeReference = _parser->_refTypes.at(obj->type);
obj->location = location;
+ obj->astNode = node;
if (propertyCount) {
Property *prop = currentProperty();
@@ -1130,7 +1132,7 @@ bool ProcessAST::visit(AST::UiObjectDefinition *node)
const QString objectType = asString(node->qualifiedTypeNameId);
const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
- defineObjectBinding(/*propertyName = */ 0, false, objectType,
+ defineObjectBinding(node, /*propertyName = */ 0, false, objectType,
typeLocation, l, node->initializer);
return false;
@@ -1146,7 +1148,7 @@ bool ProcessAST::visit(AST::UiObjectBinding *node)
const QString objectType = asString(node->qualifiedTypeNameId);
const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
- defineObjectBinding(node->qualifiedId, node->hasOnToken, objectType,
+ defineObjectBinding(node, node->qualifiedId, node->hasOnToken, objectType,
typeLocation, l, node->initializer);
return false;
diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h
index 86bbc1fb3a..fac31add5c 100644
--- a/src/qml/qml/qqmlscript_p.h
+++ b/src/qml/qml/qqmlscript_p.h
@@ -229,6 +229,7 @@ public:
// Used by compiler
struct SignalData {
int signalExpressionContextStack;
+ Object *signalScopeObject;
int functionIndex; // before gen() index in functionsToCompile, then index in runtime functions
};
union {
@@ -335,6 +336,8 @@ public:
QQmlPropertyCache *metatype;
+ QQmlJS::AST::Node *astNode; // responsible for the creation of this object
+
// The synthesized metaobject, if QML added signals or properties to
// this type. Otherwise null
QByteArray synthdata; // Generated by compiler
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 601c1b8bdc..911761d9fd 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include "qqmltypeloader_p.h"
-#include "qqmlabstracturlinterceptor.h"
+#include "qqmlabstracturlinterceptor_p.h"
#include "qqmlcontextwrapper_p.h"
#include "qqmlexpression_p.h"
@@ -1341,7 +1341,7 @@ bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQm
Q_ASSERT(errors);
if (pragma.type == QQmlScript::Pragma::Singleton) {
- QUrl myUrl = url();
+ QUrl myUrl = finalUrl();
QQmlType *ret = QQmlMetaType::qmlType(myUrl, true);
if (!ret) {
@@ -1369,7 +1369,7 @@ bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQm
} else {
QQmlError error;
error.setDescription(QLatin1String("Invalid pragma"));
- error.setUrl(url());
+ error.setUrl(finalUrl());
error.setLine(pragma.location.start.line);
error.setColumn(pragma.location.start.column);
errors->prepend(error);
@@ -1801,9 +1801,25 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
Return a QmldirContent for absoluteFilePath. The QmldirContent may be cached.
\a filePath is either a bundle URL, or a local file path.
+
+It can also be a remote path for a remote directory import, but it will have been cached by now in this case.
*/
-const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePath, const QString &uriHint)
-{
+const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn, const QString &uriHint)
+{
+ QUrl url(filePathIn); //May already contain bundle or http scheme
+ if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https"))
+ return *(m_importQmlDirCache.value(filePathIn)); //Can't load the remote here, but should be cached
+ else if (!QQmlFile::isBundle(filePathIn))
+ url = QUrl::fromLocalFile(filePathIn);
+ if (engine() && engine()->urlInterceptor())
+ url = engine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::QmldirFile);
+ Q_ASSERT(url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("bundle"));
+ QString filePath;
+ if (url.scheme() == QLatin1String("file"))
+ filePath = url.toLocalFile();
+ else
+ filePath = url.path();
+
QmldirContent *qmldir;
QmldirContent **val = m_importQmlDirCache.value(filePath);
if (!val) {
@@ -1813,13 +1829,10 @@ const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString
#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
#define CASE_MISMATCH_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File name case mismatch for \"%1\""))
- if (QQmlFile::isBundle(filePath)) {
-
- QUrl url(filePath);
-
+ if (QQmlFile::isBundle(url.toString())) {
QQmlFile file(engine(), url);
if (file.isError()) {
- ERROR(NOT_READABLE_ERROR.arg(filePath));
+ ERROR(NOT_READABLE_ERROR.arg(url.toString()));
} else {
QString content(QString::fromUtf8(file.data(), file.size()));
qmldir->setContent(filePath, content);
@@ -2086,7 +2099,7 @@ void QQmlTypeData::done()
// If the type is CompositeSingleton but there was no pragma Singleton in the
// QML file, lets report an error.
QQmlType *type = QQmlMetaType::qmlType(url(), true);
- if (type && type->isCompositeSingleton() && !m_isSingleton) {
+ if (!isError() && type && type->isCompositeSingleton() && !m_isSingleton) {
QString typeName = type->qmlTypeName();
QQmlError error;
@@ -2141,7 +2154,7 @@ void QQmlTypeData::dataReceived(const Data &data)
if (data.isFile()) preparseData = data.asFile()->metaData(QLatin1String("qml:preparse"));
if (m_useNewCompiler) {
- parsedQML.reset(new QtQml::ParsedQML);
+ parsedQML.reset(new QtQml::ParsedQML(QV8Engine::getV4(typeLoader()->engine())->debugger != 0));
QQmlCodeGenerator compiler;
if (!compiler.generateFromQml(code, finalUrl(), finalUrlString(), parsedQML.data())) {
setError(compiler.errors);
@@ -2307,6 +2320,7 @@ void QQmlTypeData::compile()
m_compiledData->importCache->addref();
QQmlEngine *engine = typeLoader()->engine();
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
for (QHash<int, TypeReference>::ConstIterator resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
resolvedType != end; ++resolvedType) {
@@ -2357,12 +2371,13 @@ void QQmlTypeData::compile()
// Compile JS binding expressions and signal handlers
- JSCodeGen jsCodeGen;
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(finalUrlString(), parsedQML.data());
+ JSCodeGen jsCodeGen(enginePrivate, finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache);
+ QHash<int, QString> expressionNames; // ### TODO
+ const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions, expressionNames);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator));
isel->setUseFastLookups(false);
QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false);
@@ -2389,7 +2404,7 @@ void QQmlTypeData::compile()
m_compiledData->datas.reserve(qmlUnit->nObjects);
m_compiledData->propertyCaches.reserve(qmlUnit->nObjects);
- QQmlPropertyCacheCreator propertyCacheBuilder(QQmlEnginePrivate::get(m_typeLoader->engine()),
+ QQmlPropertyCacheCreator propertyCacheBuilder(enginePrivate,
qmlUnit, m_compiledData->url,
&m_imports, &m_compiledData->resolvedTypes);
@@ -2689,8 +2704,8 @@ QQmlScriptData::QQmlScriptData()
: importCache(0)
, pragmas(QQmlScript::Object::ScriptBlock::None)
, m_loaded(false)
- , m_program(0)
, m_precompiledScript(0)
+ , m_program(0)
{
}
@@ -2769,9 +2784,15 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare
ctxt->engine = parentCtxt->engine; // Fix for QTBUG-21620
}
- for (int ii = 0; ii < scripts.count(); ++ii) {
- ctxt->importedScripts << scripts.at(ii)->scriptData()->scriptValueForContext(ctxt);
+ QV4::ScopedObject scriptsArray(scope);
+ if (ctxt->importedScripts.isNullOrUndefined()) {
+ scriptsArray = v4->newArrayObject(scripts.count());
+ ctxt->importedScripts = scriptsArray;
+ } else {
+ scriptsArray = ctxt->importedScripts;
}
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scriptsArray->putIndexed(ii, scripts.at(ii)->scriptData()->scriptValueForContext(ctxt));
if (!hasEngine())
initialize(parentCtxt->engine);
@@ -2786,11 +2807,10 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare
QV4::QmlContextWrapper::takeContextOwnership(qmlglobal);
QV4::ExecutionContext *ctx = QV8Engine::getV4(v8engine)->current;
- try {
- m_program->qml = qmlglobal;
- m_program->run();
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ m_program->qml = qmlglobal;
+ m_program->run();
+ if (scope.engine->hasException) {
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
if (error.isValid())
ep->warning(error);
}
@@ -2921,7 +2941,7 @@ void QQmlScriptBlob::done()
QList<QQmlError> errors;
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
- m_scriptData->m_precompiledScript = QV4::Script::precompile(v4, m_scriptData->url, m_source, /*parseAsBinding*/true, &errors);
+ 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();
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index b93cf2942d..c9a5edc39e 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -59,7 +59,6 @@
#include <QtQml/qqmlerror.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlfile.h>
-#include <QtQml/qqmlabstracturlinterceptor.h>
#include <private/qhashedstring_p.h>
#include <private/qqmlscript_p.h>
@@ -68,6 +67,7 @@
#include <private/qqmldirparser_p.h>
#include <private/qqmlbundle_p.h>
#include <private/qflagpointer_p.h>
+#include <private/qqmlabstracturlinterceptor_p.h>
#include <private/qv4value_p.h>
#include <private/qv4script_p.h>
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 87764c49ae..a880bbdd58 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -106,7 +106,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
const Import *i = static_cast<const Import *>(importNamespace);
Q_ASSERT(i->scriptIndex == -1);
- Result result = result = typeSearch(i->modules, name);
+ Result result = typeSearch(i->modules, name);
if (!result.isValid())
result = query(i->compositeSingletons, name);
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index de2386daf1..258442bc1d 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -69,6 +69,11 @@ QmlTypeWrapper::~QmlTypeWrapper()
typeNamespace->release();
}
+bool QmlTypeWrapper::isSingleton() const
+{
+ return type && type->isSingleton();
+}
+
QVariant QmlTypeWrapper::toVariant() const
{
if (type && type->isSingleton()) {
@@ -121,7 +126,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
Scoped<QmlTypeWrapper> w(scope, m->as<QmlTypeWrapper>());
if (!w)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
if (hasProperty)
@@ -202,9 +207,8 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
if (r.type) {
return create(w->v8, object, r.type, w->mode);
} else if (r.scriptIndex != -1) {
- int index = r.scriptIndex;
- if (index < context->importedScripts.count())
- return context->importedScripts.at(index).value();
+ QV4::ScopedObject scripts(scope, context->importedScripts);
+ return scripts->getIndexed(r.scriptIndex);
} else if (r.importNamespace) {
return create(w->v8, object, context->imports, r.importNamespace);
}
@@ -229,8 +233,12 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
{
QmlTypeWrapper *w = m->as<QmlTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
- if (!w)
+ if (v4->hasException)
+ return;
+ if (!w) {
v4->current->throwTypeError();
+ return;
+ }
QV4::Scope scope(v4);
QV8Engine *v8engine = v4->v8Engine;
@@ -255,6 +263,7 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
if (!apiprivate) {
QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
v4->current->throwError(error);
+ return;
} else {
apiprivate->put(name, value);
}
@@ -277,4 +286,15 @@ void QmlTypeWrapper::destroy(Managed *that)
static_cast<QmlTypeWrapper *>(that)->~QmlTypeWrapper();
}
+bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
+{
+ QV4::QmlTypeWrapper *qmlTypeWrapperA = a->asObject()->as<QV4::QmlTypeWrapper>();
+ if (QV4::QmlTypeWrapper *qmlTypeWrapperB = b->asObject()->as<QV4::QmlTypeWrapper>())
+ return qmlTypeWrapperA->toVariant() == qmlTypeWrapperB->toVariant();
+ else if (QV4::QObjectWrapper *qobjectWrapper = b->as<QV4::QObjectWrapper>())
+ return qmlTypeWrapperA->toVariant().value<QObject*>() == qobjectWrapper->object();
+
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 9078c184c6..ee462d6479 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -76,6 +76,8 @@ private:
public:
enum TypeNameMode { IncludeEnums, ExcludeEnums };
+ bool isSingleton() const;
+
QVariant toVariant() const;
static ReturnedValue create(QV8Engine *, QObject *, QQmlType *, TypeNameMode = IncludeEnums);
@@ -87,6 +89,9 @@ public:
static PropertyAttributes query(const Managed *, StringRef name);
static void destroy(Managed *that);
+protected:
+ static bool isEqualTo(Managed *that, Managed *o);
+
private:
QV8Engine *v8;
TypeNameMode mode;
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 6477f63daf..d733694923 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -208,8 +208,10 @@ PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, StringRef name)
{
const QmlValueTypeWrapper *r = m->as<const QmlValueTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
- if (!r)
+ if (!r) {
v4->current->throwTypeError();
+ return PropertyAttributes();
+ }
QQmlPropertyData local;
QQmlPropertyData *result = 0;
@@ -242,14 +244,14 @@ bool QmlValueTypeWrapper::isEqual(const QVariant& value)
}
}
-ReturnedValue QmlValueTypeWrapper::method_toString(SimpleCallContext *ctx)
+ReturnedValue QmlValueTypeWrapper::method_toString(CallContext *ctx)
{
Object *o = ctx->callData->thisObject.asObject();
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QmlValueTypeWrapper *w = o->as<QmlValueTypeWrapper>();
if (!w)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (w->objectType == QmlValueTypeWrapper::Reference) {
QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(w);
@@ -271,7 +273,7 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h
QmlValueTypeWrapper *r = m->as<QmlValueTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
if (!r)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
// Note: readReferenceValue() can change the reference->type.
if (r->objectType == QmlValueTypeWrapper::Reference) {
@@ -332,9 +334,14 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
{
ExecutionEngine *v4 = m->engine();
Scope scope(v4);
+ if (scope.hasException())
+ return;
+
Scoped<QmlValueTypeWrapper> r(scope, m->as<QmlValueTypeWrapper>());
- if (!r)
+ if (!r) {
v4->current->throwTypeError();
+ return;
+ }
QByteArray propName = name->toQString().toUtf8();
if (r->objectType == QmlValueTypeWrapper::Reference) {
@@ -359,6 +366,7 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
QString error = QLatin1String("Cannot assign JavaScript function to value-type property");
Scoped<String> e(scope, r->v8->toString(error));
v4->current->throwError(e);
+ return;
}
QQmlContextData *context = r->v8->callingContext();
@@ -377,8 +385,6 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
newBinding = new QQmlBinding(value, reference->object, context,
frame.source, qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
newBinding->setTarget(reference->object, cacheData, context);
- newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
- QQmlBinding::RequiresThisObject);
}
QQmlAbstractBinding *oldBinding =
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index f2effc362b..9dd3e8dcbe 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -89,7 +89,7 @@ public:
static bool isEqualTo(Managed *m, Managed *other);
static PropertyAttributes query(const Managed *, StringRef name);
- static QV4::ReturnedValue method_toString(SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_toString(CallContext *ctx);
QV8Engine *v8;
ObjectType objectType;
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index c1c05fac11..983136a846 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -400,8 +400,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_STORE_PROVIDER_VALUE(StoreColor, QMetaType::QColor, instr.value);
QML_STORE_VALUE(StoreDate, QDate, QDate::fromJulianDay(instr.value));
QML_STORE_VALUE(StoreDateTime, QDateTime,
- QDateTime(QDate::fromJulianDay(instr.date), *(QTime *)&instr.time));
- QML_STORE_POINTER(StoreTime, (QTime *)&instr.time);
+ QDateTime(QDate::fromJulianDay(instr.date), QTime::fromMSecsSinceStartOfDay(instr.time)));
+ QML_STORE_VALUE(StoreTime, QTime, QTime::fromMSecsSinceStartOfDay(instr.time));
QML_STORE_POINTER(StorePoint, (QPoint *)&instr.point);
QML_STORE_POINTER(StorePointF, (QPointF *)&instr.point);
QML_STORE_POINTER(StoreSize, (QSize *)&instr.size);
@@ -638,7 +638,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_BEGIN_INSTR(CreateSimpleObject)
QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QQmlData));
- ::memset(o, 0, instr.typeSize + sizeof(QQmlData));
+ ::memset(static_cast<void *>(o), 0, instr.typeSize + sizeof(QQmlData));
instr.create(o);
QQmlData *ddata = (QQmlData *)(((const char *)o) + instr.typeSize);
@@ -791,7 +791,13 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_END_INSTR(StoreSignal)
QML_BEGIN_INSTR(StoreImportedScript)
- CTXT->importedScripts << SCRIPTS.at(instr.value)->scriptValueForContext(CTXT);
+ QV4::Scope scope(v4);
+ QV4::ScopedObject scripts(scope, CTXT->importedScripts.value());
+ if (!scripts) {
+ scripts = v4->newArrayObject();
+ CTXT->importedScripts = scripts;
+ }
+ scripts->putIndexed(instr.value, SCRIPTS.at(instr.value)->scriptValueForContext(CTXT));
QML_END_INSTR(StoreImportedScript)
QML_BEGIN_INSTR(StoreScriptString)
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 5752033744..4b34792421 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -82,7 +82,8 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
}
}
- m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0);
+ if (!QQmlData::wasDeleted(m_target->object))
+ m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0);
}
}
@@ -956,14 +957,14 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
QV4::ScopedValue result(scope);
QV4::ExecutionContext *ctx = function->engine()->current;
- try {
- result = function->call(callData);
- if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ result = function->call(callData);
+ if (scope.hasException()) {
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
if (error.isValid())
ep->warning(error);
if (a[0]) *(QVariant *)a[0] = QVariant();
+ } else {
+ if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -1231,9 +1232,9 @@ void QQmlVMEMetaObject::ensureQObjectWrapper()
QV4::QObjectWrapper::wrap(v4, object);
}
-void QQmlVMEMetaObject::mark()
+void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e)
{
- varProperties.markOnce();
+ varProperties.markOnce(e);
// add references created by VMEVariant properties
int maxDataIdx = metaData->propertyCount - metaData->varPropertyCount;
@@ -1244,13 +1245,13 @@ void QQmlVMEMetaObject::mark()
if (ref) {
QQmlData *ddata = QQmlData::get(ref);
if (ddata)
- ddata->jsWrapper.markOnce();
+ ddata->jsWrapper.markOnce(e);
}
}
}
if (QQmlVMEMetaObject *parent = parentVMEMetaObject())
- parent->mark();
+ parent->mark(e);
}
void QQmlVMEMetaObject::allocateVarPropertiesArray()
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 25a577d2e6..a9a0308ded 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -209,7 +209,7 @@ public:
void ensureQObjectWrapper();
- void mark();
+ void mark(QV4::ExecutionEngine *e);
void connectAlias(int aliasId);
QBitArray aConnected;
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index aff0cf2b59..18e3e33c4b 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -73,7 +73,7 @@ using namespace QV4;
#define V4THROW_REFERENCE(string) { \
Scoped<Object> error(scope, ctx->engine->newReferenceErrorObject(QStringLiteral(string))); \
- ctx->throwError(error); \
+ return ctx->throwError(error); \
}
QT_BEGIN_NAMESPACE
@@ -189,8 +189,8 @@ class NamedNodeMap : public Object
public:
NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list)
: Object(engine)
- , d(data)
, list(list)
+ , d(data)
{
vtbl = &static_vtbl;
@@ -279,24 +279,24 @@ public:
static void initClass(ExecutionEngine *engine);
// JS API
- static ReturnedValue method_get_nodeName(SimpleCallContext *ctx);
- static ReturnedValue method_get_nodeValue(SimpleCallContext *ctx);
- static ReturnedValue method_get_nodeType(SimpleCallContext *ctx);
-
- static ReturnedValue method_get_parentNode(SimpleCallContext *ctx);
- static ReturnedValue method_get_childNodes(SimpleCallContext *ctx);
- static ReturnedValue method_get_firstChild(SimpleCallContext *ctx);
- static ReturnedValue method_get_lastChild(SimpleCallContext *ctx);
- static ReturnedValue method_get_previousSibling(SimpleCallContext *ctx);
- static ReturnedValue method_get_nextSibling(SimpleCallContext *ctx);
- static ReturnedValue method_get_attributes(SimpleCallContext *ctx);
-
- //static ReturnedValue ownerDocument(SimpleCallContext *ctx);
- //static ReturnedValue namespaceURI(SimpleCallContext *ctx);
- //static ReturnedValue prefix(SimpleCallContext *ctx);
- //static ReturnedValue localName(SimpleCallContext *ctx);
- //static ReturnedValue baseURI(SimpleCallContext *ctx);
- //static ReturnedValue textContent(SimpleCallContext *ctx);
+ static ReturnedValue method_get_nodeName(CallContext *ctx);
+ static ReturnedValue method_get_nodeValue(CallContext *ctx);
+ static ReturnedValue method_get_nodeType(CallContext *ctx);
+
+ static ReturnedValue method_get_parentNode(CallContext *ctx);
+ static ReturnedValue method_get_childNodes(CallContext *ctx);
+ static ReturnedValue method_get_firstChild(CallContext *ctx);
+ static ReturnedValue method_get_lastChild(CallContext *ctx);
+ static ReturnedValue method_get_previousSibling(CallContext *ctx);
+ static ReturnedValue method_get_nextSibling(CallContext *ctx);
+ static ReturnedValue method_get_attributes(CallContext *ctx);
+
+ //static ReturnedValue ownerDocument(CallContext *ctx);
+ //static ReturnedValue namespaceURI(CallContext *ctx);
+ //static ReturnedValue prefix(CallContext *ctx);
+ //static ReturnedValue localName(CallContext *ctx);
+ //static ReturnedValue baseURI(CallContext *ctx);
+ //static ReturnedValue textContent(CallContext *ctx);
static ReturnedValue getProto(ExecutionEngine *v4);
@@ -352,12 +352,12 @@ class Attr : public Node
{
public:
// JS API
- static ReturnedValue method_name(SimpleCallContext *ctx);
-// static ReturnedValue specified(SimpleCallContext *);
- static ReturnedValue method_value(SimpleCallContext *ctx);
- static ReturnedValue method_ownerElement(SimpleCallContext *ctx);
-// static ReturnedValue schemaTypeInfo(SimpleCallContext *);
-// static ReturnedValue isId(SimpleCallContext *c);
+ static ReturnedValue method_name(CallContext *ctx);
+// static ReturnedValue specified(CallContext *);
+ static ReturnedValue method_value(CallContext *ctx);
+ static ReturnedValue method_ownerElement(CallContext *ctx);
+// static ReturnedValue schemaTypeInfo(CallContext *);
+// static ReturnedValue isId(CallContext *c);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -367,7 +367,7 @@ class CharacterData : public Node
{
public:
// JS API
- static ReturnedValue method_length(SimpleCallContext *ctx);
+ static ReturnedValue method_length(CallContext *ctx);
// C++ API
static ReturnedValue prototype(ExecutionEngine *v4);
@@ -377,8 +377,8 @@ class Text : public CharacterData
{
public:
// JS API
- static ReturnedValue method_isElementContentWhitespace(SimpleCallContext *ctx);
- static ReturnedValue method_wholeText(SimpleCallContext *ctx);
+ static ReturnedValue method_isElementContentWhitespace(CallContext *ctx);
+ static ReturnedValue method_wholeText(CallContext *ctx);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -395,10 +395,10 @@ class Document : public Node
{
public:
// JS API
- static ReturnedValue method_xmlVersion(SimpleCallContext *ctx);
- static ReturnedValue method_xmlEncoding(SimpleCallContext *ctx);
- static ReturnedValue method_xmlStandalone(SimpleCallContext *ctx);
- static ReturnedValue method_documentElement(SimpleCallContext *ctx);
+ static ReturnedValue method_xmlVersion(CallContext *ctx);
+ static ReturnedValue method_xmlEncoding(CallContext *ctx);
+ static ReturnedValue method_xmlStandalone(CallContext *ctx);
+ static ReturnedValue method_documentElement(CallContext *ctx);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -417,12 +417,12 @@ void NodeImpl::release()
document->release();
}
-ReturnedValue NodePrototype::method_get_nodeName(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QString name;
switch (r->d->type) {
@@ -442,12 +442,12 @@ ReturnedValue NodePrototype::method_get_nodeName(SimpleCallContext *ctx)
return Encode(ctx->engine->newString(name));
}
-ReturnedValue NodePrototype::method_get_nodeValue(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (r->d->type == NodeImpl::Document ||
r->d->type == NodeImpl::DocumentFragment ||
@@ -461,22 +461,22 @@ ReturnedValue NodePrototype::method_get_nodeValue(SimpleCallContext *ctx)
return Encode(ctx->engine->newString(r->d->data));
}
-ReturnedValue NodePrototype::method_get_nodeType(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return Encode(r->d->type);
}
-ReturnedValue NodePrototype::method_get_parentNode(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV8Engine *engine = ctx->engine->v8Engine;
@@ -486,24 +486,24 @@ ReturnedValue NodePrototype::method_get_parentNode(SimpleCallContext *ctx)
return Encode::null();
}
-ReturnedValue NodePrototype::method_get_childNodes(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_childNodes(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV8Engine *engine = ctx->engine->v8Engine;
return NodeList::create(engine, r->d);
}
-ReturnedValue NodePrototype::method_get_firstChild(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV8Engine *engine = ctx->engine->v8Engine;
@@ -513,12 +513,12 @@ ReturnedValue NodePrototype::method_get_firstChild(SimpleCallContext *ctx)
return Node::create(engine, r->d->children.first());
}
-ReturnedValue NodePrototype::method_get_lastChild(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV8Engine *engine = ctx->engine->v8Engine;
@@ -528,12 +528,12 @@ ReturnedValue NodePrototype::method_get_lastChild(SimpleCallContext *ctx)
return Node::create(engine, r->d->children.last());
}
-ReturnedValue NodePrototype::method_get_previousSibling(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV8Engine *engine = ctx->engine->v8Engine;
@@ -552,12 +552,12 @@ ReturnedValue NodePrototype::method_get_previousSibling(SimpleCallContext *ctx)
return Encode::null();
}
-ReturnedValue NodePrototype::method_get_nextSibling(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV8Engine *engine = ctx->engine->v8Engine;
@@ -576,12 +576,12 @@ ReturnedValue NodePrototype::method_get_nextSibling(SimpleCallContext *ctx)
return Encode::null();
}
-ReturnedValue NodePrototype::method_get_attributes(SimpleCallContext *ctx)
+ReturnedValue NodePrototype::method_get_attributes(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
if (!r)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV8Engine *engine = ctx->engine->v8Engine;
@@ -608,7 +608,6 @@ ReturnedValue Node::create(QV8Engine *engine, NodeImpl *data)
ExecutionEngine *v4 = QV8Engine::getV4(engine);
Scope scope(v4);
- QQmlXMLHttpRequestData *d = xhrdata(engine);
Scoped<Node> instance(scope, new (v4->memoryManager) Node(v4, data));
ScopedObject p(scope);
@@ -671,7 +670,7 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine)
return d->attrPrototype.value();
}
-ReturnedValue Attr::method_name(SimpleCallContext *ctx)
+ReturnedValue Attr::method_name(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -682,7 +681,7 @@ ReturnedValue Attr::method_name(SimpleCallContext *ctx)
return engine->toString(r->d->name);
}
-ReturnedValue Attr::method_value(SimpleCallContext *ctx)
+ReturnedValue Attr::method_value(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -693,7 +692,7 @@ ReturnedValue Attr::method_value(SimpleCallContext *ctx)
return engine->toString(r->d->data);
}
-ReturnedValue Attr::method_ownerElement(SimpleCallContext *ctx)
+ReturnedValue Attr::method_ownerElement(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -704,7 +703,7 @@ ReturnedValue Attr::method_ownerElement(SimpleCallContext *ctx)
return Node::create(engine, r->d->parent);
}
-ReturnedValue CharacterData::method_length(SimpleCallContext *ctx)
+ReturnedValue CharacterData::method_length(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -731,7 +730,7 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
return d->characterDataPrototype.value();
}
-ReturnedValue Text::method_isElementContentWhitespace(SimpleCallContext *ctx)
+ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -740,7 +739,7 @@ ReturnedValue Text::method_isElementContentWhitespace(SimpleCallContext *ctx)
return Encode(r->d->data.trimmed().isEmpty());
}
-ReturnedValue Text::method_wholeText(SimpleCallContext *ctx)
+ReturnedValue Text::method_wholeText(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -907,7 +906,7 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty
QV4::ExecutionEngine *v4 = m->engine();
NamedNodeMap *r = m->as<NamedNodeMap>();
if (!r)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
QV8Engine *engine = v4->v8Engine;
@@ -926,7 +925,7 @@ ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasPrope
NamedNodeMap *r = m->as<NamedNodeMap>();
QV4::ExecutionEngine *v4 = m->engine();
if (!r)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
name->makeIdentifier();
if (name->equals(v4->id_length))
@@ -962,7 +961,7 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty)
QV4::ExecutionEngine *v4 = m->engine();
NodeList *r = m->as<NodeList>();
if (!r)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
QV8Engine *engine = v4->v8Engine;
@@ -981,7 +980,7 @@ ReturnedValue NodeList::get(Managed *m, const StringRef name, bool *hasProperty)
QV4::ExecutionEngine *v4 = m->engine();
NodeList *r = m->as<NodeList>();
if (!r)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
name->makeIdentifier();
@@ -992,14 +991,13 @@ ReturnedValue NodeList::get(Managed *m, const StringRef name, bool *hasProperty)
ReturnedValue NodeList::create(QV8Engine *engine, NodeImpl *data)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
ExecutionEngine *v4 = QV8Engine::getV4(engine);
Scope scope(v4);
Scoped<NodeList> instance(scope, new (v4->memoryManager) NodeList(v4, data));
return instance.asReturnedValue();
}
-ReturnedValue Document::method_documentElement(SimpleCallContext *ctx)
+ReturnedValue Document::method_documentElement(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -1010,7 +1008,7 @@ ReturnedValue Document::method_documentElement(SimpleCallContext *ctx)
return Node::create(engine, static_cast<DocumentImpl *>(r->d)->root);
}
-ReturnedValue Document::method_xmlStandalone(SimpleCallContext *ctx)
+ReturnedValue Document::method_xmlStandalone(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -1021,7 +1019,7 @@ ReturnedValue Document::method_xmlStandalone(SimpleCallContext *ctx)
return Encode(static_cast<DocumentImpl *>(r->d)->isStandalone);
}
-ReturnedValue Document::method_xmlVersion(SimpleCallContext *ctx)
+ReturnedValue Document::method_xmlVersion(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -1032,7 +1030,7 @@ ReturnedValue Document::method_xmlVersion(SimpleCallContext *ctx)
return engine->toString(static_cast<DocumentImpl *>(r->d)->version);
}
-ReturnedValue Document::method_xmlEncoding(SimpleCallContext *ctx)
+ReturnedValue Document::method_xmlEncoding(CallContext *ctx)
{
Scope scope(ctx);
Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
@@ -1108,6 +1106,7 @@ private:
void setMe(const ValueRef me);
PersistentValue m_me;
+ void dispatchCallbackImpl(const ValueRef me);
void dispatchCallback(const ValueRef me);
int m_status;
@@ -1534,45 +1533,57 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
return m_responseEntityBody;
}
-void QQmlXMLHttpRequest::dispatchCallback(const ValueRef me)
+void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me)
{
ExecutionContext *ctx = v4->current;
QV4::Scope scope(v4);
- try {
- Scoped<Object> o(scope, me);
- if (!o)
- ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject"));
-
- ScopedString s(scope, v4->newString(QStringLiteral("ThisObject")));
- Scoped<Object> thisObj(scope, o->get(s));
- if (!thisObj)
- ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject"));
-
- s = v4->newString(QStringLiteral("onreadystatechange"));
- Scoped<FunctionObject> callback(scope, thisObj->get(s));
- if (!callback) {
- // not an error, but no onreadystatechange function to call.
- return;
- }
+ Scoped<Object> o(scope, me);
+ if (!o) {
+ ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject"));
+ return;
+ }
- s = v4->newString(QStringLiteral("ActivationObject"));
- Scoped<Object> activationObject(scope, o->get(s));
- if (!activationObject)
- v4->current->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject"));
+ ScopedString s(scope, v4->newString(QStringLiteral("ThisObject")));
+ Scoped<Object> thisObj(scope, o->get(s));
+ if (!thisObj) {
+ ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject"));
+ return;
+ }
- QQmlContextData *callingContext = QmlContextWrapper::getContext(activationObject);
- if (callingContext) {
- QV4::ScopedCallData callData(scope, 0);
- callData->thisObject = activationObject.asReturnedValue();
- callback->call(callData);
- }
+ s = v4->newString(QStringLiteral("onreadystatechange"));
+ Scoped<FunctionObject> callback(scope, thisObj->get(s));
+ if (!callback) {
+ // not an error, but no onreadystatechange function to call.
+ return;
+ }
+
+ s = v4->newString(QStringLiteral("ActivationObject"));
+ Scoped<Object> activationObject(scope, o->get(s));
+ if (!activationObject) {
+ v4->current->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject"));
+ return;
+ }
+
+ QQmlContextData *callingContext = QmlContextWrapper::getContext(activationObject);
+ if (callingContext) {
+ QV4::ScopedCallData callData(scope, 0);
+ callData->thisObject = activationObject.asReturnedValue();
+ callback->call(callData);
+ }
- // if the callingContext object is no longer valid, then it has been
- // deleted explicitly (e.g., by a Loader deleting the itemContext when
- // the source is changed). We do nothing in this case, as the evaluation
- // cannot succeed.
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ // if the callingContext object is no longer valid, then it has been
+ // deleted explicitly (e.g., by a Loader deleting the itemContext when
+ // the source is changed). We do nothing in this case, as the evaluation
+ // cannot succeed.
+
+}
+
+void QQmlXMLHttpRequest::dispatchCallback(const ValueRef me)
+{
+ ExecutionContext *ctx = v4->current;
+ dispatchCallbackImpl(me);
+ if (v4->hasException) {
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v4->v8Engine->engine()), error);
}
}
@@ -1635,17 +1646,17 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
static void destroy(Managed *that) {
that->as<QQmlXMLHttpRequestCtor>()->~QQmlXMLHttpRequestCtor();
}
- static void markObjects(Managed *that) {
+ static void markObjects(Managed *that, ExecutionEngine *e) {
QQmlXMLHttpRequestCtor *c = that->as<QQmlXMLHttpRequestCtor>();
if (c->proto)
- c->proto->mark();
+ c->proto->mark(e);
}
static ReturnedValue construct(Managed *that, QV4::CallData *)
{
Scope scope(that->engine());
Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>());
if (!ctor)
- that->engine()->current->throwTypeError();
+ return that->engine()->current->throwTypeError();
QV8Engine *engine = that->engine()->v8Engine;
QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager());
@@ -1660,18 +1671,18 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
void setupProto();
- static ReturnedValue method_open(SimpleCallContext *ctx);
- static ReturnedValue method_setRequestHeader(SimpleCallContext *ctx);
- static ReturnedValue method_send(SimpleCallContext *ctx);
- static ReturnedValue method_abort(SimpleCallContext *ctx);
- static ReturnedValue method_getResponseHeader(SimpleCallContext *ctx);
- static ReturnedValue method_getAllResponseHeaders(SimpleCallContext *ctx);
+ static ReturnedValue method_open(CallContext *ctx);
+ static ReturnedValue method_setRequestHeader(CallContext *ctx);
+ static ReturnedValue method_send(CallContext *ctx);
+ static ReturnedValue method_abort(CallContext *ctx);
+ static ReturnedValue method_getResponseHeader(CallContext *ctx);
+ static ReturnedValue method_getAllResponseHeaders(CallContext *ctx);
- static ReturnedValue method_get_readyState(SimpleCallContext *ctx);
- static ReturnedValue method_get_status(SimpleCallContext *ctx);
- static ReturnedValue method_get_statusText(SimpleCallContext *ctx);
- static ReturnedValue method_get_responseText(SimpleCallContext *ctx);
- static ReturnedValue method_get_responseXML(SimpleCallContext *ctx);
+ static ReturnedValue method_get_readyState(CallContext *ctx);
+ static ReturnedValue method_get_status(CallContext *ctx);
+ static ReturnedValue method_get_statusText(CallContext *ctx);
+ static ReturnedValue method_get_responseText(CallContext *ctx);
+ static ReturnedValue method_get_responseXML(CallContext *ctx);
Object *proto;
@@ -1711,7 +1722,7 @@ void QQmlXMLHttpRequestCtor::setupProto()
// XMLHttpRequest methods
-ReturnedValue QQmlXMLHttpRequestCtor::method_open(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1761,7 +1772,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(SimpleCallContext *ctx)
return r->open(meObject, method, url);
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1808,7 +1819,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(SimpleCallContext
return Encode::undefined();
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_send(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_send(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1830,7 +1841,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_send(SimpleCallContext *ctx)
return r->send(meObject, data);
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_abort(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_abort(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1842,7 +1853,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_abort(SimpleCallContext *ctx)
return r->abort(meObject);
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1863,7 +1874,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(SimpleCallContext
return engine->toString(r->header(ctx->callData->args[0].toQStringNoThrow()));
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1885,7 +1896,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(SimpleCallCon
}
// XMLHttpRequest properties
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1896,7 +1907,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(SimpleCallContext *c
return Encode(r->readyState());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1914,7 +1925,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(SimpleCallContext *ctx)
return Encode(r->replyStatus());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1934,7 +1945,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(SimpleCallContext *c
return engine->toString(r->replyStatusText());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
@@ -1951,7 +1962,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(SimpleCallContext
return engine->toString(r->responseBody());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(SimpleCallContext *ctx)
+ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx)
{
Scope scope(ctx);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index f9aca08d5a..c80a742af0 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -102,11 +102,11 @@ QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine)
for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
QMetaEnum enumerator = qtMetaObject->enumerator(ii);
for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
- put((str = v4->newString(enumerator.key(jj))), (v = QV4::Primitive::fromInt32(enumerator.value(jj))));
+ put((str = v4->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj))));
}
}
- put((str = v4->newString("Asynchronous")), (v = QV4::Primitive::fromInt32(0)));
- put((str = v4->newString("Synchronous")), (v = QV4::Primitive::fromInt32(1)));
+ put((str = v4->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0)));
+ put((str = v4->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1)));
defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include);
defineDefaultProperty(QStringLiteral("isQtObject"), method_isQtObject);
@@ -158,7 +158,7 @@ QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine)
\qmlmethod bool Qt::isQtObject(object)
Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
*/
-ReturnedValue QtObject::method_isQtObject(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx)
{
if (ctx->callData->argc == 0)
return QV4::Encode(false);
@@ -172,7 +172,7 @@ ReturnedValue QtObject::method_isQtObject(QV4::SimpleCallContext *ctx)
Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
All components should be in the range 0-1 inclusive.
*/
-ReturnedValue QtObject::method_rgba(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
{
int argCount = ctx->callData->argc;
if (argCount < 3 || argCount > 4)
@@ -201,7 +201,7 @@ ReturnedValue QtObject::method_rgba(QV4::SimpleCallContext *ctx)
Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
All components should be in the range 0-1 inclusive.
*/
-ReturnedValue QtObject::method_hsla(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx)
{
int argCount = ctx->callData->argc;
if (argCount < 3 || argCount > 4)
@@ -232,7 +232,7 @@ may be either color values or string values. If a string value is supplied it
must be convertible to a color, as described for the \l{colorbasictypedocs}{color}
basic type.
*/
-ReturnedValue QtObject::method_colorEqual(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_colorEqual(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 2)
V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
@@ -272,7 +272,7 @@ Returns a \c rect with the top-left corner at \c x, \c y and the specified \c wi
The returned object has \c x, \c y, \c width and \c height attributes with the given values.
*/
-ReturnedValue QtObject::method_rect(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_rect(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 4)
V4THROW_ERROR("Qt.rect(): Invalid arguments");
@@ -289,7 +289,7 @@ ReturnedValue QtObject::method_rect(QV4::SimpleCallContext *ctx)
\qmlmethod point Qt::point(int x, int y)
Returns a Point with the specified \c x and \c y coordinates.
*/
-ReturnedValue QtObject::method_point(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_point(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 2)
V4THROW_ERROR("Qt.point(): Invalid arguments");
@@ -304,7 +304,7 @@ ReturnedValue QtObject::method_point(QV4::SimpleCallContext *ctx)
\qmlmethod Qt::size(int width, int height)
Returns a Size with the specified \c width and \c height.
*/
-ReturnedValue QtObject::method_size(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_size(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 2)
V4THROW_ERROR("Qt.size(): Invalid arguments");
@@ -323,7 +323,7 @@ key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's
subproperty names, and the values are valid values for each subproperty.
Invalid keys will be ignored.
*/
-ReturnedValue QtObject::method_font(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_font(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 1 || !ctx->callData->args[0].isObject())
V4THROW_ERROR("Qt.font(): Invalid arguments");
@@ -342,7 +342,7 @@ ReturnedValue QtObject::method_font(QV4::SimpleCallContext *ctx)
\qmlmethod Qt::vector2d(real x, real y)
Returns a Vector2D with the specified \c x and \c y.
*/
-ReturnedValue QtObject::method_vector2d(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_vector2d(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 2)
V4THROW_ERROR("Qt.vector2d(): Invalid arguments");
@@ -360,7 +360,7 @@ ReturnedValue QtObject::method_vector2d(QV4::SimpleCallContext *ctx)
\qmlmethod Qt::vector3d(real x, real y, real z)
Returns a Vector3D with the specified \c x, \c y and \c z.
*/
-ReturnedValue QtObject::method_vector3d(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_vector3d(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 3)
V4THROW_ERROR("Qt.vector3d(): Invalid arguments");
@@ -379,7 +379,7 @@ ReturnedValue QtObject::method_vector3d(QV4::SimpleCallContext *ctx)
\qmlmethod Qt::vector4d(real x, real y, real z, real w)
Returns a Vector4D with the specified \c x, \c y, \c z and \c w.
*/
-ReturnedValue QtObject::method_vector4d(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_vector4d(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 4)
V4THROW_ERROR("Qt.vector4d(): Invalid arguments");
@@ -399,7 +399,7 @@ ReturnedValue QtObject::method_vector4d(QV4::SimpleCallContext *ctx)
\qmlmethod Qt::quaternion(real scalar, real x, real y, real z)
Returns a Quaternion with the specified \c scalar, \c x, \c y, and \c z.
*/
-ReturnedValue QtObject::method_quaternion(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_quaternion(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 4)
V4THROW_ERROR("Qt.quaternion(): Invalid arguments");
@@ -422,7 +422,7 @@ Alternatively, the function may be called with a single argument
where that argument is a JavaScript array which contains the sixteen
matrix values.
*/
-ReturnedValue QtObject::method_matrix4x4(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_matrix4x4(QV4::CallContext *ctx)
{
QV8Engine *v8engine = ctx->engine->v8Engine;
@@ -473,7 +473,7 @@ by factor and converts the color back to RGB.
If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
*/
-ReturnedValue QtObject::method_lighter(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_lighter(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 1 && ctx->callData->argc != 2)
V4THROW_ERROR("Qt.lighter(): Invalid arguments");
@@ -512,7 +512,7 @@ by factor and converts the color back to RGB.
If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
*/
-ReturnedValue QtObject::method_darker(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_darker(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 1 && ctx->callData->argc != 2)
V4THROW_ERROR("Qt.darker(): Invalid arguments");
@@ -560,7 +560,7 @@ ReturnedValue QtObject::method_darker(QV4::SimpleCallContext *ctx)
Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
*/
-ReturnedValue QtObject::method_tint(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_tint(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 2)
V4THROW_ERROR("Qt.tint(): Invalid arguments");
@@ -610,7 +610,7 @@ If \a format is not specified, \a date is formatted using
\sa Locale
*/
-ReturnedValue QtObject::method_formatDate(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_formatDate(QV4::CallContext *ctx)
{
if (ctx->callData->argc < 1 || ctx->callData->argc > 2)
V4THROW_ERROR("Qt.formatDate(): Invalid arguments");
@@ -655,7 +655,7 @@ If \a format is not specified, \a time is formatted using
\sa Locale
*/
-ReturnedValue QtObject::method_formatTime(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx)
{
if (ctx->callData->argc < 1 || ctx->callData->argc > 2)
V4THROW_ERROR("Qt.formatTime(): Invalid arguments");
@@ -781,7 +781,7 @@ with the \a format values below to produce the following results:
\sa Locale
*/
-ReturnedValue QtObject::method_formatDateTime(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx)
{
if (ctx->callData->argc < 1 || ctx->callData->argc > 2)
V4THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
@@ -815,7 +815,7 @@ ReturnedValue QtObject::method_formatDateTime(QV4::SimpleCallContext *ctx)
\qmlmethod bool Qt::openUrlExternally(url target)
Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise.
*/
-ReturnedValue QtObject::method_openUrlExternally(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx)
{
if (ctx->callData->argc != 1)
return QV4::Encode(false);
@@ -830,7 +830,7 @@ ReturnedValue QtObject::method_openUrlExternally(QV4::SimpleCallContext *ctx)
\qmlmethod url Qt::resolvedUrl(url url)
Returns \a url resolved relative to the URL of the caller.
*/
-ReturnedValue QtObject::method_resolvedUrl(QV4::SimpleCallContext *ctx)
+ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx)
{
QV8Engine *v8engine = ctx->engine->v8Engine;
@@ -853,7 +853,7 @@ ReturnedValue QtObject::method_resolvedUrl(QV4::SimpleCallContext *ctx)
\qmlmethod list<string> Qt::fontFamilies()
Returns a list of the font families available to the application.
*/
-ReturnedValue QtObject::method_fontFamilies(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_fontFamilies(CallContext *ctx)
{
if (ctx->callData->argc != 0)
V4THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
@@ -866,7 +866,7 @@ ReturnedValue QtObject::method_fontFamilies(SimpleCallContext *ctx)
\qmlmethod string Qt::md5(data)
Returns a hex string of the md5 hash of \c data.
*/
-ReturnedValue QtObject::method_md5(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_md5(CallContext *ctx)
{
if (ctx->callData->argc != 1)
V4THROW_ERROR("Qt.md5(): Invalid arguments");
@@ -880,7 +880,7 @@ ReturnedValue QtObject::method_md5(SimpleCallContext *ctx)
\qmlmethod string Qt::btoa(data)
Binary to ASCII - this function returns a base64 encoding of \c data.
*/
-ReturnedValue QtObject::method_btoa(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_btoa(CallContext *ctx)
{
if (ctx->callData->argc != 1)
V4THROW_ERROR("Qt.btoa(): Invalid arguments");
@@ -894,7 +894,7 @@ ReturnedValue QtObject::method_btoa(SimpleCallContext *ctx)
\qmlmethod string Qt::atob(data)
ASCII to binary - this function returns a base64 decoding of \c data.
*/
-ReturnedValue QtObject::method_atob(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_atob(CallContext *ctx)
{
if (ctx->callData->argc != 1)
V4THROW_ERROR("Qt.atob(): Invalid arguments");
@@ -911,7 +911,7 @@ Within the \l {Prototyping with qmlscene}, this causes the launcher application
to quit a C++ application when this method is called, connect the
QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
*/
-ReturnedValue QtObject::method_quit(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_quit(CallContext *ctx)
{
QV8Engine *v8engine = ctx->engine->v8Engine;
@@ -943,7 +943,7 @@ If this is the case, consider using \l{QtQml::Qt::createComponent()}{Qt.createCo
See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function.
*/
-ReturnedValue QtObject::method_createQmlObject(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
{
Scope scope(ctx);
if (ctx->callData->argc < 2 || ctx->callData->argc > 3)
@@ -962,16 +962,16 @@ ReturnedValue QtObject::method_createQmlObject(SimpleCallContext *ctx)
const QQmlError &error = errors.at(ii);
errorstr += QLatin1String("\n ") + error.toString();
qmlerror = v4->newObject();
- qmlerror->put((s = v4->newString("lineNumber")), (v = QV4::Primitive::fromInt32(error.line())));
- qmlerror->put((s = v4->newString("columnNumber")), (v = QV4::Primitive::fromInt32(error.column())));
- qmlerror->put((s = v4->newString("fileName")), (v = v4->newString(error.url().toString())));
- qmlerror->put((s = v4->newString("message")), (v = v4->newString(error.description())));
+ qmlerror->put((s = v4->newString(QStringLiteral("lineNumber"))), (v = QV4::Primitive::fromInt32(error.line())));
+ qmlerror->put((s = v4->newString(QStringLiteral("columnNumber"))), (v = QV4::Primitive::fromInt32(error.column())));
+ qmlerror->put((s = v4->newString(QStringLiteral("fileName"))), (v = v4->newString(error.url().toString())));
+ qmlerror->put((s = v4->newString(QStringLiteral("message"))), (v = v4->newString(error.description())));
qmlerrors->putIndexed(ii, qmlerror);
}
v = v4->newString(errorstr);
Scoped<Object> errorObject(scope, v4->newErrorObject(v));
- errorObject->put((s = v4->newString("qmlErrors")), qmlerrors);
+ errorObject->put((s = v4->newString(QStringLiteral("qmlErrors"))), qmlerrors);
return errorObject.asReturnedValue();
}
};
@@ -1012,8 +1012,7 @@ ReturnedValue QtObject::method_createQmlObject(SimpleCallContext *ctx)
if (component.isError()) {
ScopedValue v(scope, Error::create(ctx->engine, component.errors()));
- ctx->throwError(v);
- return QV4::Encode::undefined();
+ return ctx->throwError(v);
}
if (!component.isReady())
@@ -1037,8 +1036,7 @@ ReturnedValue QtObject::method_createQmlObject(SimpleCallContext *ctx)
if (component.isError()) {
ScopedValue v(scope, Error::create(ctx->engine, component.errors()));
- ctx->throwError(v);
- return QV4::Encode::undefined();
+ return ctx->throwError(v);
}
Q_ASSERT(obj);
@@ -1077,10 +1075,10 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi
To create a QML object from an arbitrary string of QML (instead of a file),
use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
-ReturnedValue QtObject::method_createComponent(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_createComponent(CallContext *ctx)
{
if (ctx->callData->argc < 1 || ctx->callData->argc > 3)
- ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
Scope scope(ctx);
@@ -1108,13 +1106,13 @@ ReturnedValue QtObject::method_createComponent(SimpleCallContext *ctx)
if (ctx->callData->args[1].isInteger()) {
int mode = ctx->callData->args[1].integerValue();
if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
- ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
compileMode = QQmlComponent::CompilationMode(mode);
consumedCount += 1;
} else {
// The second argument could be the parent only if there are exactly two args
if ((ctx->callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull()))
- ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
}
if (consumedCount < ctx->callData->argc) {
@@ -1123,11 +1121,11 @@ ReturnedValue QtObject::method_createComponent(SimpleCallContext *ctx)
if (qobjectWrapper)
parentArg = qobjectWrapper->object();
if (!parentArg)
- ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object"));
+ return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object"));
} else if (lastArg->isNull()) {
parentArg = 0;
} else {
- ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object"));
+ return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object"));
}
}
}
@@ -1161,7 +1159,7 @@ ReturnedValue QtObject::method_createComponent(SimpleCallContext *ctx)
\sa QtQuick::Locale
*/
-ReturnedValue QtObject::method_locale(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_locale(CallContext *ctx)
{
QString code;
if (ctx->callData->argc > 1)
@@ -1195,11 +1193,11 @@ struct BindingFunction : public QV4::FunctionObject
return This->originalFunction->call(callData);
}
- static void markObjects(Managed *that)
+ static void markObjects(Managed *that, ExecutionEngine *e)
{
BindingFunction *This = static_cast<BindingFunction*>(that);
- This->originalFunction->mark();
- QV4::FunctionObject::markObjects(that);
+ This->originalFunction->mark(e);
+ QV4::FunctionObject::markObjects(that, e);
}
QV4::FunctionObject *originalFunction;
@@ -1255,7 +1253,7 @@ DEFINE_MANAGED_VTABLE(BindingFunction);
\since 5.0
*/
-ReturnedValue QtObject::method_binding(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_binding(CallContext *ctx)
{
if (ctx->callData->argc != 1)
V4THROW_ERROR("binding() requires 1 argument");
@@ -1267,15 +1265,15 @@ ReturnedValue QtObject::method_binding(SimpleCallContext *ctx)
}
-ReturnedValue QtObject::method_get_platform(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_get_platform(CallContext *ctx)
{
// ### inefficient. Should be just a value based getter
Object *o = ctx->callData->thisObject.asObject();
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QtObject *qt = o->as<QtObject>();
if (!qt)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (!qt->m_platform)
// Only allocate a platform object once
@@ -1284,15 +1282,15 @@ ReturnedValue QtObject::method_get_platform(SimpleCallContext *ctx)
return QV4::QObjectWrapper::wrap(ctx->engine, qt->m_platform);
}
-ReturnedValue QtObject::method_get_application(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_get_application(CallContext *ctx)
{
// ### inefficient. Should be just a value based getter
Object *o = ctx->callData->thisObject.asObject();
if (!o)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QtObject *qt = o->as<QtObject>();
if (!qt)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (!qt->m_application)
// Only allocate an application object once
@@ -1302,7 +1300,7 @@ ReturnedValue QtObject::method_get_application(SimpleCallContext *ctx)
}
#ifndef QT_NO_IM
-ReturnedValue QtObject::method_get_inputMethod(SimpleCallContext *ctx)
+ReturnedValue QtObject::method_get_inputMethod(CallContext *ctx)
{
QObject *o = QQml_guiProvider()->inputMethod();
QQmlEngine::setObjectOwnership(o, QQmlEngine::CppOwnership);
@@ -1360,13 +1358,13 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
QString::number(frame.line));
if (i)
- stack += QChar('\n');
+ stack += QLatin1Char('\n');
stack += stackFrame;
}
return stack;
}
-static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, SimpleCallContext *ctx,
+static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *ctx,
bool printStack = false)
{
QString result;
@@ -1408,12 +1406,12 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, SimpleCallCont
return QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_error(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_error(CallContext *ctx)
{
return writeToConsole(Error, ctx);
}
-QV4::ReturnedValue ConsoleObject::method_log(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_log(CallContext *ctx)
{
//console.log
//console.debug
@@ -1422,7 +1420,7 @@ QV4::ReturnedValue ConsoleObject::method_log(SimpleCallContext *ctx)
return writeToConsole(Log, ctx);
}
-QV4::ReturnedValue ConsoleObject::method_profile(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx)
{
//DeclarativeDebugTrace cannot handle nested profiling
//although v8 can handle several profiling at once,
@@ -1445,7 +1443,7 @@ QV4::ReturnedValue ConsoleObject::method_profile(SimpleCallContext *ctx)
return QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_profileEnd(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx)
{
//DeclarativeDebugTrace cannot handle nested profiling
//although v8 can handle several profiling at once,
@@ -1473,7 +1471,7 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(SimpleCallContext *ctx)
return QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_time(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_time(CallContext *ctx)
{
if (ctx->callData->argc != 1)
V4THROW_ERROR("console.time(): Invalid arguments");
@@ -1485,7 +1483,7 @@ QV4::ReturnedValue ConsoleObject::method_time(SimpleCallContext *ctx)
return QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_timeEnd(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_timeEnd(CallContext *ctx)
{
if (ctx->callData->argc != 1)
V4THROW_ERROR("console.time(): Invalid arguments");
@@ -1501,7 +1499,7 @@ QV4::ReturnedValue ConsoleObject::method_timeEnd(SimpleCallContext *ctx)
return QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_count(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx)
{
// first argument: name to print. Ignore any additional arguments
QString name;
@@ -1525,7 +1523,7 @@ QV4::ReturnedValue ConsoleObject::method_count(SimpleCallContext *ctx)
return QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_trace(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx)
{
if (ctx->callData->argc != 0)
V4THROW_ERROR("console.trace(): Invalid arguments");
@@ -1542,12 +1540,12 @@ QV4::ReturnedValue ConsoleObject::method_trace(SimpleCallContext *ctx)
return QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_warn(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_warn(CallContext *ctx)
{
return writeToConsole(Warn, ctx);
}
-QV4::ReturnedValue ConsoleObject::method_assert(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx)
{
if (ctx->callData->argc == 0)
V4THROW_ERROR("console.assert(): Missing argument");
@@ -1574,7 +1572,7 @@ QV4::ReturnedValue ConsoleObject::method_assert(SimpleCallContext *ctx)
return QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_exception(SimpleCallContext *ctx)
+QV4::ReturnedValue ConsoleObject::method_exception(CallContext *ctx)
{
if (ctx->callData->argc == 0)
V4THROW_ERROR("console.exception(): Missing argument");
@@ -1632,7 +1630,7 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTranslate(SimpleCallContext *ctx)
+ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx)
{
if (ctx->callData->argc < 2)
V4THROW_ERROR("qsTranslate() requires at least two arguments");
@@ -1688,7 +1686,7 @@ ReturnedValue GlobalExtensions::method_qsTranslate(SimpleCallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTranslateNoOp(SimpleCallContext *ctx)
+ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx)
{
if (ctx->callData->argc < 2)
return QV4::Encode::undefined();
@@ -1712,7 +1710,7 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(SimpleCallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTr(SimpleCallContext *ctx)
+ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
{
if (ctx->callData->argc < 1)
V4THROW_ERROR("qsTr() requires at least one argument");
@@ -1766,7 +1764,7 @@ ReturnedValue GlobalExtensions::method_qsTr(SimpleCallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrNoOp(SimpleCallContext *ctx)
+ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx)
{
if (ctx->callData->argc < 1)
return QV4::Encode::undefined();
@@ -1803,7 +1801,7 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(SimpleCallContext *ctx)
\sa QT_TRID_NOOP, {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrId(SimpleCallContext *ctx)
+ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx)
{
if (ctx->callData->argc < 1)
V4THROW_ERROR("qsTrId() requires at least one argument");
@@ -1835,7 +1833,7 @@ ReturnedValue GlobalExtensions::method_qsTrId(SimpleCallContext *ctx)
\sa qsTrId(), {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrIdNoOp(SimpleCallContext *ctx)
+ReturnedValue GlobalExtensions::method_qsTrIdNoOp(CallContext *ctx)
{
if (ctx->callData->argc < 1)
return QV4::Encode::undefined();
@@ -1844,7 +1842,7 @@ ReturnedValue GlobalExtensions::method_qsTrIdNoOp(SimpleCallContext *ctx)
#endif // QT_NO_TRANSLATION
-QV4::ReturnedValue GlobalExtensions::method_gc(SimpleCallContext *ctx)
+QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx)
{
ctx->engine->memoryManager->runGC();
@@ -1853,7 +1851,7 @@ QV4::ReturnedValue GlobalExtensions::method_gc(SimpleCallContext *ctx)
-ReturnedValue GlobalExtensions::method_string_arg(SimpleCallContext *ctx)
+ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx)
{
if (ctx->callData->argc != 1)
V4THROW_ERROR("String.arg(): Invalid arguments");
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index 070796f03c..90536c09dd 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -68,41 +68,41 @@ struct QtObject : Object
Q_MANAGED
QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine);
- static ReturnedValue method_isQtObject(SimpleCallContext *ctx);
- static ReturnedValue method_rgba(SimpleCallContext *ctx);
- static ReturnedValue method_hsla(SimpleCallContext *ctx);
- static ReturnedValue method_colorEqual(SimpleCallContext *ctx);
- static ReturnedValue method_font(SimpleCallContext *ctx);
- static ReturnedValue method_rect(SimpleCallContext *ctx);
- static ReturnedValue method_point(SimpleCallContext *ctx);
- static ReturnedValue method_size(SimpleCallContext *ctx);
- static ReturnedValue method_vector2d(SimpleCallContext *ctx);
- static ReturnedValue method_vector3d(SimpleCallContext *ctx);
- static ReturnedValue method_vector4d(SimpleCallContext *ctx);
- static ReturnedValue method_quaternion(SimpleCallContext *ctx);
- static ReturnedValue method_matrix4x4(SimpleCallContext *ctx);
- static ReturnedValue method_lighter(SimpleCallContext *ctx);
- static ReturnedValue method_darker(SimpleCallContext *ctx);
- static ReturnedValue method_tint(SimpleCallContext *ctx);
- static ReturnedValue method_formatDate(SimpleCallContext *ctx);
- static ReturnedValue method_formatTime(SimpleCallContext *ctx);
- static ReturnedValue method_formatDateTime(SimpleCallContext *ctx);
- static ReturnedValue method_openUrlExternally(SimpleCallContext *ctx);
- static ReturnedValue method_fontFamilies(SimpleCallContext *ctx);
- static ReturnedValue method_md5(SimpleCallContext *ctx);
- static ReturnedValue method_btoa(SimpleCallContext *ctx);
- static ReturnedValue method_atob(SimpleCallContext *ctx);
- static ReturnedValue method_quit(SimpleCallContext *ctx);
- static ReturnedValue method_resolvedUrl(SimpleCallContext *ctx);
- static ReturnedValue method_createQmlObject(SimpleCallContext *ctx);
- static ReturnedValue method_createComponent(SimpleCallContext *ctx);
- static ReturnedValue method_locale(SimpleCallContext *ctx);
- static ReturnedValue method_binding(SimpleCallContext *ctx);
-
- static ReturnedValue method_get_platform(SimpleCallContext *ctx);
- static ReturnedValue method_get_application(SimpleCallContext *ctx);
+ static ReturnedValue method_isQtObject(CallContext *ctx);
+ static ReturnedValue method_rgba(CallContext *ctx);
+ static ReturnedValue method_hsla(CallContext *ctx);
+ static ReturnedValue method_colorEqual(CallContext *ctx);
+ static ReturnedValue method_font(CallContext *ctx);
+ static ReturnedValue method_rect(CallContext *ctx);
+ static ReturnedValue method_point(CallContext *ctx);
+ static ReturnedValue method_size(CallContext *ctx);
+ static ReturnedValue method_vector2d(CallContext *ctx);
+ static ReturnedValue method_vector3d(CallContext *ctx);
+ static ReturnedValue method_vector4d(CallContext *ctx);
+ static ReturnedValue method_quaternion(CallContext *ctx);
+ static ReturnedValue method_matrix4x4(CallContext *ctx);
+ static ReturnedValue method_lighter(CallContext *ctx);
+ static ReturnedValue method_darker(CallContext *ctx);
+ static ReturnedValue method_tint(CallContext *ctx);
+ static ReturnedValue method_formatDate(CallContext *ctx);
+ static ReturnedValue method_formatTime(CallContext *ctx);
+ static ReturnedValue method_formatDateTime(CallContext *ctx);
+ static ReturnedValue method_openUrlExternally(CallContext *ctx);
+ static ReturnedValue method_fontFamilies(CallContext *ctx);
+ static ReturnedValue method_md5(CallContext *ctx);
+ static ReturnedValue method_btoa(CallContext *ctx);
+ static ReturnedValue method_atob(CallContext *ctx);
+ static ReturnedValue method_quit(CallContext *ctx);
+ static ReturnedValue method_resolvedUrl(CallContext *ctx);
+ static ReturnedValue method_createQmlObject(CallContext *ctx);
+ static ReturnedValue method_createComponent(CallContext *ctx);
+ static ReturnedValue method_locale(CallContext *ctx);
+ static ReturnedValue method_binding(CallContext *ctx);
+
+ static ReturnedValue method_get_platform(CallContext *ctx);
+ static ReturnedValue method_get_application(CallContext *ctx);
#ifndef QT_NO_IM
- static ReturnedValue method_get_inputMethod(SimpleCallContext *ctx);
+ static ReturnedValue method_get_inputMethod(CallContext *ctx);
#endif
QObject *m_platform;
@@ -113,17 +113,17 @@ struct ConsoleObject : Object
{
ConsoleObject(ExecutionEngine *v4);
- static ReturnedValue method_error(SimpleCallContext *ctx);
- static ReturnedValue method_log(SimpleCallContext *ctx);
- static ReturnedValue method_profile(SimpleCallContext *ctx);
- static ReturnedValue method_profileEnd(SimpleCallContext *ctx);
- static ReturnedValue method_time(SimpleCallContext *ctx);
- static ReturnedValue method_timeEnd(SimpleCallContext *ctx);
- static ReturnedValue method_count(SimpleCallContext *ctx);
- static ReturnedValue method_trace(SimpleCallContext *ctx);
- static ReturnedValue method_warn(SimpleCallContext *ctx);
- static ReturnedValue method_assert(SimpleCallContext *ctx);
- static ReturnedValue method_exception(SimpleCallContext *ctx);
+ static ReturnedValue method_error(CallContext *ctx);
+ static ReturnedValue method_log(CallContext *ctx);
+ static ReturnedValue method_profile(CallContext *ctx);
+ static ReturnedValue method_profileEnd(CallContext *ctx);
+ static ReturnedValue method_time(CallContext *ctx);
+ static ReturnedValue method_timeEnd(CallContext *ctx);
+ static ReturnedValue method_count(CallContext *ctx);
+ static ReturnedValue method_trace(CallContext *ctx);
+ static ReturnedValue method_warn(CallContext *ctx);
+ static ReturnedValue method_assert(CallContext *ctx);
+ static ReturnedValue method_exception(CallContext *ctx);
};
@@ -131,17 +131,17 @@ struct GlobalExtensions {
static void init(QQmlEngine *qmlEngine, Object *globalObject);
#ifndef QT_NO_TRANSLATION
- static ReturnedValue method_qsTranslate(SimpleCallContext *ctx);
- static ReturnedValue method_qsTranslateNoOp(SimpleCallContext *ctx);
- static ReturnedValue method_qsTr(SimpleCallContext *ctx);
- static ReturnedValue method_qsTrNoOp(SimpleCallContext *ctx);
- static ReturnedValue method_qsTrId(SimpleCallContext *ctx);
- static ReturnedValue method_qsTrIdNoOp(SimpleCallContext *ctx);
+ static ReturnedValue method_qsTranslate(CallContext *ctx);
+ static ReturnedValue method_qsTranslateNoOp(CallContext *ctx);
+ static ReturnedValue method_qsTr(CallContext *ctx);
+ static ReturnedValue method_qsTrNoOp(CallContext *ctx);
+ static ReturnedValue method_qsTrId(CallContext *ctx);
+ static ReturnedValue method_qsTrIdNoOp(CallContext *ctx);
#endif
- static ReturnedValue method_gc(SimpleCallContext *ctx);
+ static ReturnedValue method_gc(CallContext *ctx);
// on String:prototype
- static ReturnedValue method_string_arg(SimpleCallContext *ctx);
+ static ReturnedValue method_string_arg(CallContext *ctx);
};
diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h
index 44662e8cba..faf52ce1ad 100644
--- a/src/qml/qml/v8/qv4domerrors_p.h
+++ b/src/qml/qml/v8/qv4domerrors_p.h
@@ -80,7 +80,7 @@ QT_BEGIN_NAMESPACE
QV4::ScopedValue v(scope, ctx->engine->newString(QStringLiteral(string))); \
QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \
ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \
- ctx->throwError(ex); \
+ return ctx->throwError(ex); \
}
namespace QV4 {
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 4e8738b826..d0fc1b1295 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -66,6 +66,7 @@
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonvalue.h>
#include <QtCore/qdatetime.h>
+#include <private/qsimd_p.h>
#include <private/qv4value_p.h>
#include <private/qv4dateobject_p.h>
@@ -93,6 +94,12 @@ QV8Engine::QV8Engine(QJSEngine* qq)
, m_xmlHttpRequestData(0)
, m_listModelData(0)
{
+#ifdef Q_PROCESSOR_X86_32
+ if (!(qCpuFeatures() & SSE2)) {
+ qFatal("This program requires an X86 processor that supports SSE2 extension, at least a Pentium 4 or newer");
+ }
+#endif
+
QML_MEMORY_SCOPE_STRING("QV8Engine::QV8Engine");
qMetaTypeId<QJSValue>();
qMetaTypeId<QList<int> >();
@@ -141,7 +148,7 @@ QVariant QV8Engine::toVariant(const QV4::ValueRef value, int typeHint)
return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
} else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
return qVariantFromValue<QObject *>(wrapper->object());
- } else if (QV4::QmlContextWrapper *wrapper = object->as<QV4::QmlContextWrapper>()) {
+ } else if (object->as<QV4::QmlContextWrapper>()) {
return QVariant();
} else if (QV4::QmlTypeWrapper *w = object->as<QV4::QmlTypeWrapper>()) {
return w->toVariant();
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index a92d03ac50..e37b0d4920 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -86,10 +86,10 @@ namespace QV4 {
// #define QML_GLOBAL_HANDLE_DEBUGGING
#define V4THROW_ERROR(string) \
- ctx->throwError(QString::fromUtf8(string));
+ return ctx->throwError(QString::fromUtf8(string));
#define V4THROW_TYPE(string) \
- ctx->throwTypeError(QStringLiteral(string));
+ return ctx->throwTypeError(QStringLiteral(string));
#define V8_DEFINE_EXTENSION(dataclass, datafunction) \
static inline dataclass *datafunction(QV8Engine *engine) \
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 10f957ab40..754d008745 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -67,7 +67,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
uint flag;
DelegateModelGroupFunction(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg))
- : FunctionObject(scope, /*name*/0)
+ : FunctionObject(scope, QStringLiteral("DelegateModelGroupFunction"))
, code(code)
, flag(flag)
{
@@ -76,8 +76,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *)
{
- m->engine()->current->throwTypeError();
- return QV4::Primitive::undefinedValue().asReturnedValue();
+ return m->engine()->current->throwTypeError();
}
static QV4::ReturnedValue call(QV4::Managed *that, QV4::CallData *callData)
@@ -87,7 +86,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
QV4::Scoped<DelegateModelGroupFunction> f(scope, that, QV4::Scoped<DelegateModelGroupFunction>::Cast);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject);
if (!o)
- v4->current->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return v4->current->throwTypeError(QStringLiteral("Not a valid VisualData object"));
QV4::ScopedValue v(scope, callData->argument(0));
return f->code(o->item, f->flag, v);
@@ -1623,7 +1622,6 @@ void QQmlDelegateModelItemMetaType::initializeMetaObject()
void QQmlDelegateModelItemMetaType::initializePrototype()
{
- QQmlDelegateModelEngineData *data = engineData(v8Engine);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8Engine);
QV4::Scope scope(v4);
@@ -1706,24 +1704,24 @@ int QQmlDelegateModelItemMetaType::parseGroups(const QV4::ValueRef groups) const
return groupFlags;
}
-QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
if (!o->item->metaType->model)
return QV4::Encode::undefined();
return o->item->get();
}
-QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
QStringList groups;
for (int i = 1; i < o->item->metaType->groupCount; ++i) {
@@ -1734,14 +1732,14 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::SimpleCallContext *ctx
return ctx->engine->v8Engine->fromVariant(groups);
}
-QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
if (!ctx->callData->argc)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (!o->item->metaType->model)
return QV4::Encode::undefined();
@@ -3149,25 +3147,25 @@ struct QQmlDelegateModelGroupChange : QV4::Object
vtbl = &static_vtbl;
}
- static QV4::ReturnedValue method_get_index(QV4::SimpleCallContext *ctx) {
+ static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) {
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return QV4::Encode(that->change.index);
}
- static QV4::ReturnedValue method_get_count(QV4::SimpleCallContext *ctx) {
+ static QV4::ReturnedValue method_get_count(QV4::CallContext *ctx) {
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return QV4::Encode(that->change.count);
}
- static QV4::ReturnedValue method_get_moveId(QV4::SimpleCallContext *ctx) {
+ static QV4::ReturnedValue method_get_moveId(QV4::CallContext *ctx) {
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (that->change.moveId < 0)
return QV4::Encode::undefined();
return QV4::Encode(that->change.moveId);
@@ -3199,7 +3197,7 @@ public:
QV4::Scope scope(v4);
QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, m->as<QQmlDelegateModelGroupChangeArray>());
if (!array)
- v4->current->throwTypeError();
+ return v4->current->throwTypeError();
if (index >= array->count()) {
if (hasProperty)
@@ -3223,7 +3221,7 @@ public:
{
QQmlDelegateModelGroupChangeArray *array = m->as<QQmlDelegateModelGroupChangeArray>();
if (!array)
- m->engine()->current->throwTypeError();
+ return m->engine()->current->throwTypeError();
if (name->equals(m->engine()->id_length)) {
if (hasProperty)
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 8205b5350f..066c8e70e5 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -133,9 +133,9 @@ public:
virtual void setValue(const QString &role, const QVariant &value) { Q_UNUSED(role); Q_UNUSED(value); }
virtual bool resolveIndex(const QQmlAdaptorModel &, int) { return false; }
- static QV4::ReturnedValue get_model(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue get_groups(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue set_groups(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue get_model(QV4::CallContext *ctx);
+ static QV4::ReturnedValue get_groups(QV4::CallContext *ctx);
+ static QV4::ReturnedValue set_groups(QV4::CallContext *ctx);
static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::ValueRef);
static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::ValueRef arg);
static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::ValueRef arg);
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp
index f7b2f9254a..c28cfad9e3 100644
--- a/src/qml/types/qqmlinstantiator.cpp
+++ b/src/qml/types/qqmlinstantiator.cpp
@@ -115,7 +115,7 @@ void QQmlInstantiatorPrivate::_q_createdItem(int idx, QObject* item)
if (objects.contains(item)) //Case when it was created synchronously in regenerate
return;
item->setParent(q);
- objects << item;
+ objects.insert(idx, item);
if (objects.count() == 1)
q->objectChanged();
q->objectAdded(idx, item);
diff --git a/src/qml/types/qqmltimer.cpp b/src/qml/types/qqmltimer.cpp
index 7d1c41aeab..32018c1f03 100644
--- a/src/qml/types/qqmltimer.cpp
+++ b/src/qml/types/qqmltimer.cpp
@@ -109,7 +109,7 @@ public:
elapsed time will be reset to 0, and the Timer will be triggered
1000ms later.
- \sa {declarative/toys/clocks}{Clocks example}
+ \sa {Qt Quick Demo - Clocks}
*/
QQmlTimer::QQmlTimer(QObject *parent)
diff --git a/src/qml/types/qquickpackage.cpp b/src/qml/types/qquickpackage.cpp
index 2ce9ca36d8..1fed95eb85 100644
--- a/src/qml/types/qquickpackage.cpp
+++ b/src/qml/types/qquickpackage.cpp
@@ -73,8 +73,7 @@ QT_BEGIN_NAMESPACE
\snippet quick/views/package/view.qml 0
- \sa {quick/views/package}{Package example}, {quick/demos/photoviewer}{Photo
- Viewer example}, {Qt QML}
+ \sa {quick/views/package}{Package example}, {Qt Quick Demo - Photo Viewer}, {Qt QML}
*/
/*!
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 322b4b8df0..7607febe01 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -181,7 +181,7 @@ public:
int m_nextId;
- static QV4::ReturnedValue method_sendMessage(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_sendMessage(QV4::CallContext *ctx);
signals:
void stopThread();
@@ -229,9 +229,11 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
"})"
QV4::Scope scope(m_v4Engine);
- onmessage = QV4::Script(m_v4Engine->rootContext, CALL_ONMESSAGE_SCRIPT).run();
- QV4::Script createsendscript(m_v4Engine->rootContext, SEND_MESSAGE_CREATE_SCRIPT);
+ onmessage = QV4::Script(m_v4Engine->rootContext, QString::fromUtf8(CALL_ONMESSAGE_SCRIPT)).run(); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro
+ Q_ASSERT(!scope.engine->hasException);
+ QV4::Script createsendscript(m_v4Engine->rootContext, QString::fromUtf8(SEND_MESSAGE_CREATE_SCRIPT)); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro
QV4::Scoped<QV4::FunctionObject> createsendconstructor(scope, createsendscript.run());
+ Q_ASSERT(!scope.engine->hasException);
QV4::ScopedString name(scope, m_v4Engine->newString(QStringLiteral("sendMessage")));
QV4::ScopedValue function(scope, m_v4Engine->newBuiltinFunction(m_v4Engine->rootContext, name,
QQuickWorkerScriptEnginePrivate::method_sendMessage));
@@ -253,14 +255,12 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i
QV4::ExecutionContext *ctx = v4->current;
QV4::ScopedValue v(scope);
- try {
- QV4::ScopedCallData callData(scope, 1);
- callData->args[0] = QV4::Primitive::fromInt32(id);
- callData->thisObject = global();
- v = f->call(callData);
- } catch (...) {
+ QV4::ScopedCallData callData(scope, 1);
+ callData->args[0] = QV4::Primitive::fromInt32(id);
+ callData->thisObject = global();
+ v = f->call(callData);
+ if (scope.hasException())
v = ctx->catchException();
- }
return v.asReturnedValue();
}
@@ -281,7 +281,7 @@ QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *eng
{
}
-QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::CallContext *ctx)
{
WorkerEngine *engine = (WorkerEngine*)ctx->engine->v8Engine;
@@ -315,9 +315,9 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *scri
w->setReadOnly(false);
QV4::Scoped<QV4::Object> api(scope, v4->newObject());
- api->put(QV4::ScopedString(scope, v4->newString("sendMessage")), QV4::ScopedValue(scope, workerEngine->sendFunction(script->id)));
+ api->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("sendMessage"))), QV4::ScopedValue(scope, workerEngine->sendFunction(script->id)));
- w->QV4::Object::put(QV4::ScopedString(scope, v4->newString("WorkerScript")), api);
+ w->QV4::Object::put(QV4::ScopedString(scope, v4->newString(QStringLiteral("WorkerScript"))), api);
w->setReadOnly(true);
}
@@ -360,14 +360,13 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d
QV4::ScopedValue value(scope, QV4::Serialize::deserialize(data, workerEngine));
- try {
- QV4::ScopedCallData callData(scope, 2);
- callData->thisObject = workerEngine->global();
- callData->args[0] = script->object.value();
- callData->args[1] = value;
- f->call(callData);
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ QV4::ScopedCallData callData(scope, 2);
+ callData->thisObject = workerEngine->global();
+ callData->args[0] = script->object.value();
+ callData->args[1] = value;
+ f->call(callData);
+ if (scope.hasException()) {
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
reportScriptException(script, error);
}
}
@@ -400,11 +399,11 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
QV4::Script program(v4, activation, sourceCode, url.toString());
QV4::ExecutionContext *ctx = v4->current;
- try {
- program.parse();
+ program.parse();
+ if (!v4->hasException)
program.run();
- } catch (...) {
- QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
+ if (v4->hasException) {
+ QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
reportScriptException(script, error);
}
} else {
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index 39ebd6bd4c..38fdffdde6 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -63,12 +63,12 @@ public:
V8_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData)
-static QV4::ReturnedValue get_index(QV4::SimpleCallContext *ctx)
+static QV4::ReturnedValue get_index(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
return QV4::Encode(o->item->index);
}
@@ -108,8 +108,8 @@ public:
void setValue(const QString &role, const QVariant &value);
bool resolveIndex(const QQmlAdaptorModel &model, int idx);
- static QV4::ReturnedValue get_property(QV4::SimpleCallContext *ctx, uint propertyId);
- static QV4::ReturnedValue set_property(QV4::SimpleCallContext *ctx, uint propertyId);
+ static QV4::ReturnedValue get_property(QV4::CallContext *ctx, uint propertyId);
+ static QV4::ReturnedValue set_property(QV4::CallContext *ctx, uint propertyId);
VDMModelDelegateDataType *type;
QVector<QVariant> cachedData;
@@ -195,12 +195,12 @@ public:
dataType->watchedRoles += newRoles;
}
- static QV4::ReturnedValue get_hasModelChildren(QV4::SimpleCallContext *ctx)
+ static QV4::ReturnedValue get_hasModelChildren(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->item)->type->model;
if (o->item->index >= 0 && *model) {
@@ -339,12 +339,12 @@ bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &, int idx)
}
}
-QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::SimpleCallContext *ctx, uint propertyId)
+QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::CallContext *ctx, uint propertyId)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->item);
if (o->item->index == -1) {
@@ -359,14 +359,14 @@ QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::SimpleCallContext *c
return QV4::Encode::undefined();
}
-QV4::ReturnedValue QQmlDMCachedModelData::set_property(QV4::SimpleCallContext *ctx, uint propertyId)
+QV4::ReturnedValue QQmlDMCachedModelData::set_property(QV4::CallContext *ctx, uint propertyId)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
if (!ctx->callData->argc)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
if (o->item->index == -1) {
QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->item);
@@ -579,24 +579,24 @@ public:
}
}
- static QV4::ReturnedValue get_modelData(QV4::SimpleCallContext *ctx)
+ static QV4::ReturnedValue get_modelData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
return ctx->engine->v8Engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->item)->cachedData);
}
- static QV4::ReturnedValue set_modelData(QV4::SimpleCallContext *ctx)
+ static QV4::ReturnedValue set_modelData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
if (!ctx->callData->argc)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
static_cast<QQmlDMListAccessorData *>(o->item)->setModelData(ctx->engine->v8Engine->toVariant(ctx->callData->args[0], QVariant::Invalid));
return QV4::Encode::undefined();
@@ -902,7 +902,7 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
list.setList(variant, engine);
- if (QObject *object = qvariant_cast<QObject *>(variant)) {
+ if (QObject *object = qvariant_cast<QObject *>(list.list())) {
setObject(object);
if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(object)) {
accessors = new VDMAbstractItemModelDataType(this);
@@ -927,8 +927,8 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
} else if (list.type() == QQmlListAccessor::ListProperty) {
setObject(static_cast<const QQmlListReference *>(variant.constData())->object());
accessors = new VDMObjectDelegateDataType;
- } else if (list.type() != QQmlListAccessor::Invalid) {
- Q_ASSERT(list.type() != QQmlListAccessor::Instance); // Should have cast to QObject.
+ } else if (list.type() != QQmlListAccessor::Invalid
+ && list.type() != QQmlListAccessor::Instance) { // Null QObject
setObject(0);
accessors = &qt_vdm_list_accessors;
} else {
diff --git a/src/qml/util/qqmllistcompositor.cpp b/src/qml/util/qqmllistcompositor.cpp
index 75d2f67b51..830a24e752 100644
--- a/src/qml/util/qqmllistcompositor.cpp
+++ b/src/qml/util/qqmllistcompositor.cpp
@@ -942,7 +942,7 @@ void QQmlListCompositor::move(
void QQmlListCompositor::clear()
{
- QT_QML_TRACE_LISTCOMPOSITOR( )
+ QT_QML_TRACE_LISTCOMPOSITOR("")
for (Range *range = m_ranges.next; range != &m_ranges; range = erase(range)) {}
m_end = iterator(m_ranges.next, 0, Default, m_groupCount);
m_cacheIt = m_end;
diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro
index 633105273a..963fb1be5a 100644
--- a/src/qmldevtools/qmldevtools.pro
+++ b/src/qmldevtools/qmldevtools.pro
@@ -1,12 +1,6 @@
option(host_build)
TARGET = QtQmlDevTools
-
-force_bootstrap {
- QT = bootstrap-private
-} else {
- QT = core
-}
-
+QT = core
CONFIG += static no_module_headers internal_module
MODULE_INCLUDES = \
diff --git a/src/quick/designer/designerwindowmanager.cpp b/src/quick/designer/designerwindowmanager.cpp
index 76789cd3a8..25ea5e7f93 100644
--- a/src/quick/designer/designerwindowmanager.cpp
+++ b/src/quick/designer/designerwindowmanager.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include "designerwindowmanager_p.h"
-
+#include "private/qquickwindow_p.h"
#include <QtGui/QOpenGLContext>
#include <QtQuick/QQuickWindow>
@@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE
DesignerWindowManager::DesignerWindowManager()
: m_sgContext(QSGContext::createDefaultContext())
{
+ m_renderContext.reset(new QSGRenderContext(m_sgContext.data()));
}
void DesignerWindowManager::show(QQuickWindow *window)
@@ -74,7 +75,7 @@ void DesignerWindowManager::makeOpenGLContext(QQuickWindow *window)
m_openGlContext->create();
if (!m_openGlContext->makeCurrent(window))
qWarning("QQuickWindow: makeCurrent() failed...");
- m_sgContext->initialize(m_openGlContext.data());
+ m_renderContext->initialize(m_openGlContext.data());
} else {
m_openGlContext->makeCurrent(window);
}
@@ -89,10 +90,6 @@ QImage DesignerWindowManager::grab(QQuickWindow *)
return QImage();
}
-void DesignerWindowManager::resize(QQuickWindow *, const QSize &)
-{
-}
-
void DesignerWindowManager::maybeUpdate(QQuickWindow *)
{
}
diff --git a/src/quick/designer/designerwindowmanager_p.h b/src/quick/designer/designerwindowmanager_p.h
index a822ead64e..7414f4e3ba 100644
--- a/src/quick/designer/designerwindowmanager_p.h
+++ b/src/quick/designer/designerwindowmanager_p.h
@@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE
class QQuickWindow;
class QSGContext;
+class QSGRenderContext;
class QAnimationDriver;
class QOpenGLContext;
@@ -81,7 +82,6 @@ public:
void makeOpenGLContext(QQuickWindow *window);
void exposureChanged(QQuickWindow *window);
QImage grab(QQuickWindow *window);
- void resize(QQuickWindow *window, const QSize &size);
void maybeUpdate(QQuickWindow *window);
void update(QQuickWindow *window); // identical for this implementation.
@@ -91,12 +91,14 @@ public:
QAnimationDriver *animationDriver() const { return 0; }
QSGContext *sceneGraphContext() const;
+ QSGRenderContext *createRenderContext(QSGContext *) const { return m_renderContext.data(); }
static void createOpenGLContext(QQuickWindow *window);
private:
QScopedPointer<QOpenGLContext> m_openGlContext;
QScopedPointer<QSGContext> m_sgContext;
+ QScopedPointer<QSGRenderContext> m_renderContext;
};
QT_END_NAMESPACE
diff --git a/src/quick/doc/images/qml-xmllistmodel-example.png b/src/quick/doc/images/qml-xmllistmodel-example.png
new file mode 100644
index 0000000000..be2d15d342
--- /dev/null
+++ b/src/quick/doc/images/qml-xmllistmodel-example.png
Binary files differ
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 8f769871a5..22880c4086 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -2,7 +2,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtQuick
description = Qt Quick Reference Documentation
-url = http://qt-project.org/doc/qt-$QT_VER/qtquick-index.html
+url = http://qt-project.org/doc/qt-$QT_VER
version = $QT_VERSION
examplesinstallpath = quick
diff --git a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
index ba9ec9229e..b5dd961ea9 100644
--- a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
+++ b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
@@ -245,7 +245,7 @@ To visualize data, bind the view's \c model property to a model and the
}
\endqml
- The \l{declarative/rssnews}{RSS News demo} shows how XmlListModel can
+ The \l{Qt Quick Demo - RSS News}{RSS News demo} shows how XmlListModel can
be used to display an RSS feed.
diff --git a/src/quick/doc/src/concepts/positioning/layouts.qdoc b/src/quick/doc/src/concepts/positioning/layouts.qdoc
index 35be2f6235..fef55582dc 100644
--- a/src/quick/doc/src/concepts/positioning/layouts.qdoc
+++ b/src/quick/doc/src/concepts/positioning/layouts.qdoc
@@ -32,7 +32,7 @@
Positioner items are container items that manage the positions of
items in a declarative user interface. Positioners behave in a similar way to
-the \l{Widgets and Layouts}{layout managers} used with standard Qt widgets,
+the \l{Qt Widgets}{layout managers} used with standard Qt widgets,
except that they are also containers in their own right.
Positioners make it easier to work with many items when they need
diff --git a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
index 1c48058510..ad8b2f3b63 100644
--- a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
+++ b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
@@ -185,7 +185,7 @@ command-line parameter "-reverse":
qmlviewer myapp.qml -reverse
\endcode
-The layout direction can also be set from C++ by calling the static function \l QApplication::setLayoutDirection():
+The layout direction can also be set from C++ by calling the static function \l QGuiApplication::setLayoutDirection():
\code
QApplication app(argc, argv);
diff --git a/src/quick/doc/src/concepts/statesanimations/animations.qdoc b/src/quick/doc/src/concepts/statesanimations/animations.qdoc
index dcf1d49a72..07f1048bf2 100644
--- a/src/quick/doc/src/concepts/statesanimations/animations.qdoc
+++ b/src/quick/doc/src/concepts/statesanimations/animations.qdoc
@@ -32,7 +32,7 @@
\brief the animation system in Qt Quick
\section1 Animation and Transitions Types
-\generatelist{related}
+
\list
\li \l {Transition} - Animates transitions during state changes
\li \l {SequentialAnimation} - Runs animations sequentially
@@ -47,15 +47,6 @@
Types that animate properties based on data types
\annotatedlist qtquick-animation-properties
-\list
-\li \l {PropertyAnimation} - Animates property changes
-\li \l {NumberAnimation} - Animates properties of type qreal
-\li \l {Vector3dAnimation} - Animates properties of type QVector3d
-\li \l {ColorAnimation} - Animates color changes
-\li \l {RotationAnimation} - Animates rotations
-\li \l {ParentAnimation} - Animates parent changes
-\li \l {AnchorAnimation} - Animates anchor changes
-\endlist
Animations are created by applying animation types to property
values. Animation types will interpolate property values to create smooth
@@ -65,6 +56,8 @@ To create an animation, use an appropriate animation type for the type of
the property that is to be animated, and apply the animation depending on the
type of behavior that is required.
+\sa {Qt Quick Examples - Animation}
+
\section1 Triggering Animations
There are several ways of setting animation to an object.
@@ -218,9 +211,6 @@ The \l SequentialAnimation type is also useful for playing
\l{qml-transition-animations}{transition animations} because animations are
played in parallel inside transitions.
-See the \l {declarative/animation/basics}{Animation basics example} for a
-demonstration of creating and combining multiple animations in QML.
-
\keyword qml-controlling-animations
\section1 Controlling Animations
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index 384e8209c1..16075f0db3 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -724,6 +724,11 @@ with multiple windows.
\li Some material flags prevent batching, the most limiting one
being QSGMaterial::RequiresFullMatrix which prevents all batching.
+ \li Applications with a monochrome background should set it using
+ QQuickWindow::setColor() rather than using a top-level Rectangle item.
+ QQuickWindow::setColor() will be used in a call to \c glClear(),
+ which is potentially faster.
+
\endlist
If an application performs poorly, make sure that rendering is
diff --git a/src/quick/doc/src/cppextensionpoints.qdoc b/src/quick/doc/src/cppextensionpoints.qdoc
index 7fa7ee7aca..db003b2427 100644
--- a/src/quick/doc/src/cppextensionpoints.qdoc
+++ b/src/quick/doc/src/cppextensionpoints.qdoc
@@ -41,7 +41,7 @@ QQuickItem-derived types which can be rendered by Qt Quick. It also provides
several scene graph-related classes which allow developers to define their own
rendering primitives.
-
+\target user-defined-qquickitem-derived-types
\section1 User-Defined QQuickItem-Derived Types
While the Qt Quick module already provides a rich library of visual item types
@@ -51,7 +51,7 @@ way to do this is to subclass QQuickItem, which is the base type
for all visual types in the Qt Quick module. See the QQuickItem documentation
for more details.
-
+\target scene-graph-related-classes
\section1 Scene Graph-Related Classes
Qt Quick 2 makes use of a dedicated scene graph based on OpenGL ES 2.0 or OpenGL 2.0
@@ -66,7 +66,7 @@ enable custom nodes to be created in C++.
See the \l {Qt Quick Scene Graph} documentation for details.
-
+\target pixmap-and-threaded-image-support
\section1 Pixmap and Threaded Image Support
While the QML engine allows QML application to load images from filesystem or
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index fce7c05e00..cf40fbe37c 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -36,6 +36,7 @@ interfaces and applications with QML. This page lists every QML type provided
by this module, organized according to category and purpose.
+\target importing-qtquick
\section1 Importing Qt Quick
The types provided by the \l {Qt Quick} module are only available in a QML document
@@ -71,7 +72,7 @@ information about the concepts which are central to \c QtQuick.
\li \l{Qt Quick Layouts QML Types}{Layouts} - contains types that are used
to arrange items in the user interface
\endlist
-
+\target basic-types
\section1 Basic Types
There are a number of basic types that are
@@ -80,7 +81,7 @@ There are a number of basic types that are
In addition, the \c QtQuick module provides the following basic types:
\annotatedlist qtquickbasictypes
-
+\target object-types
\section1 Object Types
All of the object types provided by \c QtQuick are based on the \l{Item} type,
@@ -88,7 +89,7 @@ which itself derives from \l{QtQml::QtObject}{QtObject}. \l{qtqml-typereference
{QML object types} provided by the Qt QML module
(such as \l{QtQml::QtObject}{QtObject} and \l{QtQml::Component}{Component}) are also available when
you import \c QtQuick.
-
+\target visual-types
\section2 Visual Types
\list
@@ -129,7 +130,7 @@ Visual Item Transformations
\li \l {Translate} - Assigns item translation behaviors
\endlist
-
+\target user-input
\section2 User Input
\list
@@ -163,7 +164,7 @@ User Input Events
\li \l {KeyEvent} - Provides information about a key press event
\li \l {DragEvent} -Provides information about a drag event
\endlist
-
+\target positioning
\section2 Positioning
\list
@@ -174,7 +175,7 @@ User Input Events
\li \l {Flow} - Positions its children with wrapping support
\li \l {LayoutMirroring} - Attached property used to mirror layout behavior
\endlist
-
+\target states-transitions-and-animations
\section2 States, Transitions and Animations
States
@@ -211,6 +212,12 @@ Type-specific Animations
\li \l {ParentAnimation} - Animates parent changes
\li \l {AnchorAnimation} - Animates anchor changes
\li \l {PathAnimation} - Animates position along a path
+\li \l {XAnimator} - Animates x position asynchronously
+\li \l {YAnimator} - Animates y position asynchronously
+\li \l {ScaleAnimator} - Animates scale asynchronously
+\li \l {RotationAnimator} - Animates rotation asynchronously
+\li \l {OpacityAnimator} - Animates opacity asynchronously
+\li \l {UniformAnimator} - Animates a \l ShaderEffect uniform asynchronously
\endlist
Lower-level Animation Types
@@ -231,7 +238,7 @@ Animation paths
\li \l {PathAttribute} - Allows the setting of attributes along a \l {Path}
\li \l {PathPercent} - Modifies the item distribution along a \l {Path}
\endlist
-
+\target model-view-types-and-data-storage-and-access
\section2 Model/View Types And Data Storage And Access
QML Lists and Models
@@ -268,9 +275,10 @@ Views
Data Storage
\list
-\li \l {QtQuick.LocalStorage 2} - Singleton type providing simplified SQL access
+\li \l {Qt Quick Local Storage QML Types}{QtQuick.LocalStorage 2} - Singleton
+type providing simplified SQL access
\endlist
-
+\target graphical-effects
\section2 Graphical Effects
\list
@@ -278,9 +286,10 @@ Data Storage
\li \l {ShaderEffect} - Allows GLSL shaders to be used as graphical effects
\li \l {ShaderEffectSource} - Usable as a texture in ShaderEffect
\li \l {GridMesh} - Generates a grid mesh of vertices for use by ShaderEffect
-\li The \l{QtQuick.Particles 2} module provides a set of Particle System types for Qt Quick 2
+\li The \l{Qt Quick Particles QML Types}{QtQuick.Particles 2} module provides a
+set of Particle System types for Qt Quick 2
\endlist
-
+\target convenience-types
\section2 Convenience Types
\list
@@ -289,7 +298,7 @@ Data Storage
\li \l {Timer} - Provides timed triggers
\li \l {WorkerScript} - Enables the use of threads in a Qt Quick application
\endlist
-
+\target canvas-similar-to-html5-canvas
\section2 Canvas (similar to HTML5 canvas)
\list
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index 088e62d81a..392ae0af92 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -61,20 +61,18 @@ and visual effects can be supplemented through specialised components for
particle and shader effects.
\list
-\li \l{qtquick-visualcanvas-topic.html}{The Visual Canvas}
-\li \l{qtquick-input-topic.html}{User Input}
-\li \l{qtquick-positioning-topic.html}{Positioning}
-\li \l{qtquick-statesanimations-topic.html}{States, Transitions And Animations}
-\li \l{qtquick-modelviewsdata-topic.html}{Data - Models, Views and Data Storage}
-\li \l{qtquick-effects-topic.html}{Particles And Graphical Effects}
-\li \l{qtquick-convenience-topic.html}{Convenience Types}
+\li \l{Important Concepts In Qt Quick - The Visual Canvas}{The Visual Canvas}
+\li \l{Important Concepts In Qt Quick - User Input}{User Input}
+\li \l{Important Concepts In Qt Quick - Positioning}{Positioning}
+\li \l{Important Concepts in Qt Quick - States, Transitions and Animations}{States, Transitions And Animations}
+\li \l{Important Concepts In Qt Quick - Data - Models, Views and Data Storage}{Data - Models, Views and Data Storage}
+\li \l{Important Concepts In Qt Quick - Graphical Effects}{Particles And Graphical Effects}
+\li \l{Important Concepts In Qt Quick - Convenience Types}{Convenience Types}
\endlist
When using the \c QtQuick module, you will need to know how to write QML
-applications using the QML language. In particular, you should have a grasp
-of the \l{qtquick-quickstart-basics.html}{QML Basics} and
-\l{qtquick-quickstart-essentials.html}{QML Essentials} from the
-\l{QML Applications}.
+applications using the QML language. In particular, QML Basics and QML
+Essentials from the \l{QML Applications} page.
To find out more about using the QML language, see the \l{Qt QML} module documentation.
@@ -82,28 +80,28 @@ To find out more about using the QML language, see the \l{Qt QML} module documen
\section1 Qt Quick Module Documentation
\list
- \li \l{qtquick-qmltypereference.html}{Qt Quick QML Types}
+ \li \l{Qt Quick QML Types}
\list
- \li \l{qtquick-qmltypereference.html#importing-qtquick}{Importing QtQuick}
- \li \l{qtquick-qmltypereference.html#basic-types}{Basic Types}
- \li \l{qtquick-qmltypereference.html#object-types}{Object Types}
+ \li \l{importing-qtquick}{Importing QtQuick}
+ \li \l{basic-types}{Basic Types}
+ \li \l{object-types}{Object Types}
\list
- \li \l{qtquick-qmltypereference.html#visual-types}{Visual Types}
- \li \l{qtquick-qmltypereference.html#user-input}{User Input}
- \li \l{qtquick-qmltypereference.html#positioning}{Positioning}
- \li \l{qtquick-qmltypereference.html#states-transitions-and-animations}{States, Transitions And Animations}
- \li \l{qtquick-qmltypereference.html#model-view-types-and-data-storage-and-access}{Model/View Types And Data Storage And Access}
- \li \l{qtquick-qmltypereference.html#graphical-effects}{Graphical Effects}
- \li \l{qtquick-qmltypereference.html#convenience-types}{Convenience Types}
- \li \l{qtquick-qmltypereference.html#canvas-similar-to-html5-canvas}{Canvas (similar to HTML5 Canvas)}
+ \li \l{visual-types}{Visual Types}
+ \li \l{user-input}{User Input}
+ \li \l{positioning}{Positioning}
+ \li \l{states-transitions-and-animations}{States, Transitions And Animations}
+ \li \l{model-view-types-and-data-storage-and-access}{Model/View Types And Data Storage And Access}
+ \li \l{graphical-effects}{Graphical Effects}
+ \li \l{convenience-types}{Convenience Types}
+ \li \l{canvas-similar-to-html5-canvas}{Canvas (similar to HTML5 Canvas)}
\endlist
\endlist
- \li \l{qtquick-cppextensionpoints.html}{C++ Extension Points}
+ \li \l{C++ Extension Points Provided By Qt Quick}{C++ Extension Points}
\list
- \li \l{qtquick-cppextensionpoints.html#user-defined-qquickitem-derived-types}{Creating User-Defined QQuickItem-Derived Types}
- \li \l{qtquick-cppextensionpoints.html#scene-graph-related-classes}{Scene Graph-Related Classes}
- \li \l{qtquick-cppextensionpoints.html#pixmap-and-threaded-image-support}{Pixmap and Threaded Image Support}
+ \li \l{user-defined-qquickitem-derived-types}{Creating User-Defined QQuickItem-Derived Types}
+ \li \l{scene-graph-related-classes}{Scene Graph-Related Classes}
+ \li \l{pixmap-and-threaded-image-support}{Pixmap and Threaded Image Support}
\endlist
\endlist
@@ -117,20 +115,19 @@ Additional Qt Quick information:
\li \l{Qt Quick QML Types} - a list of QML types provided by the
\c{QtQuick} import
\list
- \li \l{QtQuick.XmlListModel 2}{XML List Model} - contains types
+ \li \l{Qt Quick XmlListModel QML Types}{XML List Model} - contains types
for creating models from XML data
- \li \l{QtQuick.LocalStorage 2}{Local Storage} - a submodule
+ \li \l{Qt Quick Local Storage QML Types}{Local Storage} - a submodule
containing a JavaScript interface for an SQLite database
- \li \l{QtQuick.Particles 2}{Particles} - provides a particle
+ \li \l{Qt Quick Particles QML Types}{Particles} - provides a particle
system for Qt Quick
- \li \l{QtQuick.Window 2}{Window} - contains types for creating
+ \li \l{Qt Quick Window QML Types}{Window} - contains types for creating
top-level windows and accessing screen information
\li \l{Qt Quick Dialogs}{Dialogs} - contains types for creating and
interacting with system dialogs
\endlist
\li \l{Qt Quick Release Notes} - list of changes and additions in the Qt Quick
\li \l{Qt Quick Code Samples} - list of all Qt Quick examples
-module
\endlist
Further information for writing QML applications:
diff --git a/src/quick/doc/src/tutorial.qdoc b/src/quick/doc/src/tutorial.qdoc
index bd07c9a98d..a4428c5818 100644
--- a/src/quick/doc/src/tutorial.qdoc
+++ b/src/quick/doc/src/tutorial.qdoc
@@ -29,7 +29,6 @@
\page qml-tutorial.html
\title QML Tutorial
\brief An introduction to the basic concepts and features of QML.
-\previouspage Introduction to the QML Language
\nextpage QML Tutorial 1 - Basic Types
This tutorial gives an introduction to QML, the declarative language for Qt Quick. It doesn't cover everything;
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index d9feb8d8eb..ba3592986c 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -112,7 +112,7 @@ QSGTexture *QQuickCanvasPixmap::texture()
Q_ASSERT(m_pixmap->textureFactory());
m_texture = m_pixmap->textureFactory()->createTexture(m_window);
} else {
- m_texture = QQuickWindowPrivate::get(m_window)->context->createTexture(m_image);
+ m_texture = m_window->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas);
}
}
return m_texture;
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 2fb6cb9f63..2a9e0f2ac2 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -488,45 +488,45 @@ public:
}
QQuickContext2D* context;
- static QV4::ReturnedValue method_get_globalAlpha(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_globalAlpha(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_globalCompositeOperation(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_globalCompositeOperation(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_fillStyle(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_fillStyle(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_fillRule(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_fillRule(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_strokeStyle(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_strokeStyle(QV4::SimpleCallContext *ctx);
-
- static QV4::ReturnedValue method_get_lineCap(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_lineCap(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_lineJoin(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_lineJoin(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_lineWidth(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_lineWidth(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_miterLimit(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_miterLimit(QV4::SimpleCallContext *ctx);
-
- static QV4::ReturnedValue method_get_shadowBlur(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_shadowBlur(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_shadowColor(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_shadowColor(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_shadowOffsetX(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_shadowOffsetX(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_shadowOffsetY(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_shadowOffsetY(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_get_globalAlpha(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_globalAlpha(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_globalCompositeOperation(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_globalCompositeOperation(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_fillStyle(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_fillStyle(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_fillRule(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_fillRule(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_strokeStyle(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_strokeStyle(QV4::CallContext *ctx);
+
+ static QV4::ReturnedValue method_get_lineCap(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_lineCap(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_lineJoin(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_lineJoin(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_lineWidth(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_lineWidth(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_miterLimit(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_miterLimit(QV4::CallContext *ctx);
+
+ static QV4::ReturnedValue method_get_shadowBlur(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_shadowBlur(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_shadowColor(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_shadowColor(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_shadowOffsetX(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_shadowOffsetX(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_shadowOffsetY(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_shadowOffsetY(QV4::CallContext *ctx);
// should these two be on the proto?
- static QV4::ReturnedValue method_get_path(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_path(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_get_path(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_path(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_font(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_font(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_textAlign(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_textAlign(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_textBaseline(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_set_textBaseline(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_get_font(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_font(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_textAlign(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_textAlign(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_textBaseline(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_set_textBaseline(QV4::CallContext *ctx);
protected:
static void destroy(Managed *that)
@@ -594,50 +594,50 @@ public:
defineAccessorProperty(QStringLiteral("canvas"), QQuickJSContext2DPrototype::method_get_canvas, 0);
}
- static QV4::ReturnedValue method_get_canvas(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_restore(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_reset(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_save(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_rotate(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_scale(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_translate(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_setTransform(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_transform(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_resetTransform(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_shear(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_createLinearGradient(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_createRadialGradient(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_createConicalGradient(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_createPattern(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_clearRect(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_fillRect(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_strokeRect(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_arc(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_arcTo(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_beginPath(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_bezierCurveTo(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_clip(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_closePath(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_fill(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_lineTo(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_moveTo(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_quadraticCurveTo(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_rect(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_roundedRect(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_ellipse(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_text(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_stroke(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_isPointInPath(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_drawFocusRing(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_setCaretSelectionRect(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_caretBlinkRate(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_fillText(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_strokeText(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_measureText(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_drawImage(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_createImageData(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_getImageData(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_putImageData(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_get_canvas(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_restore(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_reset(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_save(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_rotate(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_scale(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_translate(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_setTransform(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_transform(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_resetTransform(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_shear(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_createLinearGradient(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_createRadialGradient(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_createConicalGradient(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_createPattern(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_clearRect(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_fillRect(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_strokeRect(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_arc(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_arcTo(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_beginPath(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_bezierCurveTo(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_clip(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_closePath(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_fill(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_lineTo(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_moveTo(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_quadraticCurveTo(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_rect(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_roundedRect(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_ellipse(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_text(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_stroke(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_isPointInPath(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_drawFocusRing(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_setCaretSelectionRect(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_caretBlinkRate(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_fillText(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_strokeText(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_measureText(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_drawImage(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_createImageData(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_getImageData(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_putImageData(QV4::CallContext *ctx);
};
@@ -659,7 +659,7 @@ public:
bool patternRepeatX:1;
bool patternRepeatY:1;
- static QV4::ReturnedValue gradient_proto_addColorStop(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue gradient_proto_addColorStop(QV4::CallContext *ctx);
protected:
static void destroy(Managed *that)
{
@@ -880,7 +880,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object
static QV4::ReturnedValue getIndexed(QV4::Managed *m, uint index, bool *hasProperty);
static void putIndexed(QV4::Managed *m, uint index, const QV4::ValueRef value);
- static QV4::ReturnedValue proto_get_length(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue proto_get_length(QV4::CallContext *ctx);
QImage image;
};
@@ -904,12 +904,13 @@ struct QQuickJSContext2DImageData : public QV4::Object
defineAccessorProperty(QStringLiteral("data"), method_get_data, 0);
}
- static QV4::ReturnedValue method_get_width(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_height(QV4::SimpleCallContext *ctx);
- static QV4::ReturnedValue method_get_data(QV4::SimpleCallContext *ctx);
+ static QV4::ReturnedValue method_get_width(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_height(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_data(QV4::CallContext *ctx);
- static void markObjects(Managed *that) {
- static_cast<QQuickJSContext2DImageData *>(that)->pixelData.mark();
+ static void markObjects(Managed *that, QV4::ExecutionEngine *engine) {
+ static_cast<QQuickJSContext2DImageData *>(that)->pixelData.mark(engine);
+ QV4::Object::markObjects(that, engine);
}
@@ -949,7 +950,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV8Engine* engi
This property is read only.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_get_canvas(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_get_canvas(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -965,7 +966,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_get_canvas(QV4::SimpleCall
\sa save()
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_restore(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_restore(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -980,7 +981,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_restore(QV4::SimpleCallCon
\qmlmethod object QtQuick::Context2D::reset()
Resets the context state and properties to the default values.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_reset(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_reset(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1022,7 +1023,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_reset(QV4::SimpleCallConte
The current path is NOT part of the drawing state. The path can be reset by
invoking the beginPath() method.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_save(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_save(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1052,7 +1053,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_save(QV4::SimpleCallContex
where the \a angle of rotation is in radians.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_rotate(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_rotate(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1081,7 +1082,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_rotate(QV4::SimpleCallCont
\image qml-item-canvas-scale.png
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_scale(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_scale(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1127,7 +1128,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_scale(QV4::SimpleCallConte
\sa transform()
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_setTransform(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_setTransform(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1157,7 +1158,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_setTransform(QV4::SimpleCa
\sa setTransform()
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_transform(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_transform(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1184,7 +1185,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_transform(QV4::SimpleCallC
Translating the origin enables you to draw patterns of different objects on the canvas
without having to measure the coordinates manually for each shape.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_translate(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_translate(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1205,7 +1206,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_translate(QV4::SimpleCallC
\sa transform(), setTransform(), reset()
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_resetTransform(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_resetTransform(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1224,7 +1225,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_resetTransform(QV4::Simple
Shears the transformation matrix by \a sh in the horizontal direction and
\a sv in the vertical direction.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_shear(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_shear(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1245,7 +1246,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_shear(QV4::SimpleCallConte
The value must be in the range from \c 0.0 (fully transparent) to \c 1.0 (fully opaque).
The default value is \c 1.0.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_globalAlpha(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_globalAlpha(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1255,7 +1256,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_globalAlpha(QV4::SimpleCallCont
return QV4::Encode(r->context->state.globalAlpha);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1300,7 +1301,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::SimpleCallCont
extension composition modes are provided as "vendorName-operationName" syntax, for example: QPainter::CompositionMode_Exclusion is provided as
"qt-exclusion".
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_globalCompositeOperation(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_globalCompositeOperation(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1310,7 +1311,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_globalCompositeOperation(QV4::S
return QV4::Encode(ctx->engine->newString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation)));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1318,7 +1319,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::S
CHECK_CONTEXT_SETTER(r)
if (!ctx->callData->argc)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QString mode = ctx->callData->args[0].toQString();
QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
@@ -1355,7 +1356,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::S
\sa createPattern()
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_fillStyle(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_fillStyle(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1377,7 +1378,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_fillStyle(QV4::SimpleCallContex
return r->context->m_fillStyle.value();
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1425,7 +1426,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::SimpleCallContex
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_fillRule(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_fillRule(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1436,7 +1437,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_fillRule(QV4::SimpleCallContext
return engine->fromVariant(r->context->state.fillRule);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1470,7 +1471,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::SimpleCallContext
\sa createPattern()
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_strokeStyle(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_strokeStyle(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1492,7 +1493,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_strokeStyle(QV4::SimpleCallCont
return r->context->m_strokeStyle.value();
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1547,7 +1548,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::SimpleCallCont
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1594,7 +1595,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1649,7 +1650,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1659,7 +1660,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4:
QV8Engine *engine = ctx->engine->v8Engine;
- if (ctx->callData->argc == 6) {
+ if (ctx->callData->argc == 3) {
qreal x = ctx->callData->args[0].toNumber();
qreal y = ctx->callData->args[1].toNumber();
qreal angle = DEGREES(ctx->callData->args[2].toNumber());
@@ -1725,7 +1726,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4:
\sa strokeStyle
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1797,7 +1798,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::SimpleC
\endlist
Other values are ignored.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_lineCap(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_lineCap(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1816,7 +1817,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_lineCap(QV4::SimpleCallContext
return QV4::Encode(ctx->engine->newString(QStringLiteral("butt")));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1855,7 +1856,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::SimpleCallContext
\endlist
Other values are ignored.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_lineJoin(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_lineJoin(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1874,7 +1875,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_lineJoin(QV4::SimpleCallContext
return QV4::Encode(ctx->engine->newString(QStringLiteral("miter")));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1882,7 +1883,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::SimpleCallContext
CHECK_CONTEXT_SETTER(r)
if (!ctx->callData->argc)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QString lineJoin = ctx->callData->args[0].toQString();
Qt::PenJoinStyle join;
@@ -1906,7 +1907,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::SimpleCallContext
\qmlproperty real QtQuick::Context2D::lineWidth
Holds the current line width. Values that are not finite values greater than zero are ignored.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_lineWidth(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_lineWidth(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1916,7 +1917,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_lineWidth(QV4::SimpleCallContex
return QV4::Encode(r->context->state.lineWidth);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1937,7 +1938,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::SimpleCallContex
Holds the current miter limit ratio.
The default miter limit value is 10.0.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_miterLimit(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_miterLimit(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1947,7 +1948,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_miterLimit(QV4::SimpleCallConte
return QV4::Encode(r->context->state.miterLimit);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1968,7 +1969,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::SimpleCallConte
\qmlproperty real QtQuick::Context2D::shadowBlur
Holds the current level of blur applied to shadows
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_shadowBlur(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_shadowBlur(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1978,7 +1979,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_shadowBlur(QV4::SimpleCallConte
return QV4::Encode(r->context->state.shadowBlur);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -1998,7 +1999,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(QV4::SimpleCallConte
\qmlproperty string QtQuick::Context2D::shadowColor
Holds the current shadow color.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_shadowColor(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_shadowColor(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2008,7 +2009,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_shadowColor(QV4::SimpleCallCont
return QV4::Encode(ctx->engine->newString(r->context->state.shadowColor.name()));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_shadowColor(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_shadowColor(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2033,7 +2034,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowColor(QV4::SimpleCallCont
\sa shadowOffsetY
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetX(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetX(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2043,7 +2044,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetX(QV4::SimpleCallCo
return QV4::Encode(r->context->state.shadowOffsetX);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2063,7 +2064,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::SimpleCallCo
\sa shadowOffsetX
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetY(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetY(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2073,7 +2074,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetY(QV4::SimpleCallCo
return QV4::Encode(r->context->state.shadowOffsetY);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetY(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetY(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2088,7 +2089,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetY(QV4::SimpleCallCo
return QV4::Encode::undefined();
}
-QV4::ReturnedValue QQuickJSContext2D::method_get_path(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_path(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2098,7 +2099,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_path(QV4::SimpleCallContext *ct
return r->context->m_v4path.value();
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2123,7 +2124,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::SimpleCallContext *ct
\qmlmethod object QtQuick::Context2D::clearRect(real x, real y, real w, real h)
Clears all pixels on the canvas in the given rectangle to transparent black.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_clearRect(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_clearRect(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2145,7 +2146,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_clearRect(QV4::SimpleCallC
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillRect(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillRect(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2167,7 +2168,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillRect(QV4::SimpleCallCo
\sa lineJoin
\sa miterLimit
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeRect(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeRect(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2201,7 +2202,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeRect(QV4::SimpleCall
\sa arcTo, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C's 2D
Context Standard for arc()}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2253,7 +2254,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::SimpleCallContext
\sa arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C's 2D
Context Standard for arcTo()}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2281,7 +2282,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::SimpleCallConte
Resets the current path to a new path.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2312,7 +2313,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(QV4::SimpleCallC
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
\sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2361,7 +2362,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::SimpleC
\sa fill()
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_clip(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_clip(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2379,7 +2380,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_clip(QV4::SimpleCallContex
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_closePath(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_closePath(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2401,7 +2402,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_closePath(QV4::SimpleCallC
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_fill(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_fill(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2416,7 +2417,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fill(QV4::SimpleCallContex
Draws a line from the current position to the point (x, y).
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2441,7 +2442,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::SimpleCallCont
Creates a new subpath with the given point.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2465,7 +2466,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::SimpleCallCont
See \l{http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for for quadraticCurveTo}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2491,7 +2492,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::Simp
Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_rect(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_rect(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2508,7 +2509,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_rect(QV4::SimpleCallContex
Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
ellipses defining the corners of the rounded rectangle.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_roundedRect(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_roundedRect(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2532,7 +2533,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_roundedRect(QV4::SimpleCal
The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_ellipse(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_ellipse(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2551,7 +2552,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_ellipse(QV4::SimpleCallCon
Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2577,7 +2578,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::SimpleCallContex
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_stroke(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_stroke(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2594,7 +2595,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_stroke(QV4::SimpleCallCont
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_isPointInPath(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_isPointInPath(QV4::CallContext *ctx)
{
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::Scope scope(v4);
@@ -2607,21 +2608,21 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_isPointInPath(QV4::SimpleC
return QV4::Primitive::fromBoolean(pointInPath).asReturnedValue();
}
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawFocusRing(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawFocusRing(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
}
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_setCaretSelectionRect(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_setCaretSelectionRect(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
}
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_caretBlinkRate(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_caretBlinkRate(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
@@ -2651,7 +2652,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_caretBlinkRate(QV4::Simple
The default font value is "10px sans-serif".
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_font(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_font(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2660,13 +2661,15 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_font(QV4::SimpleCallContext *ct
return QV4::Encode(ctx->engine->newString(r->context->state.font.toString()));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_font(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_font(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QV4::Scoped<QV4::String> s(scope, ctx->argument(0), QV4::Scoped<QV4::String>::Convert);
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
QFont font = qt_font_from_string(s->toQString(), r->context->state.font);
if (font != r->context->state.font) {
r->context->state.font = font;
@@ -2688,7 +2691,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_font(QV4::SimpleCallContext *ct
\endlist
Other values are ignored. The default value is "start".
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_textAlign(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_textAlign(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2710,13 +2713,15 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_textAlign(QV4::SimpleCallContex
return QV4::Encode(ctx->engine->newString(QStringLiteral("start")));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QV4::Scoped<QV4::String> s(scope, ctx->argument(0), QV4::Scoped<QV4::String>::Convert);
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
QString textAlign = s->toQString();
QQuickContext2D::TextAlignType ta;
@@ -2754,7 +2759,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::SimpleCallContex
\endlist
Other values are ignored. The default value is "alphabetic".
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_textBaseline(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_get_textBaseline(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2776,12 +2781,14 @@ QV4::ReturnedValue QQuickJSContext2D::method_get_textBaseline(QV4::SimpleCallCon
return QV4::Encode(ctx->engine->newString(QStringLiteral("alphabetic")));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QV4::Scoped<QV4::String> s(scope, ctx->argument(0), QV4::Scoped<QV4::String>::Convert);
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
QString textBaseline = s->toQString();
QQuickContext2D::TextBaseLineType tb;
@@ -2812,7 +2819,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::SimpleCallCon
\sa textBaseline
\sa strokeText
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2836,7 +2843,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::SimpleCallCo
\sa textBaseline
\sa fillText
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2871,7 +2878,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(QV4::SimpleCall
\qmlmethod variant QtQuick::Context2D::measureText(text)
Returns a TextMetrics object with the metrics of the given text in the current font.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2947,7 +2954,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::SimpleCal
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
@@ -2974,7 +2981,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::SimpleCallC
} else if (arg->isObject()) {
if (QV4::Referenced<QV4::QObjectWrapper> qobjectWrapper = arg->asRef<QV4::QObjectWrapper>()) {
if (QQuickImage *imageItem = qobject_cast<QQuickImage*>(qobjectWrapper->object())) {
- pixmap.take(r->context->createPixmap(imageItem->source()));
+ pixmap = r->context->createPixmap(imageItem->source());
} else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) {
QImage img = canvas->toImage();
if (!img.isNull())
@@ -3083,12 +3090,12 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::SimpleCallC
\qmlproperty int QtQuick::CanvasImageData::width
Holds the actual width dimension of the data in the ImageData object, in device pixels.
*/
-QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->callData->thisObject);
if (!imageData)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
if (!r)
return QV4::Encode(0);
@@ -3099,12 +3106,12 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(QV4::SimpleCallC
\qmlproperty int QtQuick::CanvasImageData::height
Holds the actual height dimension of the data in the ImageData object, in device pixels.
*/
-QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->callData->thisObject);
if (!imageData)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
if (!r)
return QV4::Encode(0);
@@ -3115,12 +3122,12 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(QV4::SimpleCall
\qmlproperty object QtQuick::CanvasImageData::data
Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
*/
-QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->callData->thisObject);
if (!imageData)
- ctx->throwTypeError();
+ return ctx->throwTypeError();
return imageData->pixelData.asReturnedValue();
}
@@ -3142,7 +3149,7 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(QV4::SimpleCallCo
The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
This property is read only.
*/
-QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, ctx->callData->thisObject.as<QQuickJSContext2DPixelData>());
@@ -3158,7 +3165,7 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint
QV4::Scope scope(v4);
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
if (!m)
- m->engine()->current->throwTypeError();
+ return m->engine()->current->throwTypeError();
if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
if (hasProperty)
@@ -3188,9 +3195,14 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
{
QV4::ExecutionEngine *v4 = m->engine();
QV4::Scope scope(v4);
+ if (scope.hasException())
+ return;
+
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
- if (!r)
- m->engine()->current->throwTypeError();
+ if (!r) {
+ v4->current->throwTypeError();
+ return;
+ }
const int v = value->toInt32();
if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4) && v >= 0 && v <= 255) {
@@ -3237,7 +3249,7 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
\sa Canvas::loadImage(), QtQuick::Canvas::unloadImage(),
QtQuick::Canvas::isImageLoaded
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
@@ -3277,7 +3289,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::Simpl
\qmlmethod CanvasImageData QtQuick::Context2D::getImageData(real sx, real sy, real sw, real sh)
Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
@@ -3305,7 +3317,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(QV4::SimpleCa
\qmlmethod object QtQuick::Context2D::putImageData(CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
Paints the data from the given ImageData object onto the canvas. If a dirty rectangle (\a dirtyX, \a dirtyY, \a dirtyWidth, \a dirtyHeight) is provided, only the pixels from that rectangle are painted.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
@@ -3406,7 +3418,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::SimpleCa
gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
\endcode
*/
-QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::SimpleCallContext *ctx)
+QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
QV4::Scoped<QQuickContext2DStyle> style(scope, ctx->callData->thisObject.as<QQuickContext2DStyle>());
@@ -4101,7 +4113,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_texture->moveToThread(renderThread);
if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
- QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->glContext();
+ QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->openglContext();
m_surface = window;
m_glContext = new QOpenGLContext;
m_glContext->setFormat(cc->format());
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index cbdc5fd80f..3996512f9d 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -139,6 +139,21 @@ HEADERS += \
$$PWD/qquickshadereffectnode_p.h \
$$PWD/qquickshadereffectsource_p.h \
-include(context2d/context2d.pri)
+OTHER_FILES += \
+ $$PWD/shaders/sprite.vert \
+ $$PWD/shaders/sprite.frag \
+ $$PWD/shaders/shadereffect.vert \
+ $$PWD/shaders/shadereffect.frag \
+ $$PWD/shaders/shadereffectfallback.vert \
+ $$PWD/shaders/shadereffectfallback.frag \
+ $$PWD/shaders/sprite_core.vert \
+ $$PWD/shaders/sprite_core.frag \
+ $$PWD/shaders/shadereffect_core.vert \
+ $$PWD/shaders/shadereffect_core.frag \
+ $$PWD/shaders/shadereffectfallback_core.vert \
+ $$PWD/shaders/shadereffectfallback_core.frag
+RESOURCES += \
+ $$PWD/items.qrc
+include(context2d/context2d.pri)
diff --git a/src/quick/items/items.qrc b/src/quick/items/items.qrc
new file mode 100644
index 0000000000..671d8acdbb
--- /dev/null
+++ b/src/quick/items/items.qrc
@@ -0,0 +1,16 @@
+<RCC>
+ <qresource prefix="/items">
+ <file>shaders/sprite.frag</file>
+ <file>shaders/sprite.vert</file>
+ <file>shaders/shadereffect.vert</file>
+ <file>shaders/shadereffect.frag</file>
+ <file>shaders/shadereffectfallback.frag</file>
+ <file>shaders/shadereffectfallback.vert</file>
+ <file>shaders/shadereffect_core.frag</file>
+ <file>shaders/shadereffect_core.vert</file>
+ <file>shaders/shadereffectfallback_core.frag</file>
+ <file>shaders/shadereffectfallback_core.vert</file>
+ <file>shaders/sprite_core.frag</file>
+ <file>shaders/sprite_core.vert</file>
+ </qresource>
+</RCC>
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 846de15581..64b8f257dc 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -57,39 +57,6 @@
QT_BEGIN_NAMESPACE
-static const char vertexShaderCode[] =
- "attribute highp vec2 vPos;\n"
- "attribute highp vec2 vTex;\n"
- "uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress\n"
- "uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation)\n"
- "\n"
- "uniform highp mat4 qt_Matrix;\n"
- "\n"
- "varying highp vec4 fTexS;\n"
- "varying lowp float progress;\n"
- "\n"
- "\n"
- "void main() {\n"
- " progress = animData.z;\n"
- " //Calculate frame location in texture\n"
- " fTexS.xy = animPos.xy + vTex.xy * animData.xy;\n"
- " //Next frame is also passed, for interpolation\n"
- " fTexS.zw = animPos.zw + vTex.xy * animData.xy;\n"
- "\n"
- " gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1);\n"
- "}\n";
-
-static const char fragmentShaderCode[] =
- "uniform sampler2D _qt_texture;\n"
- "uniform lowp float qt_Opacity;\n"
- "\n"
- "varying highp vec4 fTexS;\n"
- "varying lowp float progress;\n"
- "\n"
- "void main() {\n"
- " gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), texture2D(_qt_texture, fTexS.zw), progress) * qt_Opacity;\n"
- "}\n";
-
class QQuickAnimatedSpriteMaterial : public QSGMaterial
{
public:
@@ -134,16 +101,11 @@ QQuickAnimatedSpriteMaterial::~QQuickAnimatedSpriteMaterial()
class AnimatedSpriteMaterialData : public QSGMaterialShader
{
public:
- AnimatedSpriteMaterialData(const char * /* vertexFile */ = 0, const char * /* fragmentFile */ = 0)
+ AnimatedSpriteMaterialData()
+ : QSGMaterialShader()
{
- }
-
- void deactivate() {
- QSGMaterialShader::deactivate();
-
- for (int i=0; i<8; ++i) {
- program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
- }
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/items/shaders/sprite.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/items/shaders/sprite.frag"));
}
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
@@ -166,9 +128,6 @@ public:
m_animPos_id = program()->uniformLocation("animPos");
}
- virtual const char *vertexShader() const { return vertexShaderCode; }
- virtual const char *fragmentShader() const { return fragmentShaderCode; }
-
virtual char const *const *attributeNames() const {
static const char *attr[] = {
"vPos",
@@ -182,12 +141,8 @@ public:
int m_opacity_id;
int m_animData_id;
int m_animPos_id;
-
- static float chunkOfBytes[1024];
};
-float AnimatedSpriteMaterialData::chunkOfBytes[1024];
-
QSGMaterialShader *QQuickAnimatedSpriteMaterial::createShader() const
{
return new AnimatedSpriteMaterialData;
@@ -219,7 +174,7 @@ struct AnimatedSpriteVertices {
as multiple frames in the same image file. You can play it at a fixed speed, at the
frame rate of your display, or manually advance and control the progress.
- For details of how a sprite animation is defined see the \l{Sprite Animation} overview.
+ For details of how a sprite animation is defined see the \l{Sprite Animations} overview.
Note that the AnimatedSprite type does not use Sprite types to define multiple animations,
but instead encapsulates a single animation itself.
*/
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index 9fc9752707..0bed5e96a2 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -301,7 +301,7 @@ void QQuickBorderImage::load()
d->oldSourceSize = sourceSize();
emit sourceSizeChanged();
}
- update();
+ pixmapChange();
return;
} else {
if (d->url.path().endsWith(QLatin1String("sci"))) {
@@ -509,7 +509,7 @@ void QQuickBorderImage::requestFinished()
emit sourceSizeChanged();
}
- update();
+ pixmapChange();
}
#define BORDERIMAGE_MAX_REDIRECT 16
@@ -551,7 +551,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
{
Q_D(QQuickBorderImage);
- QSGTexture *texture = d->sceneGraphContext()->textureForFactory(d->pix.textureFactory(), window());
+ QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
if (!texture || width() <= 0 || height() <= 0) {
delete oldNode;
@@ -561,6 +561,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
bool updatePixmap = d->pixmapChanged;
+ d->pixmapChanged = false;
if (!node) {
node = d->sceneGraphContext()->createImageNode();
updatePixmap = true;
@@ -634,10 +635,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
void QQuickBorderImage::pixmapChange()
{
Q_D(QQuickBorderImage);
-
d->pixmapChanged = true;
-
- // When the pixmap changes, such as being deleted, we need to update the textures
update();
}
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index f0a68b184a..ae174d86e0 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1116,10 +1116,10 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
hData.velocity = 0;
}
- if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved)) {
- draggingStarting();
+ draggingStarting();
+
+ if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved))
q->movementStarting();
- }
qint64 currentTimestamp = computeCurrentTime(event);
qreal elapsed = qreal(currentTimestamp - (lastPos.isNull() ? lastPressTime : lastPosTime)) / 1000.;
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 1c6168fbc5..c9e6d4d7e2 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -1248,7 +1248,7 @@ bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
\image gridview-layout-toptobottom-rtl-btt.png
\endtable
- \sa {quick/modelviews/gridview}{GridView example}
+ \sa {QML Data Models}, ListView, PathView, {Qt Quick Examples - Views}
*/
QQuickGridView::QQuickGridView(QQuickItem *parent)
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index d6be13f3c0..0708304051 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -532,17 +532,17 @@ QRectF QQuickImage::boundingRect() const
QSGTextureProvider *QQuickImage::textureProvider() const
{
Q_D(const QQuickImage);
+
+ if (!d->window || !d->sceneGraphRenderContext() || QThread::currentThread() != d->sceneGraphRenderContext()->thread()) {
+ qWarning("QQuickImage::textureProvider: can only be queried on the rendering thread of an exposed window");
+ return 0;
+ }
+
if (!d->provider) {
- // Make sure it gets thread affinity on the rendering thread so deletion works properly..
- Q_ASSERT_X(d->window
- && d->sceneGraphContext()
- && QThread::currentThread() == d->sceneGraphContext()->thread(),
- "QQuickImage::textureProvider",
- "Cannot be used outside the GUI thread");
QQuickImagePrivate *dd = const_cast<QQuickImagePrivate *>(d);
dd->provider = new QQuickImageTextureProvider;
dd->provider->m_smooth = d->smooth;
- dd->provider->m_texture = d->sceneGraphContext()->textureForFactory(d->pix.textureFactory(), window());
+ dd->provider->m_texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
}
return d->provider;
@@ -552,7 +552,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickImage);
- QSGTexture *texture = d->sceneGraphContext()->textureForFactory(d->pix.textureFactory(), window());
+ QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
// Copy over the current texture state into the texture provider...
if (d->provider) {
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index c3b221b2c8..c11bf904be 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -732,7 +732,7 @@ void QQuickKeyNavigationAttached::setFocusNavigation(QQuickItem *currentItem, co
do {
isNextItem = false;
if (currentItem->isVisible() && currentItem->isEnabled()) {
- currentItem->setFocus(true);
+ currentItem->forceActiveFocus(Qt::OtherFocusReason);
} else {
QObject *attached =
qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(currentItem, false);
@@ -3827,7 +3827,12 @@ void QQuickItem::setBaselineOffset(qreal offset)
void QQuickItem::update()
{
Q_D(QQuickItem);
- Q_ASSERT(flags() & ItemHasContents);
+ if (!(flags() & ItemHasContents)) {
+#ifndef QT_NO_DEBUG
+ qWarning() << metaObject()->className() << ": Update called for a item without content";
+#endif
+ return;
+ }
d->dirty(QQuickItemPrivate::Content);
}
@@ -4125,7 +4130,7 @@ QQmlListProperty<QQuickItem> QQuickItemPrivate::children()
}
/*!
- \qmlproperty real QtQuick::Item::visibleChildren
+ \qmlproperty list<Item> QtQuick::Item::visibleChildren
This read-only property lists all of the item's children that are currently visible.
Note that a child's visibility may have changed explicitly, or because the visibility
of this (it's parent) item or another grandparent changed.
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index f731acabbb..7faf39f8e5 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -468,6 +468,7 @@ public:
QQuickWindow *window;
int windowRefCount;
inline QSGContext *sceneGraphContext() const;
+ inline QSGRenderContext *sceneGraphRenderContext() const;
QQuickItem *parentItem;
QQmlNotifier parentNotifier;
@@ -840,6 +841,12 @@ Qt::MouseButtons QQuickItemPrivate::acceptedMouseButtons() const
QSGContext *QQuickItemPrivate::sceneGraphContext() const
{
Q_ASSERT(window);
+ return static_cast<QQuickWindowPrivate *>(QObjectPrivate::get(window))->context->sceneGraphContext();
+}
+
+QSGRenderContext *QQuickItemPrivate::sceneGraphRenderContext() const
+{
+ Q_ASSERT(window);
return static_cast<QQuickWindowPrivate *>(QObjectPrivate::get(window))->context;
}
diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp
index 534ad0e2f4..b840ee421c 100644
--- a/src/quick/items/qquickitemanimation.cpp
+++ b/src/quick/items/qquickitemanimation.cpp
@@ -86,7 +86,7 @@ QT_BEGIN_NAMESPACE
ParentChange that has occurred during the state change. This can be
overridden by setting a specific target item using the \l target property.
- \sa {Animation and Transitions in Qt Quick}, {declarative/animation/basics}{Animation basics example}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickParentAnimation::QQuickParentAnimation(QObject *parent)
: QQuickAnimationGroup(*(new QQuickParentAnimationPrivate), parent)
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index daf76c377e..a5b78b28e1 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -188,6 +188,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTextEdit>(uri,major,minor,"TextEdit");
qmlRegisterType<QQuickTextEdit,1>(uri,2,1,"TextEdit");
qmlRegisterType<QQuickTextInput>(uri,major,minor,"TextInput");
+ qmlRegisterType<QQuickTextInput,2>(uri,2,2,"TextInput");
qmlRegisterType<QQuickViewSection>(uri,major,minor,"ViewSection");
qmlRegisterType<QQuickItemLayer>();
@@ -268,8 +269,17 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTextEdit, 2>(uri, 2, 2, "TextEdit");
}
+static void initResources()
+{
+ Q_INIT_RESOURCE(items);
+}
+
+QT_BEGIN_NAMESPACE
+
void QQuickItemsModule::defineModule()
{
+ initResources();
+
QByteArray name = "QtQuick";
int majorVersion = 2;
int minorVersion = 0;
@@ -277,3 +287,4 @@ void QQuickItemsModule::defineModule()
qt_quickitems_defineModule(name, majorVersion, minorVersion);
}
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 513f8f3857..d9ff024d9f 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1118,11 +1118,13 @@ void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &
if (header && header->item == item) {
updateHeader();
markExtentsDirty();
+ updateViewport();
if (!q->isMoving() && !q->isFlicking())
fixupPosition();
} else if (footer && footer->item == item) {
updateFooter();
markExtentsDirty();
+ updateViewport();
if (!q->isMoving() && !q->isFlicking())
fixupPosition();
}
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 22d8176086..c55f9ef696 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -1744,7 +1744,7 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
\image listview-layout-righttoleft.png
\endtable
- \sa {QML Data Models}, GridView, {quick/modelviews/listview}{ListView examples}
+ \sa {QML Data Models}, GridView, PathView, {Qt Quick Examples - Views}
*/
QQuickListView::QQuickListView(QQuickItem *parent)
: QQuickItemView(*(new QQuickListViewPrivate), parent)
@@ -1907,7 +1907,8 @@ QQuickListView::~QQuickListView()
so as to stay with the current item, unless the highlightFollowsCurrentItem
property is false.
- \sa highlightItem, highlightFollowsCurrentItem, {quick/modelviews/listview}{ListView examples}
+ \sa highlightItem, highlightFollowsCurrentItem,
+ {Qt Quick Examples - Views#Highlight demonstrates adding a custom highlight to a ListView.}{ListView highlight example}
*/
/*!
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index b9e6efaa10..ca64ebb6e3 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -156,7 +156,7 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
}
QQuickMouseArea* ma = qobject_cast<QQuickMouseArea*>(item);
- if (ma && ma != q && itemPrivate->acceptedMouseButtons() & ev->button()) {
+ if (ma && ma != q && ma->isEnabled() && itemPrivate->acceptedMouseButtons() & ev->button()) {
switch (sig) {
case Click:
if (!ma->d_func()->isClickConnected())
diff --git a/src/quick/items/qquickpainteditem.cpp b/src/quick/items/qquickpainteditem.cpp
index e0ac974022..3bf5d82e4d 100644
--- a/src/quick/items/qquickpainteditem.cpp
+++ b/src/quick/items/qquickpainteditem.cpp
@@ -276,7 +276,7 @@ void QQuickPaintedItem::setMipmap(bool enable)
/*!
Returns the performance hints.
- By default, no performance hint is enabled/
+ By default, no performance hint is enabled.
\sa setPerformanceHint(), setPerformanceHints()
*/
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index d8132bdd12..1f41fe04e5 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -553,7 +553,7 @@ void QQuickPathViewPrivate::setDragging(bool d)
to set \e {clip: true} in order to have the out of view items clipped
nicely.
- \sa Path, {quick/modelviews/pathview}{PathView example}
+ \sa Path, {QML Data Models}, ListView, GridView, {Qt Quick Examples - Views}
*/
QQuickPathView::QQuickPathView(QQuickItem *parent)
@@ -2031,7 +2031,7 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
const int modelCount = d->modelCount;
int moveId = -1;
- int moveOffset;
+ int moveOffset = 0;
bool currentChanged = false;
bool changedOffset = false;
foreach (const QQmlChangeSet::Remove &r, changeSet.removes()) {
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 75eccf6c59..48c0f8e084 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
/*!
\qmltype Screen
\instantiates QQuickScreenAttached
- \inqmlmodule QtQuick.Window 2
+ \inqmlmodule QtQuick.Window
\ingroup qtquick-visual-utility
\brief The Screen attached object provides information about the Screen an Item or Window is displayed on.
@@ -80,26 +80,26 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlattachedproperty String QtQuick.Window::Screen::name
+ \qmlattachedproperty string Screen::name
\readonly
\since 5.1
The name of the screen.
*/
/*!
- \qmlattachedproperty int QtQuick.Window::Screen::width
+ \qmlattachedproperty int Screen::width
\readonly
This contains the width of the screen in pixels.
*/
/*!
- \qmlattachedproperty int QtQuick.Window::Screen::height
+ \qmlattachedproperty int Screen::height
\readonly
This contains the height of the screen in pixels.
*/
/*!
- \qmlattachedproperty int QtQuick.Window::Screen::desktopAvailableWidth
+ \qmlattachedproperty int Screen::desktopAvailableWidth
\readonly
\since 5.1
@@ -113,7 +113,7 @@ QT_BEGIN_NAMESPACE
\endqml
*/
/*!
- \qmlattachedproperty int QtQuick.Window::Screen::desktopAvailableHeight
+ \qmlattachedproperty int Screen::desktopAvailableHeight
\readonly
\since 5.1
@@ -127,16 +127,30 @@ QT_BEGIN_NAMESPACE
\endqml
*/
/*!
- \qmlattachedproperty real QtQuick.Window::Screen::logicalPixelDensity
+ \qmlattachedproperty real Screen::logicalPixelDensity
\readonly
\since 5.1
+ \deprecated
- The number of logical pixels per millimeter. Logical pixels are the
- usual units in QML; on some systems they may be different than physical
- pixels.
+ The number of logical pixels per millimeter. This is the effective pixel
+ density provided by the platform to use in image scaling calculations.
+
+ Due to inconsistencies in how logical pixel density is handled across
+ the various platforms Qt supports, it is recommended to
+ use physical pixels instead (via the \c pixelDensity property) for
+ portability.
+
+ \sa pixelDensity
+*/
+/*!
+ \qmlattachedproperty real Screen::pixelDensity
+ \readonly
+ \since 5.2
+
+ The number of physical pixels per millimeter.
*/
/*!
- \qmlattachedproperty Qt::ScreenOrientation QtQuick.Window::Screen::primaryOrientation
+ \qmlattachedproperty Qt::ScreenOrientation Screen::primaryOrientation
\readonly
This contains the primary orientation of the screen. If the
@@ -153,7 +167,7 @@ QT_BEGIN_NAMESPACE
automatically, so again you will see the primaryOrientation change.
*/
/*!
- \qmlattachedproperty Qt::ScreenOrientation QtQuick.Window::Screen::orientation
+ \qmlattachedproperty Qt::ScreenOrientation Screen::orientation
\readonly
This contains the current orientation of the screen, from the accelerometer
@@ -167,7 +181,7 @@ QT_BEGIN_NAMESPACE
\l Item.transform to rotate your content.
*/
/*!
- \qmlattachedmethod int QtQuick.Window::Screen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b)
+ \qmlattachedmethod int Screen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b)
Returns the rotation angle, in degrees, between the two specified angles.
*/
@@ -233,6 +247,13 @@ qreal QQuickScreenAttached::logicalPixelDensity() const
return m_screen->logicalDotsPerInch() / 25.4;
}
+qreal QQuickScreenAttached::pixelDensity() const
+{
+ if (!m_screen)
+ return 0.0;
+ return m_screen->physicalDotsPerInch() / 25.4;
+}
+
Qt::ScreenOrientation QQuickScreenAttached::primaryOrientation() const
{
if (!m_screen)
@@ -291,6 +312,8 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
emit desktopGeometryChanged();
if (!oldScreen || screen->logicalDotsPerInch() != oldScreen->logicalDotsPerInch())
emit logicalPixelDensityChanged();
+ if (!oldScreen || screen->physicalDotsPerInch() != oldScreen->physicalDotsPerInch())
+ emit pixelDensityChanged();
connect(screen, SIGNAL(geometryChanged(QRect)),
this, SIGNAL(widthChanged()));
@@ -304,6 +327,8 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
this, SIGNAL(desktopGeometryChanged()));
connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)),
this, SIGNAL(logicalPixelDensityChanged()));
+ connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)),
+ this, SIGNAL(pixelDensityChanged()));
}
}
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index 0f1e79b1a2..a155ff1843 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -64,6 +64,7 @@ class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject
Q_PROPERTY(int desktopAvailableWidth READ desktopAvailableWidth NOTIFY desktopGeometryChanged REVISION 1)
Q_PROPERTY(int desktopAvailableHeight READ desktopAvailableHeight NOTIFY desktopGeometryChanged REVISION 1)
Q_PROPERTY(qreal logicalPixelDensity READ logicalPixelDensity NOTIFY logicalPixelDensityChanged REVISION 1)
+ Q_PROPERTY(qreal pixelDensity READ pixelDensity NOTIFY pixelDensityChanged REVISION 2)
Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY primaryOrientationChanged)
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
@@ -76,6 +77,7 @@ public:
int desktopAvailableWidth() const;
int desktopAvailableHeight() const;
qreal logicalPixelDensity() const;
+ qreal pixelDensity() const;
Qt::ScreenOrientation primaryOrientation() const;
Qt::ScreenOrientation orientation() const;
@@ -90,6 +92,7 @@ Q_SIGNALS:
void heightChanged();
Q_REVISION(1) void desktopGeometryChanged();
Q_REVISION(1) void logicalPixelDensityChanged();
+ Q_REVISION(2) void pixelDensityChanged();
void primaryOrientationChanged();
void orientationChanged();
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 354b9f751b..9a20703f18 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -43,6 +43,7 @@
#include <private/qquickshadereffectnode_p.h>
#include <QtQuick/qsgmaterial.h>
+#include <QtQuick/private/qsgshadersourcebuilder_p.h>
#include "qquickitem_p.h"
#include <QtQuick/private/qsgcontext_p.h>
@@ -57,24 +58,6 @@
QT_BEGIN_NAMESPACE
-static const char qt_default_vertex_code[] =
- "uniform highp mat4 qt_Matrix; \n"
- "attribute highp vec4 qt_Vertex; \n"
- "attribute highp vec2 qt_MultiTexCoord0; \n"
- "varying highp vec2 qt_TexCoord0; \n"
- "void main() { \n"
- " qt_TexCoord0 = qt_MultiTexCoord0; \n"
- " gl_Position = qt_Matrix * qt_Vertex; \n"
- "}";
-
-static const char qt_default_fragment_code[] =
- "varying highp vec2 qt_TexCoord0; \n"
- "uniform sampler2D source; \n"
- "uniform lowp float qt_Opacity; \n"
- "void main() { \n"
- " gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; \n"
- "}";
-
static const char qt_position_attribute_name[] = "qt_Vertex";
static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
@@ -576,6 +559,7 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
\li QVector4D -> vec4
\li QTransform -> mat3
\li QMatrix4x4 -> mat4
+ \li QQuaternion -> vec4, scalar value is \c w.
\li \l Image, \l ShaderEffectSource -> sampler2D - Origin is in the top-left
corner, and the color values are premultiplied.
\endlist
@@ -979,10 +963,16 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
if (m_dirtyProgram) {
Key s = m_common.source;
- if (s.sourceCode[Key::FragmentShader].isEmpty())
- s.sourceCode[Key::FragmentShader] = qt_default_fragment_code;
- if (s.sourceCode[Key::VertexShader].isEmpty())
- s.sourceCode[Key::VertexShader] = qt_default_vertex_code;
+ QSGShaderSourceBuilder builder;
+ if (s.sourceCode[Key::FragmentShader].isEmpty()) {
+ builder.appendSourceFile(QStringLiteral(":/items/shaders/shadereffect.frag"));
+ s.sourceCode[Key::FragmentShader] = builder.source();
+ builder.clear();
+ }
+ if (s.sourceCode[Key::VertexShader].isEmpty()) {
+ builder.appendSourceFile(QStringLiteral(":/items/shaders/shadereffect.vert"));
+ s.sourceCode[Key::VertexShader] = builder.source();
+ }
s.className = metaObject()->className();
material->setProgramSource(s);
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index b84d251de5..3ab13dbbc7 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -45,6 +45,7 @@
#include "qquickshadereffect_p.h"
#include <QtQuick/qsgtextureprovider.h>
#include <QtQuick/private/qsgrenderer_p.h>
+#include <QtQuick/private/qsgshadersourcebuilder_p.h>
QT_BEGIN_NAMESPACE
@@ -196,6 +197,12 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
case QMetaType::QVector4D:
program()->setUniformValue(loc, qvariant_cast<QVector4D>(d.value));
break;
+ case QMetaType::QQuaternion:
+ {
+ QQuaternion q = qvariant_cast<QQuaternion>(d.value);
+ program()->setUniformValue(loc, q.x(), q.y(), q.z(), q.scalar());
+ }
+ break;
case QMetaType::QMatrix4x4:
program()->setUniformValue(loc, qvariant_cast<QMatrix4x4>(d.value));
break;
@@ -276,20 +283,15 @@ void QQuickCustomMaterialShader::compile()
m_log += program()->log();
}
- static const char fallbackVertexShader[] =
- "uniform highp mat4 qt_Matrix;"
- "attribute highp vec4 v;"
- "void main() { gl_Position = qt_Matrix * v; }";
- static const char fallbackFragmentShader[] =
- "void main() { gl_FragColor = vec4(1., 0., 1., 1.); }";
-
if (!m_compiled) {
qWarning("QQuickCustomMaterialShader: Shader compilation failed:");
qWarning() << program()->log();
- program()->removeAllShaders();
- program()->addShaderFromSourceCode(QOpenGLShader::Vertex, fallbackVertexShader);
- program()->addShaderFromSourceCode(QOpenGLShader::Fragment, fallbackFragmentShader);
+ QSGShaderSourceBuilder::initializeProgramFromFiles(
+ program(),
+ QStringLiteral(":/items/shaders/shadereffectfallback.vert"),
+ QStringLiteral(":/items/shaders/shadereffectfallback.frag"));
+
#ifndef QT_NO_DEBUG
for (int i = 0; i < attrCount; ++i) {
#else
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index e86550d731..e076a342df 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -45,6 +45,7 @@
#include "qquickwindow_p.h"
#include <private/qsgadaptationlayer_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
+#include <qsgsimplerectnode.h>
#include "qopenglframebufferobject.h"
#include "qmath.h"
@@ -140,10 +141,11 @@ QQuickShaderEffectTexture::QQuickShaderEffectTexture(QQuickItem *shaderSource)
, m_renderer(0)
, m_fbo(0)
, m_secondaryFbo(0)
+ , m_transparentTexture(0)
#ifdef QSG_DEBUG_FBO_OVERLAY
, m_debugOverlay(0)
#endif
- , m_context(QQuickItemPrivate::get(shaderSource)->sceneGraphContext())
+ , m_context(QQuickItemPrivate::get(shaderSource)->sceneGraphRenderContext())
, m_mipmap(false)
, m_live(true)
, m_recursive(false)
@@ -164,6 +166,8 @@ QQuickShaderEffectTexture::~QQuickShaderEffectTexture()
#ifdef QSG_DEBUG_FBO_OVERLAY
delete m_debugOverlay;
#endif
+ if (m_transparentTexture)
+ glDeleteTextures(1, &m_transparentTexture);
}
int QQuickShaderEffectTexture::textureId() const
@@ -188,8 +192,20 @@ void QQuickShaderEffectTexture::bind()
if (!m_recursive && m_fbo && ((m_multisampling && m_secondaryFbo->isBound()) || m_fbo->isBound()))
qWarning("ShaderEffectSource: \'recursive\' must be set to true when rendering recursively.");
#endif
- glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
- updateBindOptions();
+
+ if (!m_fbo && m_format == GL_RGBA) {
+ if (m_transparentTexture == 0) {
+ glGenTextures(1, &m_transparentTexture);
+ glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
+ const uint zero = 0;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
+ }
+ } else {
+ glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
+ updateBindOptions();
+ }
}
bool QQuickShaderEffectTexture::updateTexture()
@@ -326,7 +342,7 @@ void QQuickShaderEffectTexture::grab()
|| (!m_fbo->format().mipmap() && m_mipmap))
{
if (!m_multisamplingChecked) {
- if (m_context->glContext()->format().samples() <= 1) {
+ if (m_context->openglContext()->format().samples() <= 1) {
m_multisampling = false;
} else {
QList<QByteArray> extensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' ');
@@ -342,7 +358,7 @@ void QQuickShaderEffectTexture::grab()
QOpenGLFramebufferObjectFormat format;
format.setInternalTextureFormat(m_format);
- format.setSamples(m_context->glContext()->format().samples());
+ format.setSamples(m_context->openglContext()->format().samples());
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
} else {
@@ -385,20 +401,16 @@ void QQuickShaderEffectTexture::grab()
#ifdef QSG_DEBUG_FBO_OVERLAY
if (qmlFboOverlay()) {
if (!m_debugOverlay)
- m_debugOverlay = m_context->createRectangleNode();
+ m_debugOverlay = new QSGSimpleRectNode();
m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height()));
m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40));
- m_debugOverlay->setPenColor(QColor());
- m_debugOverlay->setPenWidth(0);
- m_debugOverlay->setRadius(0);
- m_debugOverlay->update();
root->appendChildNode(m_debugOverlay);
}
#endif
m_dirtyTexture = false;
- QOpenGLContext *ctx = m_context->glContext();
+ QOpenGLContext *ctx = m_context->openglContext();
m_renderer->setDeviceRect(m_size);
m_renderer->setViewportRect(m_size);
QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height());
@@ -591,8 +603,8 @@ void QQuickShaderEffectSource::ensureTexture()
return;
Q_ASSERT_X(QQuickItemPrivate::get(this)->window
- && QQuickItemPrivate::get(this)->sceneGraphContext()
- && QThread::currentThread() == QQuickItemPrivate::get(this)->sceneGraphContext()->thread(),
+ && QQuickItemPrivate::get(this)->sceneGraphRenderContext()
+ && QThread::currentThread() == QQuickItemPrivate::get(this)->sceneGraphRenderContext()->thread(),
"QQuickShaderEffectSource::ensureTexture",
"Cannot be used outside the rendering thread");
@@ -603,13 +615,13 @@ void QQuickShaderEffectSource::ensureTexture()
QSGTextureProvider *QQuickShaderEffectSource::textureProvider() const
{
+ const QQuickItemPrivate *d = QQuickItemPrivate::get(this);
+ if (!d->window || !d->sceneGraphRenderContext() || QThread::currentThread() != d->sceneGraphRenderContext()->thread()) {
+ qWarning("QQuickShaderEffectSource::textureProvider: can only be queried on the rendering thread of an exposed window");
+ return 0;
+ }
+
if (!m_provider) {
- // Make sure it gets thread affinity on the rendering thread so deletion works properly..
- Q_ASSERT_X(QQuickItemPrivate::get(this)->window
- && QQuickItemPrivate::get(this)->sceneGraphContext()
- && QThread::currentThread() == QQuickItemPrivate::get(this)->sceneGraphContext()->thread(),
- "QQuickShaderEffectSource::textureProvider",
- "Cannot be used outside the rendering thread");
const_cast<QQuickShaderEffectSource *>(this)->m_provider = new QQuickShaderEffectSourceTextureProvider();
const_cast<QQuickShaderEffectSource *>(this)->ensureTexture();
connect(m_texture, SIGNAL(updateRequested()), m_provider, SIGNAL(textureChanged()));
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 7d1a9b7304..6218775700 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE
class QSGNode;
class UpdatePaintNodeData;
class QOpenGLFramebufferObject;
+class QSGSimpleRectNode;
class QQuickShaderEffectSourceTextureProvider;
@@ -138,11 +139,13 @@ private:
QOpenGLFramebufferObject *m_secondaryFbo;
QSharedPointer<QSGDepthStencilBuffer> m_depthStencilBuffer;
+ GLuint m_transparentTexture;
+
#ifdef QSG_DEBUG_FBO_OVERLAY
- QSGRectangleNode *m_debugOverlay;
+ QSGSimpleRectNode *m_debugOverlay;
#endif
- QSGContext *m_context;
+ QSGRenderContext *m_context;
uint m_mipmap : 1;
uint m_live : 1;
diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp
index b2bfb69bab..00a265c814 100644
--- a/src/quick/items/qquicksprite.cpp
+++ b/src/quick/items/qquicksprite.cpp
@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
can be in the middle of an image file, or split along multiple rows, as long as they form
a contiguous line wrapping to the next row of the file from the left edge of the file.
- For full details, see the \l{Sprite Animation} overview.
+ For full details, see the \l{Sprite Animations} overview.
*/
/*!
\qmlproperty int QtQuick::Sprite::duration
diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp
index 3c1492e0b3..a90aa9ace2 100644
--- a/src/quick/items/qquickspritesequence.cpp
+++ b/src/quick/items/qquickspritesequence.cpp
@@ -56,39 +56,6 @@
QT_BEGIN_NAMESPACE
-static const char vertexShaderCode[] =
- "attribute highp vec2 vPos;\n"
- "attribute highp vec2 vTex;\n"
- "uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress\n"
- "uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation)\n"
- "\n"
- "uniform highp mat4 qt_Matrix;\n"
- "\n"
- "varying highp vec4 fTexS;\n"
- "varying lowp float progress;\n"
- "\n"
- "\n"
- "void main() {\n"
- " progress = animData.z;\n"
- " //Calculate frame location in texture\n"
- " fTexS.xy = animPos.xy + vTex.xy * animData.xy;\n"
- " //Next frame is also passed, for interpolation\n"
- " fTexS.zw = animPos.zw + vTex.xy * animData.xy;\n"
- "\n"
- " gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1);\n"
- "}\n";
-
-static const char fragmentShaderCode[] =
- "uniform sampler2D _qt_texture;\n"
- "uniform lowp float qt_Opacity;\n"
- "\n"
- "varying highp vec4 fTexS;\n"
- "varying lowp float progress;\n"
- "\n"
- "void main() {\n"
- " gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), texture2D(_qt_texture, fTexS.zw), progress) * qt_Opacity;\n"
- "}\n";
-
class QQuickSpriteSequenceMaterial : public QSGMaterial
{
public:
@@ -133,16 +100,11 @@ QQuickSpriteSequenceMaterial::~QQuickSpriteSequenceMaterial()
class SpriteSequenceMaterialData : public QSGMaterialShader
{
public:
- SpriteSequenceMaterialData(const char * /* vertexFile */ = 0, const char * /* fragmentFile */ = 0)
+ SpriteSequenceMaterialData()
+ : QSGMaterialShader()
{
- }
-
- void deactivate() {
- QSGMaterialShader::deactivate();
-
- for (int i=0; i<8; ++i) {
- program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
- }
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/items/shaders/sprite.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/items/shaders/sprite.frag"));
}
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
@@ -165,9 +127,6 @@ public:
m_animPos_id = program()->uniformLocation("animPos");
}
- virtual const char *vertexShader() const { return vertexShaderCode; }
- virtual const char *fragmentShader() const { return fragmentShaderCode; }
-
virtual char const *const *attributeNames() const {
static const char *attr[] = {
"vPos",
@@ -181,12 +140,8 @@ public:
int m_opacity_id;
int m_animData_id;
int m_animPos_id;
-
- static float chunkOfBytes[1024];
};
-float SpriteSequenceMaterialData::chunkOfBytes[1024];
-
QSGMaterialShader *QQuickSpriteSequenceMaterial::createShader() const
{
return new SpriteSequenceMaterialData;
@@ -217,7 +172,7 @@ struct SpriteVertices {
SpriteSequence renders and controls a list of animations defined
by \l Sprite types.
- For full details, see the \l{Sprite Animation} overview.
+ For full details, see the \l{Sprite Animations} overview.
*/
/*!
\qmlproperty bool QtQuick::SpriteSequence::running
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index fbda2df2dc..d62bf8efa1 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -107,7 +107,6 @@ void QQuickTextPrivate::init()
Q_Q(QQuickText);
q->setAcceptedMouseButtons(Qt::LeftButton);
q->setFlag(QQuickItem::ItemHasContents);
- q->setAcceptHoverEvents(true);
}
QQuickTextDocumentWithImageResources::QQuickTextDocumentWithImageResources(QQuickItem *parent)
@@ -1523,6 +1522,7 @@ void QQuickText::setText(const QString &n)
qDeleteAll(d->imgTags);
d->imgTags.clear();
d->updateLayout();
+ setAcceptHoverEvents(d->richText || d->styledText);
emit textChanged(d->text);
}
@@ -2002,6 +2002,7 @@ void QQuickText::setTextFormat(TextFormat format)
d->determineHorizontalAlignment();
}
d->updateLayout();
+ setAcceptHoverEvents(d->richText || d->styledText);
emit textFormatChanged(d->format);
}
@@ -2241,11 +2242,10 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height(), height(), d->vAlign);
QQuickTextNode *node = 0;
- if (!oldNode) {
- node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
- } else {
+ if (!oldNode)
+ node = new QQuickTextNode(this);
+ else
node = static_cast<QQuickTextNode *>(oldNode);
- }
node->setUseNativeRenderer(d->renderType == NativeRendering && d->window->devicePixelRatio() <= 1);
node->deleteContent();
@@ -2635,34 +2635,34 @@ void QQuickTextPrivate::processHoverEvent(QHoverEvent *event)
{
Q_Q(QQuickText);
QString link;
- if (event->type() != QEvent::HoverLeave)
- link = anchorAt(event->posF());
+ if (isLinkHoveredConnected()) {
+ if (event->type() != QEvent::HoverLeave)
+ link = anchorAt(event->posF());
- if ((!extra.isAllocated() && !link.isEmpty()) || (extra.isAllocated() && extra->hoveredLink != link)) {
- extra.value().hoveredLink = link;
- emit q->linkHovered(extra->hoveredLink);
+ if ((!extra.isAllocated() && !link.isEmpty()) || (extra.isAllocated() && extra->hoveredLink != link)) {
+ extra.value().hoveredLink = link;
+ emit q->linkHovered(extra->hoveredLink);
+ }
}
+ event->setAccepted(!link.isEmpty());
}
void QQuickText::hoverEnterEvent(QHoverEvent *event)
{
Q_D(QQuickText);
- if (d->isLinkHoveredConnected())
- d->processHoverEvent(event);
+ d->processHoverEvent(event);
}
void QQuickText::hoverMoveEvent(QHoverEvent *event)
{
Q_D(QQuickText);
- if (d->isLinkHoveredConnected())
- d->processHoverEvent(event);
+ d->processHoverEvent(event);
}
void QQuickText::hoverLeaveEvent(QHoverEvent *event)
{
Q_D(QQuickText);
- if (d->isLinkHoveredConnected())
- d->processHoverEvent(event);
+ d->processHoverEvent(event);
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 48518f1ba3..ffc732621d 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1769,6 +1769,9 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
d->updateType = QQuickTextEditPrivate::UpdateNone;
+ if (!oldNode) // If we had any text node references, they were deleted along with the root node
+ d->textNodeMap.clear();
+
RootNode *rootNode = static_cast<RootNode *>(oldNode);
TextNodeIterator nodeIterator = d->textNodeMap.begin();
while (nodeIterator != d->textNodeMap.end() && !(*nodeIterator)->dirty())
@@ -2367,7 +2370,7 @@ void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QSGTransformNode *root, QQu
QQuickTextNode *QQuickTextEditPrivate::createTextNode()
{
Q_Q(QQuickTextEdit);
- QQuickTextNode* node = new QQuickTextNode(QQuickItemPrivate::get(q)->sceneGraphContext(), q);
+ QQuickTextNode* node = new QQuickTextNode(q);
node->setUseNativeRenderer(renderType == QQuickTextEdit::NativeRendering && window->devicePixelRatio() <= 1);
node->initEngine(color, selectedTextColor, selectionColor);
return node;
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 1848fbb80b..c56f3648e6 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1212,6 +1212,17 @@ bool QQuickTextInput::hasAcceptableInput() const
state.
*/
+/*!
+ \qmlsignal QtQuick::TextInput::onEditingFinished()
+ \since 5.2
+
+ This handler is called 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
+ the inputMask and the validator returns an acceptable state.
+*/
+
#ifndef QT_NO_IM
Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
{
@@ -1834,7 +1845,7 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
if (node == 0)
- node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
+ node = new QQuickTextNode(this);
d->textNode = node;
if (!d->textLayoutDirty && oldNode != 0) {
@@ -2522,6 +2533,9 @@ void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
&& !persistentSelection)
deselect();
+ if (hasAcceptableInput(m_text) || fixup())
+ emit q->editingFinished();
+
#ifndef QT_NO_IM
q->disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
q, SLOT(q_updateAlignment()));
@@ -3378,7 +3392,6 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
*/
void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
{
- Q_Q(QQuickTextInput);
internalDeselect();
QString oldText = m_text;
if (m_maskData) {
@@ -3396,6 +3409,7 @@ void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool e
#ifdef QT_NO_ACCESSIBILITY
Q_UNUSED(changed)
#else
+ Q_Q(QQuickTextInput);
if (changed && QAccessible::isActive()) {
if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
@@ -4105,6 +4119,7 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
if (hasAcceptableInput(m_text) || fixup()) {
emit q->accepted();
+ emit q->editingFinished();
}
event->ignore();
return;
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index 2b72afb9dc..5f0250aaf1 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -284,6 +284,7 @@ Q_SIGNALS:
void selectedTextChanged();
void accepted();
void acceptableInputChanged();
+ Q_REVISION(2) void editingFinished();
void colorChanged();
void selectionColorChanged();
void selectedTextColorChanged();
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index 1f4ca34b13..18ee1a479d 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -47,6 +47,7 @@
#include <private/qsgadaptationlayer_p.h>
#include <private/qsgdistancefieldglyphnode_p.h>
#include <private/qquickclipnode_p.h>
+#include <private/qquickitem_p.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <QtCore/qpoint.h>
@@ -80,8 +81,8 @@ namespace {
/*!
Creates an empty QQuickTextNode
*/
-QQuickTextNode::QQuickTextNode(QSGContext *context, QQuickItem *ownerElement)
- : m_context(context), m_cursorNode(0), m_ownerElement(ownerElement), m_useNativeRenderer(false)
+QQuickTextNode::QQuickTextNode(QQuickItem *ownerElement)
+ : m_cursorNode(0), m_ownerElement(ownerElement), m_useNativeRenderer(false)
{
#ifdef QSG_RUNTIME_DESCRIPTION
qsgnode_set_description(this, QLatin1String("text"));
@@ -141,9 +142,14 @@ QSGGlyphNode *QQuickTextNode::addGlyphs(const QPointF &position, const QGlyphRun
QQuickText::TextStyle style, const QColor &styleColor,
QSGNode *parentNode)
{
- QSGGlyphNode *node = m_useNativeRenderer
- ? m_context->createNativeGlyphNode()
- : m_context->createGlyphNode();
+ QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
+ QRawFont font = glyphs.rawFont();
+ bool smoothScalable = QFontDatabase().isSmoothlyScalable(font.familyName(),
+ font.styleName());
+ QSGGlyphNode *node = m_useNativeRenderer || !smoothScalable
+ ? sg->sceneGraphContext()->createNativeGlyphNode(sg)
+ : sg->sceneGraphContext()->createGlyphNode(sg);
+
node->setOwnerElement(m_ownerElement);
node->setGlyphs(position + QPointF(0, glyphs.rawFont().ascent()), glyphs);
node->setStyle(style);
@@ -189,8 +195,9 @@ void QQuickTextNode::initEngine(const QColor& textColor, const QColor& selectedT
void QQuickTextNode::addImage(const QRectF &rect, const QImage &image)
{
- QSGImageNode *node = m_context->createImageNode();
- QSGTexture *texture = m_context->createTexture(image);
+ QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
+ QSGImageNode *node = sg->sceneGraphContext()->createImageNode();
+ QSGTexture *texture = sg->createTexture(image);
m_textures.append(texture);
node->setTargetRect(rect);
node->setInnerTargetRect(rect);
diff --git a/src/quick/items/qquicktextnode_p.h b/src/quick/items/qquicktextnode_p.h
index 64f396eb10..0bff0d5cff 100644
--- a/src/quick/items/qquicktextnode_p.h
+++ b/src/quick/items/qquicktextnode_p.h
@@ -77,7 +77,7 @@ public:
};
Q_DECLARE_FLAGS(Decorations, Decoration)
- QQuickTextNode(QSGContext *, QQuickItem *ownerElement);
+ QQuickTextNode(QQuickItem *ownerElement);
~QQuickTextNode();
static bool isComplexRichText(QTextDocument *);
@@ -110,7 +110,6 @@ private:
void initEngine(const QColor &textColor, const QColor &selectedTextColor, const QColor &selectionColor, const QColor& anchorColor = QColor()
, const QPointF &position = QPointF());
- QSGContext *m_context;
QSGSimpleRectNode *m_cursorNode;
QList<QSGTexture *> m_textures;
QQuickItem *m_ownerElement;
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index fe7effa4f1..e9ff70e00b 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -898,8 +898,8 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
int fragmentEnd = textPos + fragment.length();
#ifndef QT_NO_IM
if (preeditPosition >= 0
- && preeditPosition >= textPos
- && preeditPosition <= fragmentEnd) {
+ && (preeditPosition + block.position()) >= textPos
+ && (preeditPosition + block.position()) <= fragmentEnd) {
fragmentEnd += preeditLength;
}
#endif
diff --git a/src/quick/items/qquicktranslate.cpp b/src/quick/items/qquicktranslate.cpp
index 1ea5a6f7d6..93104ffa7a 100644
--- a/src/quick/items/qquicktranslate.cpp
+++ b/src/quick/items/qquicktranslate.cpp
@@ -335,7 +335,7 @@ public:
\image axisrotation.png
- \sa {declarative/ui-components/dialcontrol}{Dial Control example}, {declarative/toys/clocks}{Clocks example}
+ \sa {declarative/ui-components/dialcontrol}{Dial Control example}, {Qt Quick Demo - Clocks}
*/
QQuickRotation::QQuickRotation(QObject *parent)
: QQuickTransform(*new QQuickRotationPrivate, parent)
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 894059e193..a993889c45 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -50,8 +50,6 @@
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgtexture_p.h>
-#include <QtQuick/private/qsgflashnode_p.h>
-
#include <private/qsgrenderloop_p.h>
#include <private/qquickanimatorcontroller_p.h>
@@ -218,6 +216,7 @@ void QQuickWindow::exposeEvent(QExposeEvent *)
/*! \reimp */
void QQuickWindow::resizeEvent(QResizeEvent *)
{
+ d_func()->windowManager->resize(this);
}
/*! \reimp */
@@ -416,12 +415,13 @@ void QQuickWindowPrivate::init(QQuickWindow *c)
contentItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
windowManager = QSGRenderLoop::instance();
- context = windowManager->sceneGraphContext();
+ QSGContext *sg = windowManager->sceneGraphContext();
+ context = windowManager->createRenderContext(sg);
q->setSurfaceType(QWindow::OpenGLSurface);
- q->setFormat(context->defaultSurfaceFormat());
+ q->setFormat(sg->defaultSurfaceFormat());
animationController = new QQuickAnimatorController();
- animationController->window = q;
+ animationController->m_window = q;
QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
@@ -666,14 +666,18 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QVarLengthArray<QQuickItem *, 20> changed;
// Does this change the active focus?
- if (item == contentItem || (scopePrivate->activeFocus && item->isEnabled())) {
+ if (item == contentItem || scopePrivate->activeFocus) {
QQuickItem *oldActiveFocusItem = 0;
oldActiveFocusItem = activeFocusItem;
- newActiveFocusItem = item;
- while (newActiveFocusItem->isFocusScope()
- && newActiveFocusItem->scopedFocusItem()
- && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
- newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+ if (item->isEnabled()) {
+ newActiveFocusItem = item;
+ while (newActiveFocusItem->isFocusScope()
+ && newActiveFocusItem->scopedFocusItem()
+ && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
+ newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+ }
+ } else {
+ newActiveFocusItem = scope;
}
if (oldActiveFocusItem) {
@@ -772,23 +776,24 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
oldActiveFocusItem = activeFocusItem;
newActiveFocusItem = scope;
- Q_ASSERT(oldActiveFocusItem);
-
#ifndef QT_NO_IM
qApp->inputMethod()->commit();
#endif
activeFocusItem = 0;
- QFocusEvent event(QEvent::FocusOut, reason);
- q->sendEvent(oldActiveFocusItem, &event);
- QQuickItem *afi = oldActiveFocusItem;
- while (afi && afi != scope) {
- if (QQuickItemPrivate::get(afi)->activeFocus) {
- QQuickItemPrivate::get(afi)->activeFocus = false;
- changed << afi;
+ if (oldActiveFocusItem) {
+ QFocusEvent event(QEvent::FocusOut, reason);
+ q->sendEvent(oldActiveFocusItem, &event);
+
+ QQuickItem *afi = oldActiveFocusItem;
+ while (afi && afi != scope) {
+ if (QQuickItemPrivate::get(afi)->activeFocus) {
+ QQuickItemPrivate::get(afi)->activeFocus = false;
+ changed << afi;
+ }
+ afi = afi->parentItem();
}
- afi = afi->parentItem();
}
}
@@ -821,6 +826,11 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
notifyFocusChangesRecur(changed.data(), changed.count() - 1);
}
+void QQuickWindowPrivate::clearFocusObject()
+{
+ contentItem->setFocus(false, Qt::OtherFocusReason);
+}
+
void QQuickWindowPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
{
QPointer<QQuickItem> item(*items);
@@ -862,7 +872,7 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
/*!
\qmltype Window
\instantiates QQuickWindow
- \inqmlmodule QtQuick.Window 2
+ \inqmlmodule QtQuick.Window
\ingroup qtquick-visual
\brief Creates a new top-level window
@@ -2136,7 +2146,7 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent
}
/*!
- \qmlproperty list<Object> QtQuick.Window::Window::data
+ \qmlproperty list<Object> Window::data
\default
The data property allows you to freely mix visual children, resources
@@ -2345,10 +2355,6 @@ void QQuickWindowPrivate::updateDirtyNodes()
void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
{
-#ifdef QML_RUNTIME_TESTING
- bool didFlash = false;
-#endif
-
QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
quint32 dirty = itemPriv->dirtyAttributes;
itemPriv->dirtyAttributes = 0;
@@ -2572,19 +2578,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
}
#endif
-#ifdef QML_RUNTIME_TESTING
- if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
- QSGFlashNode *flash = new QSGFlashNode();
- flash->setRect(item->boundingRect());
- itemPriv->childContainerNode()->appendChildNode(flash);
- didFlash = true;
- }
- Q_Q(QQuickWindow);
- if (didFlash) {
- q->maybeUpdate();
- }
-#endif
-
}
void QQuickWindow::maybeUpdate()
@@ -2624,9 +2617,7 @@ void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
QOpenGLContext *QQuickWindow::openglContext() const
{
Q_D(const QQuickWindow);
- if (d->context->isReady())
- return d->context->glContext();
- return 0;
+ return d->context->openglContext();
}
/*!
@@ -2672,7 +2663,7 @@ QOpenGLContext *QQuickWindow::openglContext() const
/*!
\qmltype CloseEvent
\instantiates QQuickCloseEvent
- \inqmlmodule QtQuick.Window 2
+ \inqmlmodule QtQuick.Window
\ingroup qtquick-visual
\brief Notification that a \l Window is about to be closed
\since 5.1
@@ -2685,7 +2676,7 @@ QOpenGLContext *QQuickWindow::openglContext() const
*/
/*!
- \qmlproperty bool QtQuick.Window::CloseEvent::accepted
+ \qmlproperty bool CloseEvent::accepted
This property indicates whether the application will allow the user to
close the window. It is true by default.
@@ -2700,7 +2691,7 @@ QOpenGLContext *QQuickWindow::openglContext() const
*/
/*!
- \qmlsignal QtQuick.Window::closing(CloseEvent close)
+ \qmlsignal closing(CloseEvent close)
\since 5.1
This signal is emitted when the user tries to close the window.
@@ -2809,7 +2800,7 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
Grabs the contents of the window and returns it as an image.
It is possible to call the grabWindow() function when the window is not
- visible. This requires that the window is \l{QWindow::create} {created}
+ visible. This requires that the window is \l{QWindow::create()} {created}
and has a valid size and that no other QQuickWindow instances are rendering
in the same process.
@@ -2822,7 +2813,7 @@ QImage QQuickWindow::grabWindow()
Q_D(QQuickWindow);
if (!isVisible()) {
- if (d->context->isReady()) {
+ if (d->context->openglContext()) {
qWarning("QQuickWindow::grabWindow: scene graph already in use");
return QImage();
}
@@ -2834,6 +2825,7 @@ QImage QQuickWindow::grabWindow()
QOpenGLContext context;
context.setFormat(requestedFormat());
+ context.setShareContext(QSGContext::sharedOpenGLContext());
context.create();
context.makeCurrent(this);
d->context->initialize(&context);
@@ -3019,7 +3011,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const
{
Q_D(const QQuickWindow);
- if (d->context && d->context->isReady()) {
+ if (d->context && d->context->openglContext()) {
if (options & TextureCanUseAtlas)
return d->context->createTexture(image);
else
@@ -3047,7 +3039,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
{
Q_D(const QQuickWindow);
- if (d->context && d->context->isReady()) {
+ if (d->context && d->context->openglContext()) {
QSGPlainTexture *texture = new QSGPlainTexture();
texture->setTextureId(id);
texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
@@ -3060,7 +3052,7 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create
}
/*!
- \qmlproperty color QtQuick.Window::Window::color
+ \qmlproperty color Window::color
The background color for the window.
@@ -3189,7 +3181,7 @@ void QQuickWindow::resetOpenGLState()
}
/*!
- \qmlproperty string QtQuick.Window::Window::title
+ \qmlproperty string Window::title
The window's title in the windowing system.
@@ -3200,7 +3192,7 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty Qt::WindowModality QtQuick.Window::Window::modality
+ \qmlproperty Qt::WindowModality Window::modality
The modality of the window.
@@ -3210,7 +3202,7 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty Qt::WindowFlags QtQuick.Window::Window::flags
+ \qmlproperty Qt::WindowFlags Window::flags
The window flags of the window.
@@ -3223,10 +3215,10 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty int QtQuick.Window::Window::x
- \qmlproperty int QtQuick.Window::Window::y
- \qmlproperty int QtQuick.Window::Window::width
- \qmlproperty int QtQuick.Window::Window::height
+ \qmlproperty int Window::x
+ \qmlproperty int Window::y
+ \qmlproperty int Window::width
+ \qmlproperty int Window::height
Defines the window's position and size.
@@ -3241,8 +3233,8 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty int QtQuick.Window::Window::minimumWidth
- \qmlproperty int QtQuick.Window::Window::minimumHeight
+ \qmlproperty int Window::minimumWidth
+ \qmlproperty int Window::minimumHeight
\since 5.1
Defines the window's minimum size.
@@ -3252,8 +3244,8 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty int QtQuick.Window::Window::maximumWidth
- \qmlproperty int QtQuick.Window::Window::maximumHeight
+ \qmlproperty int Window::maximumWidth
+ \qmlproperty int Window::maximumHeight
\since 5.1
Defines the window's maximum size.
@@ -3263,7 +3255,7 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty bool QtQuick.Window::Window::visible
+ \qmlproperty bool Window::visible
Whether the window is visible on the screen.
@@ -3273,7 +3265,7 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty QWindow::Visibility QtQuick.Window::Window::visibility
+ \qmlproperty QWindow::Visibility Window::visibility
The screen-occupation state of the window.
@@ -3293,7 +3285,7 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty Qt::ScreenOrientation QtQuick.Window::Window::contentOrientation
+ \qmlproperty Qt::ScreenOrientation Window::contentOrientation
This is a hint to the window manager in case it needs to display
additional content like popups, dialogs, status bars, or similar
@@ -3314,7 +3306,7 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty real QtQuick.Window::Window::opacity
+ \qmlproperty real Window::opacity
The opacity of the window.
@@ -3331,7 +3323,7 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty Item QtQuick.Window::Window::activeFocusItem
+ \qmlproperty Item Window::activeFocusItem
\since 5.1
The item which currently has active focus or \c null if there is
@@ -3339,7 +3331,7 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty QtQuick.Window::Window::active
+ \qmlproperty Window::active
\since 5.1
The active status of the window.
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 420b13eeff..5063b3b5db 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -64,7 +64,7 @@ class Q_QUICK_EXPORT QQuickWindow : public QWindow
Q_OBJECT
Q_PRIVATE_PROPERTY(QQuickWindow::d_func(), QQmlListProperty<QObject> data READ data DESIGNABLE false)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
- Q_PROPERTY(QQuickItem* contentItem READ contentItem CONSTANT FINAL)
+ Q_PROPERTY(QQuickItem* contentItem READ contentItem CONSTANT)
Q_PROPERTY(QQuickItem* activeFocusItem READ activeFocusItem NOTIFY activeFocusItemChanged REVISION 1)
Q_CLASSINFO("DefaultProperty", "data")
Q_DECLARE_PRIVATE(QQuickWindow)
@@ -143,7 +143,6 @@ Q_SIGNALS:
public Q_SLOTS:
void update();
- void forcePolish();
void releaseResources();
protected:
@@ -173,11 +172,12 @@ protected:
private Q_SLOTS:
void maybeUpdate();
void cleanupSceneGraph();
+ void forcePolish();
void setTransientParent_helper(QQuickWindow *window);
private:
friend class QQuickItem;
- friend class QQuickWindowRenderLoop;
+ friend class QQuickAnimatorController;
Q_DISABLE_COPY(QQuickWindow)
};
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index c02f7107d4..c23745b5f1 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -166,6 +166,7 @@ public:
void setFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = 0);
void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = 0);
static void notifyFocusChangesRecur(QQuickItem **item, int remaining);
+ void clearFocusObject();
void updateFocusItemTransform();
@@ -194,7 +195,7 @@ public:
void fireFrameSwapped() { Q_EMIT q_func()->frameSwapped(); }
- QSGContext *context;
+ QSGRenderContext *context;
QSGRenderer *renderer;
QSGRenderLoop *windowManager;
diff --git a/src/quick/items/shaders/shadereffect.frag b/src/quick/items/shaders/shadereffect.frag
new file mode 100644
index 0000000000..c1c15ecb0c
--- /dev/null
+++ b/src/quick/items/shaders/shadereffect.frag
@@ -0,0 +1,9 @@
+varying highp vec2 qt_TexCoord0;
+
+uniform sampler2D source;
+uniform lowp float qt_Opacity;
+
+void main()
+{
+ gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity;
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/shadereffect.vert b/src/quick/items/shaders/shadereffect.vert
new file mode 100644
index 0000000000..ae1e84a50c
--- /dev/null
+++ b/src/quick/items/shaders/shadereffect.vert
@@ -0,0 +1,12 @@
+uniform highp mat4 qt_Matrix;
+
+attribute highp vec4 qt_Vertex;
+attribute highp vec2 qt_MultiTexCoord0;
+
+varying highp vec2 qt_TexCoord0;
+
+void main()
+{
+ qt_TexCoord0 = qt_MultiTexCoord0;
+ gl_Position = qt_Matrix * qt_Vertex;
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/shadereffect_core.frag b/src/quick/items/shaders/shadereffect_core.frag
new file mode 100644
index 0000000000..2163753edc
--- /dev/null
+++ b/src/quick/items/shaders/shadereffect_core.frag
@@ -0,0 +1,13 @@
+#version 150 core
+
+in vec2 qt_TexCoord0;
+
+out vec4 fragColor;
+
+uniform sampler2D source;
+uniform float qt_Opacity;
+
+void main()
+{
+ fragColor = texture(source, qt_TexCoord0) * qt_Opacity;
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/shadereffect_core.vert b/src/quick/items/shaders/shadereffect_core.vert
new file mode 100644
index 0000000000..2ed2d47b5f
--- /dev/null
+++ b/src/quick/items/shaders/shadereffect_core.vert
@@ -0,0 +1,14 @@
+#version 150 core
+
+in vec4 qt_Vertex;
+in vec2 qt_MultiTexCoord0;
+
+out vec2 qt_TexCoord0;
+
+uniform mat4 qt_Matrix;
+
+void main()
+{
+ qt_TexCoord0 = qt_MultiTexCoord0;
+ gl_Position = qt_Matrix * qt_Vertex;
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/shadereffectfallback.frag b/src/quick/items/shaders/shadereffectfallback.frag
new file mode 100644
index 0000000000..d279e54083
--- /dev/null
+++ b/src/quick/items/shaders/shadereffectfallback.frag
@@ -0,0 +1,4 @@
+void main()
+{
+ gl_FragColor = vec4(1., 0., 1., 1.);
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/shadereffectfallback.vert b/src/quick/items/shaders/shadereffectfallback.vert
new file mode 100644
index 0000000000..0a11a1d340
--- /dev/null
+++ b/src/quick/items/shaders/shadereffectfallback.vert
@@ -0,0 +1,8 @@
+uniform highp mat4 qt_Matrix;
+
+attribute highp vec4 v;
+
+void main()
+{
+ gl_Position = qt_Matrix * v;
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/shadereffectfallback_core.frag b/src/quick/items/shaders/shadereffectfallback_core.frag
new file mode 100644
index 0000000000..4abf124737
--- /dev/null
+++ b/src/quick/items/shaders/shadereffectfallback_core.frag
@@ -0,0 +1,8 @@
+#version 150 core
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(1., 0., 1., 1.);
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/shadereffectfallback_core.vert b/src/quick/items/shaders/shadereffectfallback_core.vert
new file mode 100644
index 0000000000..b1ca84cc6d
--- /dev/null
+++ b/src/quick/items/shaders/shadereffectfallback_core.vert
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 v;
+
+uniform mat4 qt_Matrix;
+
+void main()
+{
+ gl_Position = qt_Matrix * v;
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/sprite.frag b/src/quick/items/shaders/sprite.frag
new file mode 100644
index 0000000000..e1fcb0f006
--- /dev/null
+++ b/src/quick/items/shaders/sprite.frag
@@ -0,0 +1,12 @@
+uniform sampler2D _qt_texture;
+uniform lowp float qt_Opacity;
+
+varying highp vec4 fTexS;
+varying lowp float progress;
+
+void main()
+{
+ gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy),
+ texture2D(_qt_texture, fTexS.zw),
+ progress) * qt_Opacity;
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/sprite.vert b/src/quick/items/shaders/sprite.vert
new file mode 100644
index 0000000000..fc826f60b4
--- /dev/null
+++ b/src/quick/items/shaders/sprite.vert
@@ -0,0 +1,23 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+
+uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress
+uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation)
+
+uniform highp mat4 qt_Matrix;
+
+varying highp vec4 fTexS;
+varying lowp float progress;
+
+void main()
+{
+ progress = animData.z;
+
+ // Calculate frame location in texture
+ fTexS.xy = animPos.xy + vTex.xy * animData.xy;
+
+ // Next frame is also passed, for interpolation
+ fTexS.zw = animPos.zw + vTex.xy * animData.xy;
+
+ gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1);
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/sprite_core.frag b/src/quick/items/shaders/sprite_core.frag
new file mode 100644
index 0000000000..c1087a8754
--- /dev/null
+++ b/src/quick/items/shaders/sprite_core.frag
@@ -0,0 +1,16 @@
+#version 150 core
+
+in vec4 fTexS;
+in float progress;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform float qt_Opacity;
+
+void main()
+{
+ fragColor = mix(texture(_qt_texture, fTexS.xy),
+ texture(_qt_texture, fTexS.zw),
+ progress) * qt_Opacity;
+} \ No newline at end of file
diff --git a/src/quick/items/shaders/sprite_core.vert b/src/quick/items/shaders/sprite_core.vert
new file mode 100644
index 0000000000..5027bf03fc
--- /dev/null
+++ b/src/quick/items/shaders/sprite_core.vert
@@ -0,0 +1,24 @@
+#version 150 core
+
+in vec2 vPos;
+in vec2 vTex;
+
+out vec4 fTexS;
+out float progress;
+
+uniform vec3 animData; // w,h(premultiplied of anim), interpolation progress
+uniform vec4 animPos; // x,y, x,y (two frames for interpolation)
+uniform mat4 qt_Matrix;
+
+void main()
+{
+ progress = animData.z;
+
+ // Calculate frame location in texture
+ fTexS.xy = animPos.xy + vTex.xy * animData.xy;
+
+ // Next frame is also passed, for interpolation
+ fTexS.zw = animPos.zw + vTex.xy * animData.xy;
+
+ gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1);
+} \ No newline at end of file
diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp
index 5216fca355..ee5034c108 100644
--- a/src/quick/qtquick2.cpp
+++ b/src/quick/qtquick2.cpp
@@ -55,6 +55,11 @@
#include <qqmlproperty.h>
#include <QtCore/QPointer>
+static void initResources()
+{
+ Q_INIT_RESOURCE(scenegraph);
+}
+
QT_BEGIN_NAMESPACE
class QQmlQtQuick2DebugStatesDelegate : public QQmlDebugStatesDelegate
@@ -172,6 +177,8 @@ void QQmlQtQuick2DebugStatesDelegate::resetBindingForInvalidProperty(QObject *ob
void QQmlQtQuick2Module::defineModule()
{
+ initResources();
+
QQuick_initializeProviders();
QQuickUtilModule::defineModule();
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index f25e144674..79b5de72c0 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -40,11 +40,13 @@
****************************************************************************/
#include "qsgbatchrenderer_p.h"
+#include <private/qsgshadersourcebuilder_p.h>
#include <QtCore/QElapsedTimer>
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLFramebufferObject>
+#include <QtGui/QOpenGLVertexArrayObject>
#include <private/qqmlprofilerservice_p.h>
@@ -56,7 +58,7 @@
QT_BEGIN_NAMESPACE
-extern QByteArray qsgShaderRewriter_insertZAttributes(const char *input);
+extern QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat::OpenGLContextProfile profile);
namespace QSGBatchRenderer
{
@@ -112,6 +114,7 @@ struct QMatrix4x4_Accessor
int flagBits;
static bool isTranslate(const QMatrix4x4 &m) { return ((const QMatrix4x4_Accessor &) m).flagBits <= 0x1; }
+ static bool isScale(const QMatrix4x4 &m) { return ((const QMatrix4x4_Accessor &) m).flagBits <= 0x2; }
static bool is2DSafe(const QMatrix4x4 &m) { return ((const QMatrix4x4_Accessor &) m).flagBits < 0x8; }
};
@@ -130,10 +133,12 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material)
#endif
QSGMaterialShader *s = material->createShader();
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile();
QOpenGLShaderProgram *p = s->program();
p->addShaderFromSourceCode(QOpenGLShader::Vertex,
- qsgShaderRewriter_insertZAttributes(s->vertexShader()));
+ qsgShaderRewriter_insertZAttributes(s->vertexShader(), profile));
p->addShaderFromSourceCode(QOpenGLShader::Fragment,
s->fragmentShader());
@@ -283,7 +288,6 @@ Updater::Updater(Renderer *r)
void Updater::updateStates(QSGNode *n)
{
- m_toplevel_alpha = 1;
m_current_clip = 0;
m_added = 0;
@@ -389,6 +393,9 @@ void Updater::visitOpacityNode(Node *n)
if (was != is) {
renderer->m_rebuild = Renderer::FullRebuild;
n->isOpaque = is;
+ } else if (!is) {
+ renderer->invalidateAlphaBatchesForRoot(m_roots.last());
+ renderer->m_rebuild |= Renderer::BuildBatches;
}
++m_force_update;
SHADOWNODE_TRAVERSE(n) visitNode(*child);
@@ -530,6 +537,38 @@ int qsg_positionAttribute(QSGGeometry *g) {
return -1;
}
+
+void Rect::map(const QMatrix4x4 &matrix)
+{
+ const float *m = matrix.constData();
+ if (QMatrix4x4_Accessor::isScale(matrix)) {
+ tl.x = tl.x * m[0] + m[12];
+ tl.y = tl.y * m[5] + m[13];
+ br.x = br.x * m[0] + m[12];
+ br.y = br.y * m[5] + m[13];
+ if (tl.x > br.x)
+ qSwap(tl.x, br.x);
+ if (tl.y > br.y)
+ qSwap(tl.y, br.y);
+ } else {
+ Pt mtl = tl;
+ Pt mtr = { br.x, tl.y };
+ Pt mbl = { tl.x, br.y };
+ Pt mbr = br;
+
+ mtl.map(matrix);
+ mtr.map(matrix);
+ mbl.map(matrix);
+ mbr.map(matrix);
+
+ set(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
+ (*this) |= mtl;
+ (*this) |= mtr;
+ (*this) |= mbl;
+ (*this) |= mbr;
+ }
+}
+
void Element::computeBounds()
{
Q_ASSERT(!boundsComputed);
@@ -550,6 +589,17 @@ void Element::computeBounds()
vd += g->sizeOfVertex();
}
bounds.map(*node->matrix());
+
+ if (!qIsFinite(bounds.tl.x))
+ bounds.tl.x = -FLT_MAX;
+ if (!qIsFinite(bounds.tl.y))
+ bounds.tl.y = -FLT_MAX;
+ if (!qIsFinite(bounds.br.x))
+ bounds.br.x = FLT_MAX;
+ if (!qIsFinite(bounds.br.y))
+ bounds.br.y = FLT_MAX;
+
+ boundsOutsideFloatRange = bounds.isOutsideFloatRange();
}
RenderNodeElement::~RenderNodeElement()
@@ -650,12 +700,26 @@ bool Batch::isTranslateOnlyToRoot() const {
/*
* Iterates through all the nodes in the batch and returns true if the
- * nodes are all "2D safe" meaning that they can be merged and that
- * the value in the z coordinate is of no consequence.
+ * nodes are all safe to batch. There are two separate criteria:
+ *
+ * - The matrix is such that the z component of the result is of no
+ * consequence.
+ *
+ * - The bounds are inside the stable floating point range. This applies
+ * to desktop only where we in this case can trigger a fallback to
+ * unmerged in which case we pass the geometry straight through and
+ * just apply the matrix.
+ *
+ * NOTE: This also means a slight performance impact for geometries which
+ * are defined to be outside the stable floating point range and still
+ * use single precision float, but given that this implicitly fixes
+ * huge lists and tables, it is worth it.
*/
-bool Batch::allMatricesAre2DSafe() const {
+bool Batch::isSafeToBatch() const {
Element *e = first;
while (e) {
+ if (e->boundsOutsideFloatRange)
+ return false;
if (!QMatrix4x4_Accessor::is2DSafe(*e->node->matrix()))
return false;
e = e->nextInBatch;
@@ -683,7 +747,7 @@ static int qsg_countNodesInBatches(const QDataBuffer<Batch *> &batches)
return sum;
}
-Renderer::Renderer(QSGContext *ctx)
+Renderer::Renderer(QSGRenderContext *ctx)
: QSGRenderer(ctx)
, m_opaqueRenderList(64)
, m_alphaRenderList(64)
@@ -700,6 +764,7 @@ Renderer::Renderer(QSGContext *ctx)
, m_zRange(0)
, m_currentMaterial(0)
, m_currentShader(0)
+ , m_vao(0)
{
setNodeUpdater(new Updater(this));
@@ -740,6 +805,13 @@ Renderer::Renderer(QSGContext *ctx)
qDebug() << "Batch thresholds: nodes:" << m_batchNodeThreshold << " vertices:" << m_batchVertexThreshold;
qDebug() << "Using buffer strategy:" << (m_bufferStrategy == GL_STATIC_DRAW ? "static" : (m_bufferStrategy == GL_DYNAMIC_DRAW ? "dynamic" : "stream"));
}
+
+ // If rendering with an OpenGL Core profile context, we need to create a VAO
+ // to hold our vertex specification state.
+ if (context()->openglContext()->format().profile() == QSurfaceFormat::CoreProfile) {
+ m_vao = new QOpenGLVertexArrayObject(this);
+ m_vao->create();
+ }
}
static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs)
@@ -1344,6 +1416,15 @@ void Renderer::buildRenderListsFromScratch()
buildRenderLists(rootNode());
}
+void Renderer::invalidateAlphaBatchesForRoot(Node *root)
+{
+ for (int i=0; i<m_alphaBatches.size(); ++i) {
+ Batch *b = m_alphaBatches.at(i);
+ if (b->root == root || root == 0)
+ b->invalidate();
+ }
+}
+
/* Clean up batches by making it a consecutive list of "valid"
* batches and moving all invalidated batches to the batches pool.
*/
@@ -1491,6 +1572,13 @@ void Renderer::prepareAlphaBatches()
ej->batch = batch;
next->nextInBatch = ej;
next = ej;
+ } else {
+ /* When we come across a compatible element which hits an overlap, we
+ * need to stop the batch right away. We cannot add more elements
+ * to the current batch as they will be rendered before the batch that the
+ * current 'ej' will be added to.
+ */
+ break;
}
} else {
overlapBounds |= ej->bounds;
@@ -1616,7 +1704,7 @@ void Renderer::uploadBatch(Batch *b)
&& (((gn->activeMaterial()->flags() & QSGMaterial::RequiresDeterminant) == 0)
|| (((gn->activeMaterial()->flags() & QSGMaterial_RequiresFullMatrixBit) == 0) && b->isTranslateOnlyToRoot())
)
- && b->allMatricesAre2DSafe();
+ && b->isSafeToBatch();
b->merged = canMerge;
@@ -1890,7 +1978,14 @@ void Renderer::renderMergedBatch(const Batch *batch)
updateClip(gn->clipList(), batch);
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id);
+
+ char *indexBase = 0;
+ if (m_context->hasBrokenIndexBufferObjects()) {
+ indexBase = batch->vbo.data;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ } else {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id);
+ }
QSGMaterial *material = gn->activeMaterial();
@@ -1925,7 +2020,7 @@ void Renderer::renderMergedBatch(const Batch *batch)
}
glVertexAttribPointer(sms->pos_order, 1, GL_FLOAT, false, 0, (void *) (qintptr) (draw.zorders));
- glDrawElements(g->drawingMode(), draw.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (draw.indices));
+ glDrawElements(g->drawingMode(), draw.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (indexBase + draw.indices));
}
}
@@ -1958,8 +2053,15 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
updateClip(gn->clipList(), batch);
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
- if (batch->indexCount)
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id);
+ char *indexBase = 0;
+ if (batch->indexCount) {
+ if (m_context->hasBrokenIndexBufferObjects()) {
+ indexBase = batch->vbo.data;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ } else {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id);
+ }
+ }
// We always have dirty matrix as all batches are at a unique z range.
QSGMaterialShader::RenderState::DirtyStates dirty = QSGMaterialShader::RenderState::DirtyMatrix;
@@ -1978,7 +2080,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
}
int vOffset = 0;
- int iOffset = batch->vertexCount * gn->geometry()->sizeOfVertex();
+ char *iOffset = indexBase + batch->vertexCount * gn->geometry()->sizeOfVertex();
QMatrix4x4 rootMatrix = batch->root ? matrixForRoot(batch->root) : QMatrix4x4();
@@ -1994,7 +2096,9 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
program->updateState(state(dirty), material, m_currentMaterial);
- m_currentMaterial = gn->activeMaterial();
+ // We don't need to bother with asking each node for its material as they
+ // are all identical (compare==0) since they are in the same batch.
+ m_currentMaterial = material;
QSGGeometry* g = gn->geometry();
char const *const *attrNames = program->attributeNames();
@@ -2009,7 +2113,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
}
if (g->indexCount())
- glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), (void *) (qintptr) iOffset);
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), iOffset);
else
glDrawArrays(g->drawingMode(), 0, g->vertexCount());
@@ -2031,14 +2135,13 @@ void Renderer::renderBatches()
<< " -> Alpha: " << qsg_countNodesInBatches(m_alphaBatches) << " nodes in " << m_alphaBatches.size() << " batches...";
}
- QRect r = viewportRect();
- glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
-
for (QHash<QSGRenderNode *, RenderNodeElement *>::const_iterator it = m_renderNodeElements.constBegin();
it != m_renderNodeElements.constEnd(); ++it) {
prepareRenderNode(it.value());
}
+ QRect r = viewportRect();
+ glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
glClearColor(clearColor().redF(), clearColor().greenF(), clearColor().blueF(), clearColor().alphaF());
#if defined(QT_OPENGL_ES)
glClearDepthf(1);
@@ -2126,6 +2229,17 @@ void Renderer::deleteRemovedElements()
m_elementsToDelete.reset();
}
+void Renderer::preprocess()
+{
+ // Bind our VAO. It's important that we do this here as the
+ // QSGRenderer::preprocess() call may well do work that requires
+ // a bound VAO.
+ if (m_vao)
+ m_vao->bind();
+
+ QSGRenderer::preprocess();
+}
+
void Renderer::render()
{
if (Q_UNLIKELY(debug_dump)) {
@@ -2233,6 +2347,9 @@ void Renderer::render()
renderBatches();
m_rebuild = 0;
+
+ if (m_vao)
+ m_vao->release();
}
void Renderer::prepareRenderNode(RenderNodeElement *e)
@@ -2310,23 +2427,11 @@ void Renderer::renderRenderNode(Batch *batch)
if (!m_shaderManager->blitProgram) {
m_shaderManager->blitProgram = new QOpenGLShaderProgram();
- const char *vs =
- "attribute highp vec4 av; "
- "attribute highp vec2 at; "
- "varying highp vec2 t; "
- "void main() { "
- " gl_Position = av; "
- " t = at; "
- "} ";
- const char *fs =
- "uniform lowp sampler2D tex; "
- "varying highp vec2 t; "
- "void main() { "
- " gl_FragColor = texture2D(tex, t); "
- "} ";
-
- m_shaderManager->blitProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vs);
- m_shaderManager->blitProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fs);
+
+ QSGShaderSourceBuilder::initializeProgramFromFiles(
+ m_shaderManager->blitProgram,
+ QStringLiteral(":/scenegraph/shaders/rendernode.vert"),
+ QStringLiteral(":/scenegraph/shaders/rendernode.frag"));
m_shaderManager->blitProgram->bindAttributeLocation("av", 0);
m_shaderManager->blitProgram->bindAttributeLocation("at", 1);
m_shaderManager->blitProgram->link();
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 94e8ba5d96..95e111552d 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -50,9 +50,13 @@
QT_BEGIN_NAMESPACE
+class QOpenGLVertexArrayObject;
+
namespace QSGBatchRenderer
{
+#define QSG_RENDERER_COORD_LIMIT 1000000.0f
+
struct Vec;
struct Rect;
struct Buffer;
@@ -117,14 +121,7 @@ struct Rect {
Q_ASSERT(tl.y <= br.y);
}
- void map(const QMatrix4x4 &m) {
- tl.map(m);
- br.map(m);
- if (br.x < tl.x)
- qSwap(br.x, tl.x);
- if (br.y < tl.y)
- qSwap(br.y, tl.y);
- }
+ void map(const QMatrix4x4 &m);
void set(float left, float top, float right, float bottom) {
tl.set(left, top);
@@ -136,6 +133,13 @@ struct Rect {
bool yOverlap = r.tl.y < br.y && r.br.y > tl.y;
return xOverlap && yOverlap;
}
+
+ bool isOutsideFloatRange() const {
+ return tl.x < -QSG_RENDERER_COORD_LIMIT
+ || tl.y < -QSG_RENDERER_COORD_LIMIT
+ || br.x > QSG_RENDERER_COORD_LIMIT
+ || br.y > QSG_RENDERER_COORD_LIMIT;
+ }
};
inline QDebug operator << (QDebug d, const Rect &r) {
@@ -158,6 +162,7 @@ struct Element {
, root(0)
, order(0)
, boundsComputed(false)
+ , boundsOutsideFloatRange(false)
, translateOnlyToRoot(false)
, removed(false)
, orphaned(false)
@@ -181,6 +186,7 @@ struct Element {
int order;
uint boundsComputed : 1;
+ uint boundsOutsideFloatRange : 1;
uint translateOnlyToRoot : 1;
uint removed : 1;
uint orphaned : 1;
@@ -242,7 +248,7 @@ struct Batch
void cleanupRemovedElements();
bool isTranslateOnlyToRoot() const;
- bool allMatricesAre2DSafe() const;
+ bool isSafeToBatch() const;
// pseudo-constructor...
void init() {
@@ -389,11 +395,12 @@ public:
class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer
{
public:
- Renderer(QSGContext *);
+ Renderer(QSGRenderContext *);
~Renderer();
protected:
void nodeChanged(QSGNode *node, QSGNode::DirtyState state);
+ void preprocess() Q_DECL_OVERRIDE;
void render();
private:
@@ -420,6 +427,7 @@ private:
void prepareOpaqueBatches();
bool checkOverlap(int first, int last, const Rect &bounds);
void prepareAlphaBatches();
+ void invalidateAlphaBatchesForRoot(Node *root);
void uploadBatch(Batch *b);
void uploadMergedElement(Element *e, int vaOffset, char **vertexData, char **zData, char **indexData, quint16 *iBase, int *indexCount);
@@ -476,6 +484,9 @@ private:
QSGMaterialShader *m_currentProgram;
ShaderManager::Shader *m_currentShader;
const QSGClipNode *m_currentClip;
+
+ // For minimal OpenGL core profile support
+ QOpenGLVertexArrayObject *m_vao;
};
Batch *Renderer::newBatch()
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 25d256158e..686d1438b4 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -41,9 +41,21 @@
#include "qsgmaterial.h"
#include "qsgrenderer_p.h"
+#include "qsgmaterialshader_p.h"
+#include <private/qsgshadersourcebuilder_p.h>
QT_BEGIN_NAMESPACE
+const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType type) const
+{
+ QStringList files = m_sourceFiles[type];
+ QSGShaderSourceBuilder builder;
+ Q_FOREACH (const QString &file, files)
+ builder.appendSourceFile(file);
+ m_sources[type] = builder.source();
+ return m_sources[type].constData();
+}
+
#ifndef QT_NO_DEBUG
static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty();
#endif
@@ -165,14 +177,21 @@ static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty();
Creates a new QSGMaterialShader.
*/
QSGMaterialShader::QSGMaterialShader()
+ : d_ptr(new QSGMaterialShaderPrivate)
+{
+}
+
+QSGMaterialShader::QSGMaterialShader(QSGMaterialShaderPrivate &dd)
+ : d_ptr(&dd)
{
- Q_UNUSED(m_reserved);
}
/*!
- \fn QSGMaterialShader::~QSGMaterialShader()
\internal
*/
+QSGMaterialShader::~QSGMaterialShader()
+{
+}
/*!
\fn char const *const *QSGMaterialShader::attributeNames() const
@@ -194,6 +213,11 @@ QSGMaterialShader::QSGMaterialShader()
The contents returned from this function should never change.
*/
+const char *QSGMaterialShader::vertexShader() const
+{
+ Q_D(const QSGMaterialShader);
+ return d->loadShaderSource(QOpenGLShader::Vertex);
+}
/*!
@@ -204,6 +228,11 @@ QSGMaterialShader::QSGMaterialShader()
The contents returned from this function should never change.
*/
+const char *QSGMaterialShader::fragmentShader() const
+{
+ Q_D(const QSGMaterialShader);
+ return d->loadShaderSource(QOpenGLShader::Fragment);
+}
/*!
@@ -274,7 +303,35 @@ void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial
{
}
+/*!
+ Sets the GLSL source file for the shader stage \a type to \a sourceFile. The
+ default implementation of the vertexShader() and fragmentShader() functions
+ will load the source files set by this function.
+
+ This function is useful when you have a single source file for a given shader
+ stage. If your shader consists of multiple source files then use
+ setShaderSourceFiles()
+
+ \sa setShaderSourceFiles(), vertexShader(), fragmentShader()
+ */
+void QSGMaterialShader::setShaderSourceFile(QOpenGLShader::ShaderType type, const QString &sourceFile)
+{
+ Q_D(QSGMaterialShader);
+ d->m_sourceFiles[type] = (QStringList() << sourceFile);
+}
+
+/*!
+ Sets the GLSL source files for the shader stage \a type to \a sourceFiles. The
+ default implementation of the vertexShader() and fragmentShader() functions
+ will load the source files set by this function in the order given.
+ \sa setShaderSourceFile(), vertexShader(), fragmentShader()
+ */
+void QSGMaterialShader::setShaderSourceFiles(QOpenGLShader::ShaderType type, const QStringList &sourceFiles)
+{
+ Q_D(QSGMaterialShader);
+ d->m_sourceFiles[type] = sourceFiles;
+}
/*!
This function is called when the shader is initialized to compile the
@@ -478,7 +535,7 @@ QRect QSGMaterialShader::RenderState::deviceRect() const
QOpenGLContext *QSGMaterialShader::RenderState::context() const
{
- return static_cast<const QSGRenderer *>(m_data)->glContext();
+ return static_cast<const QSGRenderer *>(m_data)->context()->openglContext();
}
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.h b/src/quick/scenegraph/coreapi/qsgmaterial.h
index f3ef62d3e5..bfe570ca02 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.h
@@ -48,6 +48,7 @@
QT_BEGIN_NAMESPACE
class QSGMaterial;
+class QSGMaterialShaderPrivate;
namespace QSGBatchRenderer {
class ShaderManager;
@@ -88,7 +89,7 @@ public:
};
QSGMaterialShader();
- virtual ~QSGMaterialShader() {};
+ virtual ~QSGMaterialShader();
virtual void activate();
virtual void deactivate();
@@ -99,18 +100,24 @@ public:
inline QOpenGLShaderProgram *program() { return &m_program; }
protected:
+ Q_DECLARE_PRIVATE(QSGMaterialShader)
+ QSGMaterialShader(QSGMaterialShaderPrivate &dd);
+
friend class QSGContext;
friend class QSGBatchRenderer::ShaderManager;
+ void setShaderSourceFile(QOpenGLShader::ShaderType type, const QString &sourceFile);
+ void setShaderSourceFiles(QOpenGLShader::ShaderType type, const QStringList &sourceFiles);
+
virtual void compile();
virtual void initialize() { }
- virtual const char *vertexShader() const = 0;
- virtual const char *fragmentShader() const = 0;
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
private:
QOpenGLShaderProgram m_program;
- void *m_reserved;
+ QScopedPointer<QSGMaterialShaderPrivate> d_ptr;
};
struct QSGMaterialType { };
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
new file mode 100644
index 0000000000..fc8a35c41d
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and 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 QSGMATERIALSHADER_P_H
+#define QSGMATERIALSHADER_P_H
+
+#include <private/qtquickglobal_p.h>
+#include <QOpenGLShader>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QSGMaterialShaderPrivate
+{
+public:
+ const char *loadShaderSource(QOpenGLShader::ShaderType type) const;
+
+ QHash<QOpenGLShader::ShaderType, QStringList> m_sourceFiles;
+ mutable QHash<QOpenGLShader::ShaderType, QByteArray> m_sources;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGMATERIALSHADER_P_H
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
index d5e83bb452..51cc844612 100644
--- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -102,16 +102,11 @@ void QSGNodeUpdater::updateStates(QSGNode *n)
bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const
{
- qreal opacity = 1;
while (node != root && node != 0) {
- if (node->type() == QSGNode::OpacityNodeType) {
- opacity *= static_cast<QSGOpacityNode *>(node)->opacity();
- if (opacity < 0.001)
- return true;
- }
+ if (node->isSubtreeBlocked())
+ return true;
node = node->parent();
}
-
return false;
}
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h b/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h
index d0adbc5dd2..4c3be61a76 100644
--- a/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h
@@ -64,9 +64,6 @@ public:
virtual void updateStates(QSGNode *n);
virtual bool isNodeBlocked(QSGNode *n, QSGNode *root) const;
- void setToplevelOpacity(qreal alpha) { m_opacity_stack.last() = alpha; }
- qreal toplevelOpacity() const { return m_opacity_stack.last(); }
-
protected:
virtual void enterTransformNode(QSGTransformNode *);
virtual void leaveTransformNode(QSGTransformNode *);
@@ -88,8 +85,6 @@ protected:
const QSGClipNode *m_current_clip;
int m_force_update;
-
- qreal m_toplevel_alpha;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 216c32f027..3c9c353bd8 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -46,6 +46,7 @@
#include "qsggeometry_p.h"
#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgshadersourcebuilder_p.h>
#include <QOpenGLShaderProgram>
#include <qopenglframebufferobject.h>
@@ -133,7 +134,7 @@ void QSGBindableFboId::bind() const
*/
-QSGRenderer::QSGRenderer(QSGContext *context)
+QSGRenderer::QSGRenderer(QSGRenderContext *context)
: QObject()
, m_clear_color(Qt::transparent)
, m_clear_mode(ClearColorBuffer | ClearDepthBuffer)
@@ -162,20 +163,6 @@ QSGRenderer::~QSGRenderer()
}
/*!
- Returns the scene graph context for this renderer.
-
- \internal
- */
-
-QSGContext *QSGRenderer::context()
-{
- return m_context;
-}
-
-
-
-
-/*!
Returns the node updater that this renderer uses to update states in the
scene graph.
@@ -398,7 +385,6 @@ void QSGRenderer::preprocess()
preprocessTime = frameTimer.nsecsElapsed();
#endif
- nodeUpdater()->setToplevelOpacity(context()->renderAlpha());
nodeUpdater()->updateStates(m_root_node);
#ifndef QSG_NO_RENDER_TIMING
@@ -496,16 +482,10 @@ QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip)
} else {
if (!(clipType & StencilClip)) {
if (!m_clip_program.isLinked()) {
- m_clip_program.addShaderFromSourceCode(QOpenGLShader::Vertex,
- "attribute highp vec4 vCoord; \n"
- "uniform highp mat4 matrix; \n"
- "void main() { \n"
- " gl_Position = matrix * vCoord; \n"
- "}");
- m_clip_program.addShaderFromSourceCode(QOpenGLShader::Fragment,
- "void main() { \n"
- " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw!
- "}");
+ QSGShaderSourceBuilder::initializeProgramFromFiles(
+ &m_clip_program,
+ QStringLiteral(":/scenegraph/shaders/stencilclip.vert"),
+ QStringLiteral(":/scenegraph/shaders/stencilclip.frag"));
m_clip_program.bindAttributeLocation("vCoord", 0);
m_clip_program.link();
m_clip_matrix_id = m_clip_program.uniformLocation("matrix");
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index a1ebfa0946..43811e6d5e 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -84,7 +84,7 @@ public:
};
Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
- QSGRenderer(QSGContext *context);
+ QSGRenderer(QSGRenderContext *context);
virtual ~QSGRenderer();
void setRootNode(QSGRootNode *node);
@@ -117,9 +117,7 @@ public:
void setClearColor(const QColor &color);
QColor clearColor() const { return m_clear_color; }
- QOpenGLContext *glContext() const { Q_ASSERT(m_context); return m_context->glContext(); }
-
- QSGContext *context();
+ QSGRenderContext *context() const { return m_context; }
void renderScene();
void renderScene(const QSGBindable &bindable);
@@ -161,7 +159,7 @@ protected:
QRect m_current_scissor_rect;
int m_current_stencil_value;
- QSGContext *m_context;
+ QSGRenderContext *m_context;
private:
QSGRootNode *m_root_node;
diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
index eade198cd0..2849eff304 100644
--- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
+++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include <QtCore>
+#include <QtGui/QSurfaceFormat>
// Duct Tape tokenizer for the purpose of parsing and rewriting
// shader source code
@@ -173,7 +174,7 @@ Tokenizer::Token Tokenizer::next()
using namespace QSGShaderRewriter;
-QByteArray qsgShaderRewriter_insertZAttributes(const char *input)
+QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat::OpenGLContextProfile profile)
{
Tokenizer tok;
tok.initialize(input);
@@ -182,15 +183,33 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input)
Tokenizer::Token t = tok.next();
// First find "void main() { ... "
+ const char* voidPos = input;
while (t != Tokenizer::Token_EOF) {
if (lt == Tokenizer::Token_Void && t == Tokenizer::Token_Identifier) {
if (qstrncmp("main", tok.identifier, 4) == 0)
break;
}
+ voidPos = tok.pos - 4;
lt = t;
t = tok.next();
}
+ QByteArray result;
+ result.reserve(1024);
+ result += QByteArray::fromRawData(input, voidPos - input);
+ switch (profile) {
+ case QSurfaceFormat::NoProfile:
+ case QSurfaceFormat::CompatibilityProfile:
+ result += QByteArrayLiteral("attribute highp float _qt_order;\n");
+ result += QByteArrayLiteral("uniform highp float _qt_zRange;\n");
+ break;
+
+ case QSurfaceFormat::CoreProfile:
+ result += QByteArrayLiteral("in float _qt_order;\n");
+ result += QByteArrayLiteral("uniform float _qt_zRange;\n");
+ break;
+ }
+
// Find first brace '{'
while (t != Tokenizer::Token_EOF && t != Tokenizer::Token_OpenBrace) t = tok.next();
int braceDepth = 1;
@@ -202,12 +221,8 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input)
case Tokenizer::Token_CloseBrace:
braceDepth--;
if (braceDepth == 0) {
- QByteArray result;
- result.reserve(1024);
- result += "attribute highp float _qt_order;\n";
- result += "uniform highp float _qt_zRange;\n";
- result += QByteArray::fromRawData(input, tok.pos - 1 - input);
- result += " gl_Position.z = gl_Position.z * _qt_zRange + _qt_order;\n";
+ result += QByteArray::fromRawData(voidPos, tok.pos - 1 - voidPos);
+ result += QByteArrayLiteral(" gl_Position.z = (gl_Position.z * _qt_zRange + _qt_order) * gl_Position.w;\n");
result += QByteArray(tok.pos - 1);
return result;
}
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index cdf63be5f2..58c843a286 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -61,8 +61,7 @@ static QElapsedTimer qsg_render_timer;
QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture;
QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
- : ctx(c)
- , m_manager(man)
+ : m_manager(man)
, m_pendingGlyphs(64)
{
Q_ASSERT(font.isValid());
@@ -75,6 +74,8 @@ QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCach
m_referenceFont = font;
m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution));
Q_ASSERT(m_referenceFont.isValid());
+
+ m_coreProfile = (c->format().profile() == QSurfaceFormat::CoreProfile);
}
QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index ebeb449be5..f2d7dc07ca 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -66,6 +66,7 @@ class QImage;
class TextureReference;
class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldGlyphNode;
+class QOpenGLContext;
class Q_QUICK_PRIVATE_EXPORT QSGRectangleNode : public QSGGeometryNode
{
@@ -246,7 +247,7 @@ protected:
GlyphData &glyphData(glyph_t glyph);
- QOpenGLContext *ctx;
+ inline bool isCoreProfile() const { return m_coreProfile; }
private:
QSGDistanceFieldGlyphCacheManager *m_manager;
@@ -255,6 +256,7 @@ private:
int m_glyphCount;
bool m_doubleGlyphResolution;
+ bool m_coreProfile;
QList<Texture> m_textures;
QHash<glyph_t, GlyphData> m_glyphsData;
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index bb8e3c4b36..afde7939f2 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -72,11 +72,8 @@
#include <private/qqmlprofilerservice_p.h>
-DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE)
-DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE)
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
-
/*
Comments about this class from Gunnar:
@@ -94,51 +91,38 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
to defining plugin interfaces..
*/
-
QT_BEGIN_NAMESPACE
class QSGContextPrivate : public QObjectPrivate
{
public:
QSGContextPrivate()
- : gl(0)
- , depthStencilBufferManager(0)
- , distanceFieldCacheManager(0)
- #if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2_ANGLE)
- , distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing)
- #else
- , distanceFieldAntialiasing(QSGGlyphNode::GrayAntialiasing)
- #endif
- , atlasManager(0)
- , flashMode(qmlFlashMode())
+ : antialiasingMethod(QSGContext::UndecidedAntialiasing)
, distanceFieldDisabled(qmlDisableDistanceField())
- , msaa(false)
+ , distanceFieldAntialiasing(
+#if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2_ANGLE)
+ QSGGlyphNode::HighQualitySubPixelAntialiasing
+#else
+ QSGGlyphNode::GrayAntialiasing
+#endif
+ )
{
- renderAlpha = qmlTranslucentMode() ? 0.5 : 1;
}
~QSGContextPrivate()
{
}
- QOpenGLContext *gl;
-
- QMutex textureMutex;
- QHash<QQuickTextureFactory *, QSGTexture *> textures;
- QSGDepthStencilBufferManager *depthStencilBufferManager;
- QSGDistanceFieldGlyphCacheManager *distanceFieldCacheManager;
-
- QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing;
-
- QSGAtlasTexture::Manager *atlasManager;
-
- bool flashMode;
- float renderAlpha;
+ QMutex mutex;
+ QSGContext::AntialiasingMethod antialiasingMethod;
bool distanceFieldDisabled;
+ QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing;
- bool msaa;
+ static QOpenGLContext *sharedOpenGLContext;
};
+QOpenGLContext *QSGContextPrivate::sharedOpenGLContext = 0;
+
class QSGTextureCleanupEvent : public QEvent
{
public:
@@ -188,144 +172,190 @@ QSGContext::QSGContext(QObject *parent) :
QSGContext::~QSGContext()
{
- invalidate();
}
+/*!
+ * 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::invalidate()
+void QSGContext::renderContextInitialized(QSGRenderContext *renderContext)
{
Q_D(QSGContext);
- d->textureMutex.lock();
- qDeleteAll(d->textures.values());
- d->textures.clear();
- d->textureMutex.unlock();
- delete d->depthStencilBufferManager;
- d->depthStencilBufferManager = 0;
- delete d->distanceFieldCacheManager;
- d->distanceFieldCacheManager = 0;
- d->gl = 0;
-
- emit invalidated();
-
- /* The cleanup of the atlas textures is a bit intruiging.
- As part of the cleanup in the threaded render loop, we
- do:
- 1. call this function
- 2. call QCoreApp::sendPostedEvents() to immediately process
- any pending deferred deletes.
- 3. delete the GL context.
- As textures need the atlas manager while cleaning up, the
- manager needs to be cleaned up after the textures, so
- we post a deleteLater here at the very bottom so it gets
- deferred deleted last.
-
- Another alternative would be to use a QPointer in
- QSGAtlasTexture::Texture, but this seemed simpler.
- */
+ d->mutex.lock();
+ if (d->antialiasingMethod == UndecidedAntialiasing) {
+ QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD");
+ if (aaType == "msaa") {
+ d->antialiasingMethod = MsaaAntialiasing;
+ } else if (aaType == "vertex") {
+ d->antialiasingMethod = VertexAntialiasing;
+ } else {
+ if (renderContext->openglContext()->format().samples() > 0)
+ d->antialiasingMethod = MsaaAntialiasing;
+ else
+ d->antialiasingMethod = VertexAntialiasing;
+ }
+ }
- if (d->atlasManager) {
- d->atlasManager->deleteLater();
- d->atlasManager = 0;
+ static bool dumped = false;
+ if (!dumped && qEnvironmentVariableIsSet("QSG_INFO")) {
+ dumped = true;
+ qDebug() << "GL_VENDOR: " << (const char *) glGetString(GL_VENDOR);
+ qDebug() << "GL_RENDERER: " << (const char *) glGetString(GL_RENDERER);
+ qDebug() << "GL_VERSION: " << (const char *) glGetString(GL_VERSION);
+ qDebug() << "GL_EXTENSIONS:\n " << QByteArray((const char *) glGetString(GL_EXTENSIONS)).replace(" ", "\n ").constData();
}
+
+ d->mutex.unlock();
}
+void QSGContext::renderContextInvalidated(QSGRenderContext *)
+{
+}
-QSGTexture *QSGContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window)
+/*!
+ Factory function for scene graph backends of the Rectangle element.
+ */
+QSGRectangleNode *QSGContext::createRectangleNode()
{
Q_D(QSGContext);
- if (!factory)
- return 0;
-
- d->textureMutex.lock();
- QSGTexture *texture = d->textures.value(factory);
- if (!texture) {
- if (QQuickDefaultTextureFactory *dtf = qobject_cast<QQuickDefaultTextureFactory *>(factory))
- texture = createTexture(dtf->image());
- else
- texture = factory->createTexture(window);
- d->textures.insert(factory, texture);
- connect(factory, SIGNAL(destroyed(QObject *)), this, SLOT(textureFactoryDestroyed(QObject *)), Qt::DirectConnection);
- }
- d->textureMutex.unlock();
- return texture;
+ return d->antialiasingMethod == MsaaAntialiasing
+ ? new QSGMultisampleAntialiasing::RectangleNode
+ : new QSGDefaultRectangleNode;
}
+/*!
+ Factory function for scene graph backends of the Image element.
+ */
+QSGImageNode *QSGContext::createImageNode()
+{
+ Q_D(QSGContext);
+ return d->antialiasingMethod == MsaaAntialiasing
+ ? new QSGMultisampleAntialiasing::ImageNode
+ : new QSGDefaultImageNode;
+}
-void QSGContext::textureFactoryDestroyed(QObject *o)
+/*!
+ Factory function for scene graph backends of the Text elements which supports native
+ text rendering. Used in special cases where native look and feel is a main objective.
+*/
+QSGGlyphNode *QSGContext::createNativeGlyphNode(QSGRenderContext *rc)
{
+#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE)
Q_D(QSGContext);
- QQuickTextureFactory *f = static_cast<QQuickTextureFactory *>(o);
+ if (d->distanceFieldDisabled)
+ return new QSGDefaultGlyphNode;
+ else
+ return createGlyphNode(rc);
+#else
+ Q_UNUSED(rc);
+ return new QSGDefaultGlyphNode;
+#endif
+}
- d->textureMutex.lock();
- QSGTexture *t = d->textures.take(f);
- d->textureMutex.unlock();
+/*!
+ Factory function for scene graph backends of the Text elements;
+ */
+QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc)
+{
+ Q_D(QSGContext);
- if (t) {
- if (t->thread() == thread())
- t->deleteLater();
- else
- QCoreApplication::postEvent(this, new QSGTextureCleanupEvent(t));
+ if (d->distanceFieldDisabled) {
+ return createNativeGlyphNode(rc);
+ } else {
+ QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(rc);
+ node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing);
+ return node;
}
}
-
-QOpenGLContext *QSGContext::glContext() const
+QSurfaceFormat QSGContext::defaultSurfaceFormat() const
{
- Q_D(const QSGContext);
- return d->gl;
+ QSurfaceFormat format;
+ format.setDepthBufferSize(24);
+ format.setStencilBufferSize(8);
+ if (QQuickWindow::hasDefaultAlphaBuffer())
+ format.setAlphaBufferSize(8);
+ format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ return format;
}
/*!
- Initializes the scene graph context with the GL context \a context. This also
- emits the ready() signal so that the QML graph can start building scene graph nodes.
+ Returns the minimum supported framebuffer object size.
*/
-void QSGContext::initialize(QOpenGLContext *context)
+
+QSize QSGContext::minimumFBOSize() const
{
- Q_D(QSGContext);
+#ifdef Q_OS_MAC
+ return QSize(33, 33);
+#else
+ return QSize(1, 1);
+#endif
+}
- QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD");
- if (aaType == "msaa") {
- d->msaa = true;
- } else if (aaType == "vertex") {
- d->msaa = false;
- } else {
- if (context->format().samples() > 0)
- d->msaa = true;
- else
- d->msaa = false;
- }
- // Sanity check the surface format, in case it was overridden by the application
- QSurfaceFormat requested = defaultSurfaceFormat();
- QSurfaceFormat actual = context->format();
- if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0)
- qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors");
- if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0)
- qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors");
- d->atlasManager = new QSGAtlasTexture::Manager();
+/*!
+ Sets whether or not the scene graph should use the distance field technique to render text
+ */
+void QSGContext::setDistanceFieldEnabled(bool enabled)
+{
+ d_func()->distanceFieldDisabled = !enabled;
+}
- Q_ASSERT(!d->gl);
- d->gl = context;
- emit initialized();
+/*!
+ Returns true if the scene graph uses the distance field technique to render text
+ */
+bool QSGContext::isDistanceFieldEnabled() const
+{
+ return !d_func()->distanceFieldDisabled;
}
+
+
/*!
- Returns if the scene graph context is ready or not, meaning that it has a valid
- GL context.
+ Creates a new animation driver.
*/
-bool QSGContext::isReady() const
+
+QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
{
- Q_D(const QSGContext);
- return d->gl;
+ return new QAnimationDriver(parent);
}
+QSGRenderContext::QSGRenderContext(QSGContext *context)
+ : m_gl(0)
+ , m_sg(context)
+ , m_atlasManager(0)
+ , m_depthStencilManager(0)
+ , m_distanceFieldCacheManager(0)
+ , m_brokenIBOs(false)
+ , m_serializedRender(false)
+{
+}
-void QSGContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
+QSGRenderContext::~QSGRenderContext()
{
+ invalidate();
+}
+
+static QBasicMutex qsg_framerender_mutex;
+
+void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
+{
+ if (m_serializedRender)
+ qsg_framerender_mutex.lock();
+
if (fboId) {
QSGBindableFboId bindable(fboId);
renderer->renderScene(bindable);
@@ -333,39 +363,20 @@ void QSGContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
renderer->renderScene();
}
-}
+ if (m_serializedRender)
+ qsg_framerender_mutex.unlock();
-/*!
- Factory function for scene graph backends of the Rectangle element.
- */
-QSGRectangleNode *QSGContext::createRectangleNode()
-{
- Q_D(QSGContext);
- return d->msaa ? new QSGMultisampleAntialiasing::RectangleNode
- : new QSGDefaultRectangleNode;
-}
-
-/*!
- Factory function for scene graph backends of the Image element.
- */
-QSGImageNode *QSGContext::createImageNode()
-{
- Q_D(QSGContext);
- return d->msaa ? new QSGMultisampleAntialiasing::ImageNode
- : new QSGDefaultImageNode;
}
/*!
Factory function for scene graph backends of the distance-field glyph cache.
*/
-QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &font)
+QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &font)
{
- Q_D(QSGContext);
-
- if (!d->distanceFieldCacheManager)
- d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
+ if (!m_distanceFieldCacheManager)
+ m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
- QSGDistanceFieldGlyphCache *cache = d->distanceFieldCacheManager->cache(font);
+ QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font);
if (!cache) {
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
if (platformIntegration != 0
@@ -387,125 +398,125 @@ QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &
QPlatformSharedGraphicsCache::Alpha8);
cache = new QSGSharedDistanceFieldGlyphCache(keyName,
- sharedGraphicsCache,
- d->distanceFieldCacheManager,
- glContext(),
- font);
+ sharedGraphicsCache,
+ m_distanceFieldCacheManager,
+ openglContext(),
+ font);
}
}
}
if (!cache)
- cache = new QSGDefaultDistanceFieldGlyphCache(d->distanceFieldCacheManager, glContext(), font);
- d->distanceFieldCacheManager->insertCache(font, cache);
+ cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font);
+ m_distanceFieldCacheManager->insertCache(font, cache);
}
+
return cache;
}
-/*!
- Factory function for scene graph backends of the Text elements which supports native
- text rendering. Used in special cases where native look and feel is a main objective.
-*/
-QSGGlyphNode *QSGContext::createNativeGlyphNode()
+#define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext"
+
+QSGRenderContext *QSGRenderContext::from(QOpenGLContext *context)
{
-#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE)
- Q_D(QSGContext);
- if (d->distanceFieldDisabled)
- return new QSGDefaultGlyphNode;
- else
- return createGlyphNode();
-#else
- return new QSGDefaultGlyphNode;
-#endif
+ return qobject_cast<QSGRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>());
}
-/*!
- Factory function for scene graph backends of the Text elements;
- */
-QSGGlyphNode *QSGContext::createGlyphNode()
+void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine)
{
- Q_D(QSGContext);
-
- if (d->distanceFieldDisabled) {
- return createNativeGlyphNode();
- } else {
- QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(this);
- node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing);
- return node;
- }
+ m_fontEnginesToClean << engine;
}
/*!
- Factory function for the scene graph renderers.
-
- The renderers are used for the toplevel renderer and once for every
- QQuickShaderEffectSource used in the QML scene.
+ Initializes the scene graph render context with the GL context \a context. This also
+ emits the ready() signal so that the QML graph can start building scene graph nodes.
*/
-QSGRenderer *QSGContext::createRenderer()
+void QSGRenderContext::initialize(QOpenGLContext *context)
{
- return new QSGBatchRenderer::Renderer(this);
-}
-
-
+ // Sanity check the surface format, in case it was overridden by the application
+ QSurfaceFormat requested = m_sg->defaultSurfaceFormat();
+ QSurfaceFormat actual = context->format();
+ if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0)
+ qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors");
+ if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0)
+ qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors");
+ if (!m_atlasManager)
+ m_atlasManager = new QSGAtlasTexture::Manager();
+
+ Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!");
+ m_gl = context;
+ m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this));
+ m_sg->renderContextInitialized(this);
+
+#ifdef Q_OS_LINUX
+ const char *vendor = (const char *) glGetString(GL_VENDOR);
+ if (strstr(vendor, "nouveau"))
+ m_brokenIBOs = true;
+ const char *renderer = (const char *) glGetString(GL_RENDERER);
+ if (strstr(renderer, "llvmpipe"))
+ m_serializedRender = true;
+#endif
-QSurfaceFormat QSGContext::defaultSurfaceFormat() const
-{
- QSurfaceFormat format;
- format.setDepthBufferSize(24);
- format.setStencilBufferSize(8);
- if (QQuickWindow::hasDefaultAlphaBuffer())
- format.setAlphaBufferSize(8);
- format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
- return format;
+ emit initialized();
}
-
-/*!
- Factory function for texture objects.
-
- If \a image is a valid image, the QSGTexture::setImage function
- will be called with \a image as argument.
- */
-
-QSGTexture *QSGContext::createTexture(const QImage &image) const
+void QSGRenderContext::invalidate()
{
- Q_D(const QSGContext);
- QSGTexture *at = d->atlasManager->create(image);
- if (at)
- return at;
- return createTextureNoAtlas(image);
-}
+ if (!m_gl)
+ return;
+
+ qDeleteAll(m_textures.values());
+ m_textures.clear();
+
+ /* The cleanup of the atlas textures is a bit intriguing.
+ As part of the cleanup in the threaded render loop, we
+ do:
+ 1. call this function
+ 2. call QCoreApp::sendPostedEvents() to immediately process
+ any pending deferred deletes.
+ 3. delete the GL context.
+
+ As textures need the atlas manager while cleaning up, the
+ manager needs to be cleaned up after the textures, so
+ we post a deleteLater here at the very bottom so it gets
+ deferred deleted last.
+
+ Another alternative would be to use a QPointer in
+ QSGAtlasTexture::Texture, but this seemed simpler.
+ */
+ m_atlasManager->invalidate();
+ m_atlasManager->deleteLater();
+ m_atlasManager = 0;
+
+ // The following piece of code will read/write to the font engine's caches,
+ // potentially from different threads. However, this is safe because this
+ // code is only called from QQuickWindow's shutdown which is called
+ // only when the GUI is blocked, and multiple threads will call it in
+ // sequence. (see qsgdefaultglyphnode_p.cpp's init())
+ for (QSet<QFontEngine *>::const_iterator it = m_fontEnginesToClean.constBegin(),
+ end = m_fontEnginesToClean.constEnd(); it != end; ++it) {
+ (*it)->clearGlyphCache(m_gl);
+ }
+ m_fontEnginesToClean.clear();
-QSGTexture *QSGContext::createTextureNoAtlas(const QImage &image) const
-{
- QSGPlainTexture *t = new QSGPlainTexture();
- if (!image.isNull())
- t->setImage(image);
- return t;
-}
+ delete m_depthStencilManager;
+ m_depthStencilManager = 0;
-/*!
- Returns the minimum supported framebuffer object size.
- */
-
-QSize QSGContext::minimumFBOSize() const
-{
-#ifdef Q_OS_MAC
- return QSize(33, 33);
-#else
- return QSize(1, 1);
-#endif
-}
+ delete m_distanceFieldCacheManager;
+ m_distanceFieldCacheManager = 0;
+ m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
+ m_gl = 0;
+ m_sg->renderContextInvalidated(this);
+ emit invalidated();
+}
/*!
Returns a shared pointer to a depth stencil buffer that can be used with \a fbo.
*/
-QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
+QSharedPointer<QSGDepthStencilBuffer> QSGRenderContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
{
- Q_D(QSGContext);
- if (!d->gl)
+ if (!m_gl)
return QSharedPointer<QSGDepthStencilBuffer>();
QSGDepthStencilBufferManager *manager = depthStencilBufferManager();
QSGDepthStencilBuffer::Format format;
@@ -514,7 +525,7 @@ QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpen
format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment;
QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format);
if (buffer.isNull()) {
- buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(d->gl, format));
+ buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(m_gl, format));
manager->insertBuffer(buffer);
}
return buffer;
@@ -524,89 +535,81 @@ QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpen
Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom
implementations of \l depthStencilBufferForFbo().
*/
-QSGDepthStencilBufferManager *QSGContext::depthStencilBufferManager()
+QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager()
{
- Q_D(QSGContext);
- if (!d->gl)
+ if (!m_gl)
return 0;
- if (!d->depthStencilBufferManager)
- d->depthStencilBufferManager = new QSGDepthStencilBufferManager(d->gl);
- return d->depthStencilBufferManager;
+ if (!m_depthStencilManager)
+ m_depthStencilManager = new QSGDepthStencilBufferManager(m_gl);
+ return m_depthStencilManager;
}
/*!
- Sets whether the scene graph should render with flashing update rectangles or not
- */
-
-void QSGContext::setFlashModeEnabled(bool enabled)
-{
- d_func()->flashMode = enabled;
-}
-
+ Factory function for texture objects.
-/*!
- Returns true if the scene graph should be rendered with flashing update rectangles
+ If \a image is a valid image, the QSGTexture::setImage function
+ will be called with \a image as argument.
*/
-bool QSGContext::isFlashModeEnabled() const
+
+QSGTexture *QSGRenderContext::createTexture(const QImage &image) const
{
- return d_func()->flashMode;
+ QSGTexture *t = m_atlasManager->create(image);
+ if (t)
+ return t;
+ return createTextureNoAtlas(image);
}
-
-/*!
- Sets the toplevel opacity for rendering. This value will be multiplied into all
- drawing calls where possible.
-
- The default value is 1. Any other value will cause artifacts and is primarily
- useful for debugging.
- */
-void QSGContext::setRenderAlpha(qreal renderAlpha)
+QSGTexture *QSGRenderContext::createTextureNoAtlas(const QImage &image) const
{
- d_func()->renderAlpha = renderAlpha;
+ QSGPlainTexture *t = new QSGPlainTexture();
+ if (!image.isNull())
+ t->setImage(image);
+ return t;
}
-
/*!
- Returns the toplevel opacity used for rendering.
-
- The default value is 1.
+ Factory function for the scene graph renderers.
- \sa setRenderAlpha()
+ The renderers are used for the toplevel renderer and once for every
+ QQuickShaderEffectSource used in the QML scene.
*/
-qreal QSGContext::renderAlpha() const
+QSGRenderer *QSGRenderContext::createRenderer()
{
- return d_func()->renderAlpha;
+ return new QSGBatchRenderer::Renderer(this);
}
-
-/*!
- Sets whether or not the scene graph should use the distance field technique to render text
- */
-void QSGContext::setDistanceFieldEnabled(bool enabled)
+QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window)
{
- d_func()->distanceFieldDisabled = !enabled;
-}
+ if (!factory)
+ return 0;
+ m_mutex.lock();
+ QSGTexture *texture = m_textures.value(factory);
+ m_mutex.unlock();
-/*!
- Returns true if the scene graph uses the distance field technique to render text
- */
-bool QSGContext::isDistanceFieldEnabled() const
-{
- return !d_func()->distanceFieldDisabled;
-}
-
+ if (!texture) {
+ if (QQuickDefaultTextureFactory *dtf = qobject_cast<QQuickDefaultTextureFactory *>(factory))
+ texture = createTexture(dtf->image());
+ else
+ texture = factory->createTexture(window);
+ m_mutex.lock();
+ m_textures.insert(factory, texture);
+ m_mutex.unlock();
-/*!
- Creates a new animation driver.
- */
+ connect(factory, SIGNAL(destroyed(QObject *)), this, SLOT(textureFactoryDestroyed(QObject *)), Qt::DirectConnection);
+ }
+ return texture;
+}
-QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
+void QSGRenderContext::textureFactoryDestroyed(QObject *o)
{
- return new QAnimationDriver(parent);
+ m_mutex.lock();
+ QSGTexture *t = m_textures.take(static_cast<QQuickTextureFactory *>(o));
+ m_mutex.unlock();
+ if (t)
+ t->deleteLater();
}
-
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 2057c0031d..c562a909c5 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -56,6 +56,9 @@
QT_BEGIN_NAMESPACE
+namespace QSGAtlasTexture {
+ class Manager;
+}
class QSGContextPrivate;
class QSGRectangleNode;
@@ -73,66 +76,102 @@ class QOpenGLContext;
class QOpenGLFramebufferObject;
class QQuickTextureFactory;
+class QSGDistanceFieldGlyphCacheManager;
+class QSGContext;
-class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
+
+class Q_QUICK_PRIVATE_EXPORT QSGRenderContext : public QObject
{
Q_OBJECT
- Q_DECLARE_PRIVATE(QSGContext)
-
public:
- explicit QSGContext(QObject *parent = 0);
- ~QSGContext();
+ QSGRenderContext(QSGContext *context);
+ ~QSGRenderContext();
+
+ QOpenGLContext *openglContext() const { return m_gl; }
+ QSGContext *sceneGraphContext() const { return m_sg; }
virtual void initialize(QOpenGLContext *context);
virtual void invalidate();
- QOpenGLContext *glContext() const;
-
- bool isReady() const;
-
virtual void renderNextFrame(QSGRenderer *renderer, GLuint fboId);
- virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font);
+ virtual QSharedPointer<QSGDepthStencilBuffer> depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo);
+ QSGDepthStencilBufferManager *depthStencilBufferManager();
- virtual QSGRectangleNode *createRectangleNode();
- virtual QSGImageNode *createImageNode();
- virtual QSGGlyphNode *createGlyphNode();
- virtual QSGGlyphNode *createNativeGlyphNode();
- virtual QSGRenderer *createRenderer();
+ virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font);
+ QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window);
virtual QSGTexture *createTexture(const QImage &image) const;
virtual QSGTexture *createTextureNoAtlas(const QImage &image) const;
- virtual QSize minimumFBOSize() const;
- virtual QSharedPointer<QSGDepthStencilBuffer> depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo);
- QSGDepthStencilBufferManager *depthStencilBufferManager();
+ virtual QSGRenderer *createRenderer();
- virtual QSurfaceFormat defaultSurfaceFormat() const;
+ void registerFontengineForCleanup(QFontEngine *engine);
- QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window);
+ static QSGRenderContext *from(QOpenGLContext *context);
- static QSGContext *createDefaultContext();
+ bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
- void setFlashModeEnabled(bool enabled);
- bool isFlashModeEnabled() const;
+Q_SIGNALS:
+ void initialized();
+ void invalidated();
+
+public Q_SLOTS:
+ void textureFactoryDestroyed(QObject *o);
- void setRenderAlpha(qreal renderAlpha);
- qreal renderAlpha() const;
+protected:
+ QOpenGLContext *m_gl;
+ QSGContext *m_sg;
- void setDistanceFieldEnabled(bool enabled);
- bool isDistanceFieldEnabled() const;
+ QMutex m_mutex;
+ QHash<QQuickTextureFactory *, QSGTexture *> m_textures;
+ QSGAtlasTexture::Manager *m_atlasManager;
+ QSGDepthStencilBufferManager *m_depthStencilManager;
+ QSGDistanceFieldGlyphCacheManager *m_distanceFieldCacheManager;
+
+ QSet<QFontEngine *> m_fontEnginesToClean;
+
+ bool m_brokenIBOs;
+ bool m_serializedRender;
+};
+
+
+class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGContext)
+
+public:
+ enum AntialiasingMethod {
+ UndecidedAntialiasing,
+ VertexAntialiasing,
+ MsaaAntialiasing
+ };
+
+ explicit QSGContext(QObject *parent = 0);
+ ~QSGContext();
+
+ virtual void renderContextInitialized(QSGRenderContext *renderContext);
+ virtual void renderContextInvalidated(QSGRenderContext *renderContext);
+
+ virtual QSGRectangleNode *createRectangleNode();
+ virtual QSGImageNode *createImageNode();
+ virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc);
+ virtual QSGGlyphNode *createNativeGlyphNode(QSGRenderContext *rc);
virtual QAnimationDriver *createAnimationDriver(QObject *parent);
- static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
- static QSGRenderLoop *createWindowManager();
+ virtual QSize minimumFBOSize() const;
+ virtual QSurfaceFormat defaultSurfaceFormat() const;
+ static void setSharedOpenGLContext(QOpenGLContext *context);
+ static QOpenGLContext *sharedOpenGLContext();
-public Q_SLOTS:
- void textureFactoryDestroyed(QObject *o);
+ void setDistanceFieldEnabled(bool enabled);
+ bool isDistanceFieldEnabled() const;
-Q_SIGNALS:
- void initialized();
- void invalidated();
+ static QSGContext *createDefaultContext();
+ static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
+ static QSGRenderLoop *createWindowManager();
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 8a1a87cdc0..c5c4e18e37 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -48,6 +48,10 @@
#include <qopenglfunctions.h>
#include <qmath.h>
+#if !defined(QT_OPENGL_ES_2)
+#include <QtGui/qopenglfunctions_3_2_core.h>
+#endif
+
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlUseGlyphCacheWorkaround, QML_USE_GLYPHCACHE_WORKAROUND)
@@ -58,6 +62,9 @@ QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistance
, m_maxTextureCount(3)
, m_blitProgram(0)
, m_fboGuard(0)
+#if !defined(QT_OPENGL_ES_2)
+ , m_funcs(0)
+#endif
{
m_blitVertexCoordinateArray[0] = -1.0f;
m_blitVertexCoordinateArray[1] = -1.0f;
@@ -167,7 +174,7 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
if (glyph.width() != expectedWidth)
glyph = glyph.copy(0, 0, expectedWidth, glyph.height());
- if (useWorkaround()) {
+ if (useTextureResizeWorkaround()) {
uchar *inBits = glyph.scanLine(0);
uchar *outBits = texInfo->image.scanLine(int(c.y)) + int(c.x);
for (int y = 0; y < glyph.height(); ++y) {
@@ -177,7 +184,24 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
}
}
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
+#if !defined(QT_OPENGL_ES_2)
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLenum format = GL_ALPHA;
+#endif
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < glyph.height(); ++i) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ c.x, c.y + i, glyph.width(),1,
+ format, GL_UNSIGNED_BYTE,
+ glyph.scanLine(i));
+ }
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ c.x, c.y, glyph.width(), glyph.height(),
+ format, GL_UNSIGNED_BYTE,
+ glyph.constBits());
+ }
}
// restore to previous alignment
@@ -204,7 +228,7 @@ void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyph
void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int width, int height)
{
- if (useWorkaround() && texInfo->image.isNull())
+ if (useTextureResizeWorkaround() && texInfo->image.isNull())
texInfo->image = QDistanceField(width, height);
while (glGetError() != GL_NO_ERROR) { }
@@ -212,11 +236,20 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int
glGenTextures(1, &texInfo->texture);
glBindTexture(GL_TEXTURE_2D, texInfo->texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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);
+ const GLint internalFormat = isCoreProfile() ? GL_R8 : GL_ALPHA;
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLint internalFormat = GL_ALPHA;
+ const GLenum format = GL_ALPHA;
+#endif
+
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, 0);
texInfo->size = QSize(width, height);
@@ -236,6 +269,9 @@ static void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id)
void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int width, int height)
{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ Q_ASSERT(ctx);
+
int oldWidth = texInfo->size.width();
int oldHeight = texInfo->size.height();
if (width == oldWidth && height == oldHeight)
@@ -249,12 +285,76 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
updateTexture(oldTexture, texInfo->texture, texInfo->size);
- if (useWorkaround()) {
+#if !defined(QT_OPENGL_ES_2)
+ if (isCoreProfile() && !useTextureResizeWorkaround()) {
+ // For an OpenGL Core Profile we can use http://www.opengl.org/wiki/Framebuffer#Blitting
+ // to efficiently copy the contents of the old texture to the new texture
+ // TODO: Use ARB_copy_image if available of if we have >=4.3 context
+ if (!m_funcs) {
+ m_funcs = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>();
+ Q_ASSERT(m_funcs);
+ m_funcs->initializeOpenGLFunctions();
+ }
+
+ // Create a framebuffer object to which we can attach our old and new textures (to
+ // the first two color buffer attachment points)
+ if (!m_fboGuard) {
+ GLuint fbo;
+ m_funcs->glGenFramebuffers(1, &fbo);
+ m_fboGuard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
+ }
+
+ // Bind the FBO to both the GL_READ_FRAMEBUFFER? and GL_DRAW_FRAMEBUFFER targets
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_fboGuard->id());
+
+ // Bind the old texture to GL_COLOR_ATTACHMENT0
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, oldTexture, 0);
+
+ // Bind the new texture to GL_COLOR_ATTACHMENT1
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
+ GL_TEXTURE_2D, texInfo->texture, 0);
+
+ // Set the source and destination buffers
+ m_funcs->glReadBuffer(GL_COLOR_ATTACHMENT0);
+ m_funcs->glDrawBuffer(GL_COLOR_ATTACHMENT1);
+
+ // Do the blit
+ m_funcs->glBlitFramebuffer(0, 0, oldWidth, oldHeight,
+ 0, 0, oldWidth, oldHeight,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ // Reset the default framebuffer
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return;
+ } else if (useTextureResizeWorkaround()) {
+#else
+ if (useTextureResizeWorkaround()) {
+#endif
GLint alignment = 4; // default value
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, texInfo->image.constBits());
+#if !defined(QT_OPENGL_ES_2)
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLenum format = GL_ALPHA;
+#endif
+
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < texInfo->image.height(); ++i) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, i, oldWidth, 1,
+ format, GL_UNSIGNED_BYTE,
+ texInfo->image.scanLine(i));
+ }
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, 0, oldWidth, oldHeight,
+ format, GL_UNSIGNED_BYTE,
+ texInfo->image.constBits());
+ }
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); // restore to previous value
@@ -278,12 +378,15 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
GLuint tmp_texture;
glGenTextures(1, &tmp_texture);
glBindTexture(GL_TEXTURE_2D, tmp_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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);
+#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tmp_texture, 0);
@@ -325,7 +428,12 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
glBindTexture(GL_TEXTURE_2D, texInfo->texture);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < oldHeight; ++i)
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, 0, i, oldWidth, 1);
+ } else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+ }
ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0);
@@ -350,12 +458,12 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
m_blitProgram->disableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
}
-bool QSGDefaultDistanceFieldGlyphCache::useWorkaround() const
+bool QSGDefaultDistanceFieldGlyphCache::useTextureResizeWorkaround() const
{
static bool set = false;
static bool useWorkaround = false;
if (!set) {
- QOpenGLContextPrivate *ctx_p = static_cast<QOpenGLContextPrivate *>(QOpenGLContextPrivate::get(ctx));
+ QOpenGLContextPrivate *ctx_p = static_cast<QOpenGLContextPrivate *>(QOpenGLContextPrivate::get(QOpenGLContext::currentContext()));
useWorkaround = ctx_p->workaround_brokenFBOReadBack
|| qmlUseGlyphCacheWorkaround(); // on some hardware the workaround is faster (see QTBUG-29264)
set = true;
@@ -363,6 +471,18 @@ bool QSGDefaultDistanceFieldGlyphCache::useWorkaround() const
return useWorkaround;
}
+bool QSGDefaultDistanceFieldGlyphCache::useTextureUploadWorkaround() const
+{
+ static bool set = false;
+ static bool useWorkaround = false;
+ if (!set) {
+ useWorkaround = qstrcmp(reinterpret_cast<const char*>(glGetString(GL_RENDERER)),
+ "Mali-400 MP") == 0;
+ set = true;
+ }
+ return useWorkaround;
+}
+
int QSGDefaultDistanceFieldGlyphCache::maxTextureSize() const
{
if (!m_maxTextureSize)
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
index cd6fa00852..a5833af5fb 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -51,6 +51,10 @@
QT_BEGIN_NAMESPACE
class QOpenGLSharedResourceGuard;
+#if !defined(QT_OPENGL_ES_2)
+class QOpenGLFunctions_3_2_Core;
+#endif
+
class Q_QUICK_PRIVATE_EXPORT QSGDefaultDistanceFieldGlyphCache : public QSGDistanceFieldGlyphCache
{
public:
@@ -62,7 +66,8 @@ public:
void referenceGlyphs(const QSet<glyph_t> &glyphs);
void releaseGlyphs(const QSet<glyph_t> &glyphs);
- bool useWorkaround() const;
+ bool useTextureResizeWorkaround() const;
+ bool useTextureUploadWorkaround() const;
int maxTextureSize() const;
void setMaxTextureCount(int max) { m_maxTextureCount = max; }
@@ -132,6 +137,9 @@ private:
GLfloat m_blitTextureCoordinateArray[8];
QOpenGLSharedResourceGuard *m_fboGuard;
+#if !defined(QT_OPENGL_ES_2)
+ QOpenGLFunctions_3_2_Core *m_funcs;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 39d9832f58..35c4d1c506 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgdefaultglyphnode_p_p.h"
+#include <private/qsgmaterialshader_p.h>
#include <qopenglshaderprogram.h>
@@ -75,8 +76,6 @@ public:
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrix_id;
int m_color_id;
@@ -85,30 +84,6 @@ protected:
QFontEngineGlyphCache::Type m_cacheType;
};
-const char *QSGTextMaskShader::vertexShader() const {
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *QSGTextMaskShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "void main() { \n"
- " lowp vec4 glyph = texture2D(_qt_texture, sampleCoord); \n"
- " gl_FragColor = vec4(glyph.rgb * color.a, glyph.a); \n"
- "}";
-}
-
char const *const *QSGTextMaskShader::attributeNames() const
{
static char const *const attr[] = { "vCoord", "tCoord", 0 };
@@ -116,8 +91,11 @@ char const *const *QSGTextMaskShader::attributeNames() const
}
QSGTextMaskShader::QSGTextMaskShader(QFontEngineGlyphCache::Type cacheType)
- : m_cacheType(cacheType)
+ : QSGMaterialShader(*new QSGMaterialShaderPrivate),
+ m_cacheType(cacheType)
{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/textmask.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/textmask.frag"));
}
static inline qreal fontSmoothingGamma()
@@ -186,22 +164,13 @@ class QSG8BitTextMaskShader : public QSGTextMaskShader
public:
QSG8BitTextMaskShader(QFontEngineGlyphCache::Type cacheType)
: QSGTextMaskShader(cacheType)
- {}
+ {
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/8bittextmask.frag"));
+ }
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual const char *fragmentShader() const;
};
-const char *QSG8BitTextMaskShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform lowp sampler2D texture; \n"
- "uniform lowp vec4 color; \n"
- "void main() { \n"
- " gl_FragColor = color * texture2D(texture, sampleCoord).a; \n"
- "}";
-}
-
void QSG8BitTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
QSGTextMaskShader::updateState(state, newEffect, oldEffect);
@@ -220,28 +189,18 @@ public:
QSG24BitTextMaskShader(QFontEngineGlyphCache::Type cacheType)
: QSGTextMaskShader(cacheType)
, m_useSRGB(false)
- {}
+ {
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/24bittextmask.frag"));
+ }
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual void initialize();
void activate();
void deactivate();
- virtual const char *fragmentShader() const;
uint m_useSRGB : 1;
};
-const char *QSG24BitTextMaskShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform lowp sampler2D texture; \n"
- "uniform lowp float color; // just the alpha, really... \n"
- "void main() { \n"
- " lowp vec4 glyph = texture2D(texture, sampleCoord); \n"
- " gl_FragColor = vec4(glyph.rgb * color, glyph.a); \n"
- "}";
-}
-
void QSG24BitTextMaskShader::initialize()
{
QSGTextMaskShader::initialize();
@@ -302,14 +261,15 @@ class QSGStyledTextShader : public QSG8BitTextMaskShader
public:
QSGStyledTextShader(QFontEngineGlyphCache::Type cacheType)
: QSG8BitTextMaskShader(cacheType)
- { }
+ {
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/styledtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/styledtext.frag"));
+ }
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
private:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_shift_id;
int m_styleColor_id;
@@ -367,98 +327,17 @@ void QSGStyledTextShader::updateState(const RenderState &state,
program()->setUniformValue(m_matrix_id, state.combinedMatrix());
}
-const char *QSGStyledTextShader::vertexShader() const
-{
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "uniform highp vec2 shift; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " shiftedSampleCoord = (tCoord - shift) * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *QSGStyledTextShader::fragmentShader() const
-{
- return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "void main() { \n"
- " lowp float glyph = texture2D(_qt_texture, sampleCoord).a; \n"
- " lowp float style = clamp(texture2D(_qt_texture, shiftedSampleCoord).a - glyph, \n"
- " 0.0, 1.0); \n"
- " gl_FragColor = style * styleColor + glyph * color; \n"
- "}";
-}
-
-
class QSGOutlinedTextShader : public QSGStyledTextShader
{
public:
QSGOutlinedTextShader(QFontEngineGlyphCache::Type cacheType)
: QSGStyledTextShader(cacheType)
- { }
-
-private:
- const char *vertexShader() const;
- const char *fragmentShader() const;
+ {
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/outlinedtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/outlinedtext.frag"));
+ }
};
-const char *QSGOutlinedTextShader::vertexShader() const
-{
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "uniform highp vec2 shift; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 sCoordUp; \n"
- "varying highp vec2 sCoordDown; \n"
- "varying highp vec2 sCoordLeft; \n"
- "varying highp vec2 sCoordRight; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " sCoordUp = (tCoord - vec2(0.0, -1.0)) * textureScale; \n"
- " sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale; \n"
- " sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale; \n"
- " sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *QSGOutlinedTextShader::fragmentShader() const
-{
- return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 sCoordUp; \n"
- "varying highp vec2 sCoordDown; \n"
- "varying highp vec2 sCoordLeft; \n"
- "varying highp vec2 sCoordRight; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "void main() { \n"
- "lowp float glyph = texture2D(_qt_texture, sampleCoord).a; \n"
- " lowp float outline = clamp(clamp(texture2D(_qt_texture, sCoordUp).a + \n"
- " texture2D(_qt_texture, sCoordDown).a + \n"
- " texture2D(_qt_texture, sCoordLeft).a + \n"
- " texture2D(_qt_texture, sCoordRight).a, \n"
- " 0.0, 1.0) - glyph, \n"
- " 0.0, 1.0); \n"
- " gl_FragColor = outline * styleColor + glyph * color; \n"
- "}";
-}
-
QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font, int cacheType)
: m_texture(0)
, m_glyphCache(0)
@@ -480,6 +359,12 @@ void QSGTextMaskMaterial::init(int cacheType)
QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
Q_ASSERT(ctx != 0);
+ // The following piece of code will read/write to the font engine's caches,
+ // potentially from different threads. However, this is safe because this
+ // code is only called from QQuickItem::updatePaintNode() which is called
+ // only when the GUI is blocked, and multiple threads will call it in
+ // sequence. See also QSGRenderContext::invalidate
+
QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
if (fontD->fontEngine != 0) {
if (cacheType < 0) {
@@ -494,6 +379,9 @@ void QSGTextMaskMaterial::init(int cacheType)
m_glyphCache = new QOpenGLTextureGlyphCache(QFontEngineGlyphCache::Type(cacheType),
QTransform());
fontD->fontEngine->setGlyphCache(ctx, m_glyphCache.data());
+ QSGRenderContext *sg = QSGRenderContext::from(ctx);
+ Q_ASSERT(sg);
+ sg->registerFontengineForCleanup(fontD->fontEngine);
}
}
}
diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultimagenode.cpp
index 11d0e5dbeb..926c0c1f4a 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultimagenode.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgdefaultimagenode_p.h"
+#include <private/qsgmaterialshader_p.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qmath.h>
@@ -75,13 +76,13 @@ namespace
class SmoothTextureMaterialShader : public QSGTextureMaterialShader
{
public:
+ SmoothTextureMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_pixelSizeLoc;
};
@@ -109,6 +110,13 @@ QSGMaterialShader *QSGSmoothTextureMaterial::createShader() const
return new SmoothTextureMaterialShader;
}
+SmoothTextureMaterialShader::SmoothTextureMaterialShader()
+ : QSGTextureMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/smoothtexture.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/smoothtexture.frag"));
+}
+
void SmoothTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
if (oldEffect == 0) {
@@ -137,70 +145,6 @@ void SmoothTextureMaterialShader::initialize()
QSGTextureMaterialShader::initialize();
}
-const char *SmoothTextureMaterialShader::vertexShader() const
-{
- return
- "uniform highp vec2 pixelSize; \n"
- "uniform highp mat4 qt_Matrix; \n"
- "uniform lowp float opacity; \n"
- "attribute highp vec4 vertex; \n"
- "attribute highp vec2 multiTexCoord; \n"
- "attribute highp vec2 vertexOffset; \n"
- "attribute highp vec2 texCoordOffset; \n"
- "varying highp vec2 texCoord; \n"
- "varying lowp float vertexOpacity; \n"
- "void main() { \n"
- " highp vec4 pos = qt_Matrix * vertex; \n"
- " gl_Position = pos; \n"
- " texCoord = multiTexCoord; \n"
-
- " if (vertexOffset.x != 0.) { \n"
- " highp vec4 delta = qt_Matrix[0] * vertexOffset.x; \n"
- " highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
- " highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize); \n"
- " dir -= ndir * delta.w * pos.w; \n"
- " highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
- " highp float scale = 0.0; \n"
- " if (numerator < 0.0) \n"
- " scale = 1.0; \n"
- " else \n"
- " scale = min(1.0, numerator / dot(dir, dir)); \n"
- " gl_Position += scale * delta; \n"
- " texCoord.x += scale * texCoordOffset.x; \n"
- " } \n"
-
- " if (vertexOffset.y != 0.) { \n"
- " highp vec4 delta = qt_Matrix[1] * vertexOffset.y; \n"
- " highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
- " highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize); \n"
- " dir -= ndir * delta.w * pos.w; \n"
- " highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
- " highp float scale = 0.0; \n"
- " if (numerator < 0.0) \n"
- " scale = 1.0; \n"
- " else \n"
- " scale = min(1.0, numerator / dot(dir, dir)); \n"
- " gl_Position += scale * delta; \n"
- " texCoord.y += scale * texCoordOffset.y; \n"
- " } \n"
-
- " bool onEdge = any(notEqual(vertexOffset, vec2(0.))); \n"
- " bool outerEdge = all(equal(texCoordOffset, vec2(0.))); \n"
- " vertexOpacity = onEdge && outerEdge ? 0. : opacity; \n"
- "}";
-}
-
-const char *SmoothTextureMaterialShader::fragmentShader() const
-{
- return
- "uniform sampler2D qt_Texture; \n"
- "varying highp vec2 texCoord; \n"
- "varying lowp float vertexOpacity; \n"
- "void main() { \n"
- " gl_FragColor = texture2D(qt_Texture, texCoord) * vertexOpacity; \n"
- "}";
-}
-
QSGDefaultImageNode::QSGDefaultImageNode()
: m_innerSourceRect(0, 0, 1, 1)
, m_subSourceRect(0, 0, 1, 1)
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
index 14c61bae79..fb989fd6fb 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
@@ -110,19 +110,26 @@ namespace
class SmoothColorMaterialShader : public QSGMaterialShader
{
public:
+ SmoothColorMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
private:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrixLoc;
int m_opacityLoc;
int m_pixelSizeLoc;
};
+SmoothColorMaterialShader::SmoothColorMaterialShader()
+ : QSGMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/smoothcolor.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/smoothcolor.frag"));
+}
+
void SmoothColorMaterialShader::updateState(const RenderState &state, QSGMaterial *, QSGMaterial *oldEffect)
{
if (state.isOpacityDirty())
@@ -156,61 +163,6 @@ void SmoothColorMaterialShader::initialize()
m_pixelSizeLoc = program()->uniformLocation("pixelSize");
}
-const char *SmoothColorMaterialShader::vertexShader() const
-{
- return
- "uniform highp vec2 pixelSize; \n"
- "uniform highp mat4 matrix; \n"
- "uniform lowp float opacity; \n"
- "attribute highp vec4 vertex; \n"
- "attribute lowp vec4 vertexColor; \n"
- "attribute highp vec2 vertexOffset; \n"
- "varying lowp vec4 color; \n"
- "void main() { \n"
- " highp vec4 pos = matrix * vertex; \n"
- " gl_Position = pos; \n"
-
- " if (vertexOffset.x != 0.) { \n"
- " highp vec4 delta = matrix[0] * vertexOffset.x; \n"
- " highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
- " highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize); \n"
- " dir -= ndir * delta.w * pos.w; \n"
- " highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
- " highp float scale = 0.0; \n"
- " if (numerator < 0.0) \n"
- " scale = 1.0; \n"
- " else \n"
- " scale = min(1.0, numerator / dot(dir, dir)); \n"
- " gl_Position += scale * delta; \n"
- " } \n"
-
- " if (vertexOffset.y != 0.) { \n"
- " highp vec4 delta = matrix[1] * vertexOffset.y; \n"
- " highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
- " highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize); \n"
- " dir -= ndir * delta.w * pos.w; \n"
- " highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
- " highp float scale = 0.0; \n"
- " if (numerator < 0.0) \n"
- " scale = 1.0; \n"
- " else \n"
- " scale = min(1.0, numerator / dot(dir, dir)); \n"
- " gl_Position += scale * delta; \n"
- " } \n"
-
- " color = vertexColor * opacity; \n"
- "}";
-}
-
-const char *SmoothColorMaterialShader::fragmentShader() const
-{
- return
- "varying lowp vec4 color; \n"
- "void main() { \n"
- " gl_FragColor = color; \n"
- "}";
-}
-
QSGSmoothColorMaterial::QSGSmoothColorMaterial()
{
setFlag(RequiresFullMatrixExceptTranslate, true);
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
index 876a9ea9ad..a9faf12096 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
-QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGContext *context)
+QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGRenderContext *context)
: m_glyphNodeType(RootGlyphNode)
, m_context(context)
, m_material(0)
@@ -235,7 +235,12 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
if (texture->textureId && !m_texture)
m_texture = texture;
- if (m_texture != texture) {
+ // As we use UNSIGNED_SHORT indexing in the geometry, we overload the
+ // "glyphsInOtherTextures" concept as overflow for if there are more than
+ // 65536 vertices to render which would otherwise exceed the maximum index
+ // size. This will cause sub-nodes to be recursively created to handle any
+ // number of glyphs.
+ if (m_texture != texture || vp.size() >= 65536) {
if (texture->textureId) {
GlyphInfo &glyphInfo = glyphsInOtherTextures[texture];
glyphInfo.indexes.append(glyphIndex);
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index 125243847a..12a431246c 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -59,8 +59,6 @@ public:
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
void updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc);
void updateColor(const QVector4D &c);
@@ -81,44 +79,20 @@ protected:
float m_lastAlphaMax;
};
-const char *QSGDistanceFieldTextMaterialShader::vertexShader() const {
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *QSGDistanceFieldTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform mediump sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " gl_FragColor = color * smoothstep(alphaMin, \n"
- " alphaMax, \n"
- " texture2D(_qt_texture, sampleCoord).a); \n"
- "}";
-}
-
char const *const *QSGDistanceFieldTextMaterialShader::attributeNames() const {
static char const *const attr[] = { "vCoord", "tCoord", 0 };
return attr;
}
QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader()
- : m_fontScale(1.0)
+ : QSGMaterialShader(),
+ m_fontScale(1.0)
, m_matrixScale(1.0)
, m_lastAlphaMin(-1)
, m_lastAlphaMax(-1)
{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/distancefieldtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldtext.frag"));
}
void QSGDistanceFieldTextMaterialShader::updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc)
@@ -287,7 +261,6 @@ public:
protected:
virtual void initialize();
- virtual const char *fragmentShader() const = 0;
int m_styleColor_id;
};
@@ -355,7 +328,6 @@ public:
protected:
virtual void initialize();
- virtual const char *fragmentShader() const;
void updateOutlineAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc, int dfRadius);
@@ -363,26 +335,10 @@ protected:
int m_outlineAlphaMax1_id;
};
-const char *DistanceFieldOutlineTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "uniform mediump float outlineAlphaMax0; \n"
- "uniform mediump float outlineAlphaMax1; \n"
- "void main() { \n"
- " mediump float d = texture2D(_qt_texture, sampleCoord).a; \n"
- " gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d)) \n"
- " * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d); \n"
- "}";
-}
-
DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader()
: DistanceFieldStyledTextMaterialShader()
{
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldoutlinetext.frag"));
}
void DistanceFieldOutlineTextMaterialShader::initialize()
@@ -454,8 +410,6 @@ public:
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
void updateShift(qreal fontScale, const QPointF& shift);
@@ -465,6 +419,8 @@ protected:
DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader()
: DistanceFieldStyledTextMaterialShader()
{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.frag"));
}
void DistanceFieldShiftedStyleTextMaterialShader::initialize()
@@ -495,41 +451,6 @@ void DistanceFieldShiftedStyleTextMaterialShader::updateShift(qreal fontScale, c
program()->setUniformValue(m_shift_id, texel);
}
-const char *DistanceFieldShiftedStyleTextMaterialShader::vertexShader() const
-{
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "uniform highp vec2 shift; \n"
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " shiftedSampleCoord = (tCoord - shift) * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *DistanceFieldShiftedStyleTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " highp float a = smoothstep(alphaMin, alphaMax, texture2D(_qt_texture, sampleCoord).a); \n"
- " highp vec4 shifted = styleColor * smoothstep(alphaMin, \n"
- " alphaMax, \n"
- " texture2D(_qt_texture, shiftedSampleCoord).a); \n"
- " gl_FragColor = mix(shifted, color, a); \n"
- "}";
-}
-
QSGDistanceFieldShiftedStyleTextMaterial::QSGDistanceFieldShiftedStyleTextMaterial()
: QSGDistanceFieldStyledTextMaterial()
{
@@ -550,111 +471,35 @@ QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader() cons
return new DistanceFieldShiftedStyleTextMaterialShader;
}
+int QSGDistanceFieldShiftedStyleTextMaterial::compare(const QSGMaterial *o) const
+{
+ const QSGDistanceFieldShiftedStyleTextMaterial *other = static_cast<const QSGDistanceFieldShiftedStyleTextMaterial *>(o);
+ if (m_shift != other->m_shift)
+ return &m_shift < &other->m_shift ? -1 : 1;
+ return QSGDistanceFieldStyledTextMaterial::compare(o);
+}
class QSGHiQSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTextMaterialShader
{
public:
+ QSGHiQSubPixelDistanceFieldTextMaterialShader();
+
virtual void initialize();
virtual void activate();
virtual void deactivate();
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
-protected:
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
-
private:
int m_fontScale_id;
int m_vecDelta_id;
};
-const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "uniform highp float fontScale; \n"
- "uniform highp vec4 vecDelta; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec3 sampleFarLeft; \n"
- "varying highp vec3 sampleNearLeft; \n"
- "varying highp vec3 sampleNearRight; \n"
- "varying highp vec3 sampleFarRight; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- // Calculate neighbour pixel position in item space.
- " highp vec3 wDelta = gl_Position.w * vecDelta.xyw; \n"
- " highp vec3 farLeft = vCoord.xyw - 0.667 * wDelta; \n"
- " highp vec3 nearLeft = vCoord.xyw - 0.333 * wDelta; \n"
- " highp vec3 nearRight = vCoord.xyw + 0.333 * wDelta; \n"
- " highp vec3 farRight = vCoord.xyw + 0.667 * wDelta; \n"
- // Calculate neighbour texture coordinate.
- " highp vec2 scale = textureScale / fontScale; \n"
- " highp vec2 base = sampleCoord - scale * vCoord.xy; \n"
- " sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z); \n"
- " sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
- " sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
- " sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z); \n"
- "}";
-}
-
-const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec3 sampleFarLeft; \n"
- "varying highp vec3 sampleNearLeft; \n"
- "varying highp vec3 sampleNearRight; \n"
- "varying highp vec3 sampleFarRight; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " highp vec4 n; \n"
- " n.x = texture2DProj(_qt_texture, sampleFarLeft).a; \n"
- " n.y = texture2DProj(_qt_texture, sampleNearLeft).a; \n"
- " highp float c = texture2D(_qt_texture, sampleCoord).a; \n"
- " n.z = texture2DProj(_qt_texture, sampleNearRight).a; \n"
- " n.w = texture2DProj(_qt_texture, sampleFarRight).a; \n"
-#if 0
- // Blurrier, faster.
- " n = smoothstep(alphaMin, alphaMax, n); \n"
- " c = smoothstep(alphaMin, alphaMax, c); \n"
-#else
- // Sharper, slower.
- " highp vec2 d = min(abs(n.yw - n.xz) * 2., 0.67); \n"
- " highp vec2 lo = mix(vec2(alphaMin), vec2(0.5), d); \n"
- " highp vec2 hi = mix(vec2(alphaMax), vec2(0.5), d); \n"
- " n = smoothstep(lo.xxyy, hi.xxyy, n); \n"
- " c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c); \n"
-#endif
- " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
- "}";
-}
-
-//const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
-// return
-// "#extension GL_OES_standard_derivatives: enable \n"
-// "varying highp vec2 sampleCoord; \n"
-// "uniform sampler2D _qt_texture; \n"
-// "uniform lowp vec4 color; \n"
-// "uniform highp float alphaMin; \n"
-// "uniform highp float alphaMax; \n"
-// "void main() { \n"
-// " highp vec2 delta = dFdx(sampleCoord); \n"
-// " highp vec4 n; \n"
-// " n.x = texture2D(_qt_texture, sampleCoord - 0.667 * delta).a; \n"
-// " n.y = texture2D(_qt_texture, sampleCoord - 0.333 * delta).a; \n"
-// " highp float c = texture2D(_qt_texture, sampleCoord).a; \n"
-// " n.z = texture2D(_qt_texture, sampleCoord + 0.333 * delta).a; \n"
-// " n.w = texture2D(_qt_texture, sampleCoord + 0.667 * delta).a; \n"
-// " n = smoothstep(alphaMin, alphaMax, n); \n"
-// " c = smoothstep(alphaMin, alphaMax, c); \n"
-// " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
-// "}";
-//}
+QSGHiQSubPixelDistanceFieldTextMaterialShader::QSGHiQSubPixelDistanceFieldTextMaterialShader()
+ : QSGDistanceFieldTextMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag"));
+}
void QSGHiQSubPixelDistanceFieldTextMaterialShader::initialize()
{
@@ -712,52 +557,15 @@ QSGMaterialShader *QSGHiQSubPixelDistanceFieldTextMaterial::createShader() const
class QSGLoQSubPixelDistanceFieldTextMaterialShader : public QSGHiQSubPixelDistanceFieldTextMaterialShader
{
-protected:
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
+public:
+ QSGLoQSubPixelDistanceFieldTextMaterialShader();
};
-const char *QSGLoQSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "uniform highp float fontScale; \n"
- "uniform highp vec4 vecDelta; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec3 sampleNearLeft; \n"
- "varying highp vec3 sampleNearRight; \n"
- "void main() { \n"
- " highp vec2 sampleCoord = tCoord * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- // Calculate neighbour pixel position in item space.
- " highp vec3 wDelta = gl_Position.w * vecDelta.xyw; \n"
- " highp vec3 nearLeft = vCoord.xyw - 0.25 * wDelta; \n"
- " highp vec3 nearRight = vCoord.xyw + 0.25 * wDelta; \n"
- // Calculate neighbour texture coordinate.
- " highp vec2 scale = textureScale / fontScale; \n"
- " highp vec2 base = sampleCoord - scale * vCoord.xy; \n"
- " sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
- " sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
- "}";
-}
-
-const char *QSGLoQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec3 sampleNearLeft; \n"
- "varying highp vec3 sampleNearRight; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " highp vec2 n; \n"
- " n.x = texture2DProj(_qt_texture, sampleNearLeft).a; \n"
- " n.y = texture2DProj(_qt_texture, sampleNearRight).a; \n"
- " n = smoothstep(alphaMin, alphaMax, n); \n"
- " highp float c = 0.5 * (n.x + n.y); \n"
- " gl_FragColor = vec4(n.x, c, n.y, c) * color.w; \n"
- "}";
+QSGLoQSubPixelDistanceFieldTextMaterialShader::QSGLoQSubPixelDistanceFieldTextMaterialShader()
+ : QSGHiQSubPixelDistanceFieldTextMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/loqsubpixeldistancefieldtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/loqsubpixeldistancefieldtext.frag"));
}
QSGMaterialType *QSGLoQSubPixelDistanceFieldTextMaterial::type() const
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
index 2558413675..98a65d7347 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -49,13 +49,13 @@
QT_BEGIN_NAMESPACE
-class QSGContext;
+class QSGRenderContext;
class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldTextMaterial;
class QSGDistanceFieldGlyphNode: public QSGGlyphNode, public QSGDistanceFieldGlyphConsumer
{
public:
- QSGDistanceFieldGlyphNode(QSGContext *context);
+ QSGDistanceFieldGlyphNode(QSGRenderContext *context);
~QSGDistanceFieldGlyphNode();
virtual QPointF baseLine() const { return m_baseLine; }
@@ -86,7 +86,7 @@ private:
DistanceFieldGlyphNodeType m_glyphNodeType;
QColor m_color;
QPointF m_baseLine;
- QSGContext *m_context;
+ QSGRenderContext *m_context;
QSGDistanceFieldTextMaterial *m_material;
QPointF m_originalPosition;
QPointF m_position;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
index cf0d2d525e..d56fd01d3e 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -117,6 +117,7 @@ public:
virtual QSGMaterialType *type() const;
virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
void setShift(const QPointF &shift) { m_shift = shift; }
const QPointF &shift() const { return m_shift; }
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 163d1d35c5..aa0d7b5a6c 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -87,13 +87,13 @@ class QSGGuiThreadRenderLoop : public QSGRenderLoop
Q_OBJECT
public:
QSGGuiThreadRenderLoop();
+ ~QSGGuiThreadRenderLoop();
void show(QQuickWindow *window);
void hide(QQuickWindow *window);
void windowDestroyed(QQuickWindow *window);
- void initializeGL();
void renderWindow(QQuickWindow *window);
void exposureChanged(QQuickWindow *window);
QImage grab(QQuickWindow *window);
@@ -106,6 +106,7 @@ public:
QAnimationDriver *animationDriver() const { return 0; }
QSGContext *sceneGraphContext() const;
+ QSGRenderContext *createRenderContext(QSGContext *) const { return rc; }
bool event(QEvent *);
@@ -118,6 +119,7 @@ public:
QOpenGLContext *gl;
QSGContext *sg;
+ QSGRenderContext *rc;
QImage grabContent;
@@ -140,11 +142,15 @@ bool QSGRenderLoop::useConsistentTiming()
QSGRenderLoop *QSGRenderLoop::instance()
{
if (!s_instance) {
-
s_instance = QSGContext::createWindowManager();
- if (useConsistentTiming())
+ bool info = qEnvironmentVariableIsSet("QSG_INFO");
+
+ if (useConsistentTiming()) {
QUnifiedTimer::instance(true)->setConsistentTiming(true);
+ if (info)
+ qDebug() << "QSG: using fixed animation steps";
+ }
if (!s_instance) {
@@ -177,12 +183,15 @@ QSGRenderLoop *QSGRenderLoop::instance()
switch (loopType) {
case ThreadedRenderLoop:
+ if (info) qDebug() << "QSG: threaded render loop";
s_instance = new QSGThreadedRenderLoop();
break;
case WindowsRenderLoop:
+ if (info) qDebug() << "QSG: windows render loop";
s_instance = new QSGWindowsRenderLoop();
break;
default:
+ if (info) qDebug() << "QSG: basic render loop";
s_instance = new QSGGuiThreadRenderLoop();
break;
}
@@ -202,8 +211,14 @@ QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop()
, eventPending(false)
{
sg = QSGContext::createDefaultContext();
+ rc = new QSGRenderContext(sg);
}
+QSGGuiThreadRenderLoop::~QSGGuiThreadRenderLoop()
+{
+ delete rc;
+ delete sg;
+}
void QSGGuiThreadRenderLoop::show(QQuickWindow *window)
{
@@ -226,7 +241,8 @@ void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
if (m_windows.size() == 0) {
if (!cd->persistentSceneGraph) {
- sg->invalidate();
+ rc->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
if (!cd->persistentGLContext) {
delete gl;
gl = 0;
@@ -239,7 +255,8 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
{
hide(window);
if (m_windows.size() == 0) {
- sg->invalidate();
+ rc->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete gl;
gl = 0;
}
@@ -257,14 +274,17 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (!gl) {
gl = new QOpenGLContext();
gl->setFormat(window->requestedFormat());
+ if (QSGContext::sharedOpenGLContext())
+ gl->setShareContext(QSGContext::sharedOpenGLContext());
if (!gl->create()) {
+ qWarning("QtQuick: failed to create OpenGL context");
delete gl;
gl = 0;
} else {
current = gl->makeCurrent(window);
}
if (current)
- sg->initialize(gl);
+ QQuickWindowPrivate::get(window)->context->initialize(gl);
} else {
current = gl->makeCurrent(window);
}
diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h
index 933a8428f1..72bad16c63 100644
--- a/src/quick/scenegraph/qsgrenderloop_p.h
+++ b/src/quick/scenegraph/qsgrenderloop_p.h
@@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
class QQuickWindow;
class QSGContext;
+class QSGRenderContext;
class QAnimationDriver;
class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop : public QObject
@@ -60,6 +61,7 @@ public:
virtual void show(QQuickWindow *window) = 0;
virtual void hide(QQuickWindow *window) = 0;
+ virtual void resize(QQuickWindow *) {};
virtual void windowDestroyed(QQuickWindow *window) = 0;
@@ -72,6 +74,7 @@ public:
virtual QAnimationDriver *animationDriver() const = 0;
virtual QSGContext *sceneGraphContext() const = 0;
+ virtual QSGRenderContext *createRenderContext(QSGContext *) const = 0;
virtual void releaseResources(QQuickWindow *window) = 0;
diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
index 34a884348d..cc0218aefd 100644
--- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
@@ -228,6 +228,7 @@ QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteAr
this, SLOT(reportItemsInvalidated(QByteArray,QVector<quint32>)),
Qt::DirectConnection);
+ Q_ASSERT(c);
QQuickWindow *window = static_cast<QQuickWindow *>(c->surface());
Q_ASSERT(window != 0);
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 7421db1db1..850a463c3e 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -84,6 +84,17 @@
---
+ There is one thread per window and one opengl context per thread.
+
+ ---
+
+ The render thread has affinity to the GUI thread until a window
+ is shown. From that moment and until the window is destroyed, it
+ will have affinity to the render thread. (moved back at the end
+ of run for cleanup).
+
+ ---
+
The render loop is active while any window is exposed. All visible
windows are tracked, but only exposed windows are actually added to
the render thread and rendered. That means that if all windows are
@@ -97,26 +108,14 @@ QT_BEGIN_NAMESPACE
// #define QSG_RENDER_LOOP_DEBUG
-// #define QSG_RENDER_LOOP_DEBUG_FULL
-#ifdef QSG_RENDER_LOOP_DEBUG
-#define QSG_RENDER_LOOP_DEBUG_BASIC
-#endif
-
-#ifdef QSG_RENDER_LOOP_DEBUG_FULL
-#define QSG_RENDER_LOOP_DEBUG_BASIC
-#endif
-#if defined (QSG_RENDER_LOOP_DEBUG_FULL)
+#if defined (QSG_RENDER_LOOP_DEBUG)
QElapsedTimer qsgrl_timer;
-# define RLDEBUG1(x) qDebug("(%6d) %s : %4d - %s", (int) qsgrl_timer.elapsed(), __FILE__, __LINE__, x);
-# define RLDEBUG(x) qDebug("(%6d) %s : %4d - %s", (int) qsgrl_timer.elapsed(), __FILE__, __LINE__, x);
-#elif defined (QSG_RENDER_LOOP_DEBUG_BASIC)
-QElapsedTimer qsgrl_timer;
-# define RLDEBUG1(x) qDebug("(%6d) %s : %4d - %s", (int) qsgrl_timer.elapsed(), __FILE__, __LINE__, x);
-# define RLDEBUG(x)
+# define QSG_RT_DEBUG(MSG) qDebug("(%6d) line=%4d - win=%10p): Render: %s", (int) qsgrl_timer.elapsed(), __LINE__, window, MSG);
+# define QSG_GUI_DEBUG(WIN, MSG) qDebug("(%6d) line=%4d - win=%10p): Gui: %s", (int) qsgrl_timer.elapsed(), __LINE__, WIN, MSG);
#else
-# define RLDEBUG1(x)
-# define RLDEBUG(x)
+# define QSG_RT_DEBUG(MSG)
+# define QSG_GUI_DEBUG(WIN,MSG)
#endif
@@ -276,23 +275,25 @@ class QSGRenderThread : public QThread
{
Q_OBJECT
public:
-
- QSGRenderThread(QSGThreadedRenderLoop *w)
+ QSGRenderThread(QSGThreadedRenderLoop *w, QSGRenderContext *renderContext)
: wm(w)
, gl(0)
- , sg(QSGContext::createDefaultContext())
+ , sgrc(renderContext)
, animatorDriver(0)
, pendingUpdate(0)
, sleeping(false)
, syncResultedInChanges(false)
- , guiIsLocked(false)
- , shouldExit(false)
+ , active(false)
+ , window(0)
, stopEventProcessing(false)
{
- sg->moveToThread(this);
vsyncDelta = qsgrl_animation_interval();
}
+ ~QSGRenderThread()
+ {
+ delete sgrc;
+ }
void invalidateOpenGL(QQuickWindow *window, bool inDestructor);
void initializeOpenGL();
@@ -307,7 +308,7 @@ public:
{
if (sleeping)
stopEventProcessing = true;
- if (m_windows.size() > 0)
+ if (window)
pendingUpdate |= RepaintRequest;
}
@@ -317,7 +318,7 @@ public:
public slots:
void sceneGraphChanged() {
- RLDEBUG(" Render: sceneGraphChanged()");
+ QSG_RT_DEBUG("sceneGraphChanged()");
syncResultedInChanges = true;
}
@@ -329,16 +330,15 @@ public:
QSGThreadedRenderLoop *wm;
QOpenGLContext *gl;
- QSGContext *sg;
+ QSGRenderContext *sgrc;
QAnimationDriver *animatorDriver;
uint pendingUpdate;
- uint sleeping;
- uint syncResultedInChanges;
+ bool sleeping;
+ bool syncResultedInChanges;
- volatile bool guiIsLocked;
- volatile bool shouldExit;
+ volatile bool active;
float vsyncDelta;
@@ -347,11 +347,8 @@ public:
QElapsedTimer m_timer;
- struct Window {
- QQuickWindow *window;
- QSize size;
- };
- QList<Window> m_windows;
+ QQuickWindow *window; // Will be 0 when window is not exposed
+ QSize windowSize;
// Local event queue stuff...
bool stopEventProcessing;
@@ -363,64 +360,57 @@ bool QSGRenderThread::event(QEvent *e)
switch ((int) e->type()) {
case WM_Expose: {
- RLDEBUG1(" Render: WM_Expose");
+ QSG_RT_DEBUG("WM_Expose");
WMExposeEvent *se = static_cast<WMExposeEvent *>(e);
pendingUpdate |= RepaintRequest;
- if (Window *w = windowFor(m_windows, se->window)) {
- w->size = se->size;
- RLDEBUG1(" Render: - window already added...");
+ Q_ASSERT(!window || window == se->window);
+
+ windowSize = se->size;
+ if (window) {
+ QSG_RT_DEBUG(" - window already added...");
return true;
}
- Window window;
- window.window = se->window;
- window.size = se->size;
- m_windows << window;
- connect(animatorDriver, SIGNAL(started()), QQuickWindowPrivate::get(se->window)->animationController, SLOT(animationsStarted()));
+ window = se->window;
return true; }
case WM_Obscure: {
- RLDEBUG1(" Render: WM_Obscure");
- WMWindowEvent *ce = static_cast<WMWindowEvent *>(e);
- for (int i=0; i<m_windows.size(); ++i) {
- if (m_windows.at(i).window == ce->window) {
- RLDEBUG1(" Render: - removed one...");
- m_windows.removeAt(i);
- disconnect(animatorDriver, SIGNAL(started()), QQuickWindowPrivate::get(ce->window)->animationController, SLOT(animationsStarted()));
- break;
- }
- }
+ QSG_RT_DEBUG("WM_Obscure");
- if (sleeping && m_windows.size())
- stopEventProcessing = true;
+ Q_ASSERT(!window || window == static_cast<WMWindowEvent *>(e)->window);
+
+ mutex.lock();
+ if (window) {
+ QSG_RT_DEBUG(" - removed one...");
+ window = 0;
+ }
+ waitCondition.wakeOne();
+ mutex.unlock();
return true; }
case WM_RequestSync:
- RLDEBUG(" Render: WM_RequestSync");
+ QSG_RT_DEBUG("WM_RequestSync");
if (sleeping)
stopEventProcessing = true;
- if (m_windows.size() > 0)
+ if (window)
pendingUpdate |= SyncRequest;
return true;
case WM_TryRelease: {
- RLDEBUG1(" Render: WM_TryRelease");
+ QSG_RT_DEBUG("WM_TryRelease");
mutex.lock();
WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
- if (m_windows.size() == 0) {
- RLDEBUG1(" Render: - setting exit flag and invalidating GL");
+ if (!window || wme->inDestructor) {
+ QSG_RT_DEBUG(" - setting exit flag and invalidating GL");
invalidateOpenGL(wme->window, wme->inDestructor);
- shouldExit = !gl;
+ active = gl;
if (sleeping)
stopEventProcessing = true;
- } else if (wme->window == gl->surface()) {
- RLDEBUG1(" Render: - destroying the current window. Calling doneCurrent()...");
- gl->doneCurrent();
} else {
- RLDEBUG1(" Render: - not releasing anything because we have active windows...");
+ QSG_RT_DEBUG(" - not releasing anything because we have active windows...");
}
waitCondition.wakeOne();
mutex.unlock();
@@ -428,24 +418,24 @@ bool QSGRenderThread::event(QEvent *e)
}
case WM_Grab: {
- RLDEBUG1(" Render: WM_Grab");
+ QSG_RT_DEBUG("WM_Grab");
WMGrabEvent *ce = static_cast<WMGrabEvent *>(e);
- Window *w = windowFor(m_windows, ce->window);
+ Q_ASSERT(ce->window == window);
mutex.lock();
- if (w) {
- gl->makeCurrent(ce->window);
+ if (window) {
+ gl->makeCurrent(window);
- RLDEBUG1(" Render: - syncing scene graph");
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w->window);
+ QSG_RT_DEBUG(" - syncing scene graph");
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
d->syncSceneGraph();
- RLDEBUG1(" Render: - rendering scene graph");
- QQuickWindowPrivate::get(ce->window)->renderSceneGraph(w->size);
+ QSG_RT_DEBUG(" - rendering scene graph");
+ QQuickWindowPrivate::get(window)->renderSceneGraph(windowSize);
- RLDEBUG1(" Render: - grabbing result...");
- *ce->image = qt_gl_read_framebuffer(w->size, false, false);
+ QSG_RT_DEBUG(" - grabbing result...");
+ *ce->image = qt_gl_read_framebuffer(windowSize, false, false);
}
- RLDEBUG1(" Render: - waking gui to handle grab result");
+ QSG_RT_DEBUG(" - waking gui to handle grab result");
waitCondition.wakeOne();
mutex.unlock();
return true;
@@ -465,7 +455,7 @@ bool QSGRenderThread::event(QEvent *e)
void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
{
- RLDEBUG1(" Render: invalidateOpenGL()");
+ QSG_RT_DEBUG("invalidateOpenGL()");
if (!gl)
return;
@@ -476,43 +466,32 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
}
- bool persistentGL = false;
- bool persistentSG = false;
-
- // GUI is locked so accessing the wm and window here is safe
- for (int i=0; i<wm->m_windows.size(); ++i) {
- const QSGThreadedRenderLoop::Window &w = wm->m_windows.at(i);
- if (!inDestructor || w.window != window) {
- persistentSG |= w.window->isPersistentSceneGraph();
- persistentGL |= w.window->isPersistentOpenGLContext();
- }
- }
+ bool wipeSG = inDestructor || !window->isPersistentSceneGraph();
+ bool wipeGL = inDestructor || (wipeSG && !window->isPersistentOpenGLContext());
gl->makeCurrent(window);
- // The canvas nodes must be cleanded up regardless if we are in the destructor..
- if (!persistentSG || inDestructor) {
+ // The canvas nodes must be cleaned up regardless if we are in the destructor..
+ if (wipeSG) {
QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window);
dd->cleanupNodesOnShutdown();
- }
-
- // We're not doing any cleanup in this case...
- if (persistentSG) {
- RLDEBUG1(" Render: - persistent SG, avoiding cleanup");
+ } else {
+ QSG_RT_DEBUG(" - persistent SG, avoiding cleanup");
return;
}
- sg->invalidate();
+ sgrc->invalidate();
+ QCoreApplication::processEvents();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
gl->doneCurrent();
- RLDEBUG1(" Render: - invalidated scenegraph..");
+ QSG_RT_DEBUG(" - invalidated scenegraph..");
- if (!persistentGL) {
+ if (wipeGL) {
delete gl;
gl = 0;
- RLDEBUG1(" Render: - invalidated OpenGL");
+ QSG_RT_DEBUG(" - invalidated OpenGL");
} else {
- RLDEBUG1(" Render: - persistent GL, avoiding cleanup");
+ QSG_RT_DEBUG(" - persistent GL, avoiding cleanup");
}
}
@@ -522,32 +501,34 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
*/
void QSGRenderThread::sync()
{
- RLDEBUG(" Render: sync()");
+ QSG_RT_DEBUG("sync()");
mutex.lock();
- Q_ASSERT_X(guiIsLocked, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked...");
+ Q_ASSERT_X(wm->m_locked, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked...");
- for (int i=0; i<m_windows.size(); ++i) {
- Window &w = const_cast<Window &>(m_windows.at(i));
- if (w.size.width() == 0 || w.size.height() == 0) {
- RLDEBUG(" Render: - window has bad size, waiting...");
- continue;
- }
- gl->makeCurrent(w.window);
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w.window);
+ bool current = false;
+ if (windowSize.width() > 0 && windowSize.height() > 0)
+ current = gl->makeCurrent(window);
+ if (current) {
+ gl->makeCurrent(window);
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool hadRenderer = d->renderer != 0;
d->syncSceneGraph();
if (!hadRenderer && d->renderer) {
- RLDEBUG(" Render: - renderer was created, hooking up changed signal");
+ QSG_RT_DEBUG(" - renderer was created, hooking up changed signal");
syncResultedInChanges = true;
connect(d->renderer, SIGNAL(sceneGraphChanged()), this, SLOT(sceneGraphChanged()), Qt::DirectConnection);
}
- }
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
-
- RLDEBUG(" Render: - unlocking after sync");
+ // Process deferred deletes now, directly after the sync as
+ // deleteLater on the GUI must now also have resulted in SG changes
+ // and the delete is a safe operation.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ } else {
+ QSG_RT_DEBUG(" - window has bad size, waiting...");
+ }
+ QSG_RT_DEBUG(" - window has bad size, waiting...");
waitCondition.wakeOne();
mutex.unlock();
}
@@ -565,7 +546,7 @@ void QSGRenderThread::syncAndRender()
QElapsedTimer waitTimer;
waitTimer.start();
- RLDEBUG(" Render: syncAndRender()");
+ QSG_RT_DEBUG("syncAndRender()");
syncResultedInChanges = false;
@@ -574,16 +555,15 @@ void QSGRenderThread::syncAndRender()
pendingUpdate = 0;
if (syncRequested) {
- RLDEBUG(" Render: - update pending, doing sync");
+ QSG_RT_DEBUG(" - update pending, doing sync");
sync();
}
if (!syncResultedInChanges && !(repaintRequested)) {
- RLDEBUG(" Render: - no changes, rendering aborted");
+ QSG_RT_DEBUG(" - no changes, rendering aborted");
int waitTime = vsyncDelta - (int) waitTimer.elapsed();
if (waitTime > 0)
msleep(waitTime);
- emit wm->timeToIncubate();
return;
}
@@ -591,33 +571,37 @@ void QSGRenderThread::syncAndRender()
if (profileFrames)
syncTime = threadTimer.nsecsElapsed();
#endif
- RLDEBUG(" Render: - rendering starting");
+ QSG_RT_DEBUG(" - rendering starting");
+
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
- if (animatorDriver->isRunning())
+ if (animatorDriver->isRunning()) {
+ d->animationController->lock();
animatorDriver->advance();
+ d->animationController->unlock();
+ }
- for (int i=0; i<m_windows.size(); ++i) {
- Window &w = const_cast<Window &>(m_windows.at(i));
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w.window);
- if (!d->renderer || w.size.width() == 0 || w.size.height() == 0) {
- RLDEBUG(" Render: - Window not yet ready, skipping render...");
- continue;
- }
- gl->makeCurrent(w.window);
- d->renderSceneGraph(w.size);
+ bool current = false;
+ if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0)
+ current = gl->makeCurrent(window);
+ if (current) {
+ d->renderSceneGraph(windowSize);
#ifndef QSG_NO_RENDER_TIMING
- if (profileFrames && i == 0)
+ if (profileFrames)
renderTime = threadTimer.nsecsElapsed();
#endif
- gl->swapBuffers(w.window);
+ gl->swapBuffers(window);
d->fireFrameSwapped();
+ } else {
+ QSG_RT_DEBUG(" - Window not yet ready, skipping render...");
}
- RLDEBUG(" Render: - rendering done");
- emit wm->timeToIncubate();
+
+ QSG_RT_DEBUG(" - rendering done");
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing)
- qDebug("Render Thread: framedelta=%d, sync=%d, first render=%d, after final swap=%d",
+ qDebug("Render Thread: window=%p, framedelta=%d, sync=%d, first render=%d, after final swap=%d",
+ window,
int(sinceLastTime/1000000),
int(syncTime/1000000),
int((renderTime - syncTime)/1000000),
@@ -644,78 +628,73 @@ void QSGRenderThread::postEvent(QEvent *e)
void QSGRenderThread::processEvents()
{
- RLDEBUG(" Render: processEvents()");
+ QSG_RT_DEBUG("processEvents()");
while (eventQueue.hasMoreEvents()) {
QEvent *e = eventQueue.takeEvent(false);
event(e);
delete e;
}
- RLDEBUG(" Render: - done with processEvents()");
+ QSG_RT_DEBUG(" - done with processEvents()");
}
void QSGRenderThread::processEventsAndWaitForMore()
{
- RLDEBUG(" Render: processEventsAndWaitForMore()");
+ QSG_RT_DEBUG("processEventsAndWaitForMore()");
stopEventProcessing = false;
while (!stopEventProcessing) {
QEvent *e = eventQueue.takeEvent(true);
event(e);
delete e;
}
- RLDEBUG(" Render: - done with processEventsAndWaitForMore()");
+ QSG_RT_DEBUG(" - done with processEventsAndWaitForMore()");
}
void QSGRenderThread::run()
{
- RLDEBUG1(" Render: run()");
- animatorDriver = sg->createAnimationDriver(0);
+ QSG_RT_DEBUG("run()");
+ animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0);
animatorDriver->install();
QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming());
- while (!shouldExit) {
+ while (active) {
- if (m_windows.size() > 0) {
- if (!sg->isReady()) {
- gl->makeCurrent(m_windows.at(0).window);
- sg->initialize(gl);
- }
+ if (window) {
+ if (!sgrc->openglContext() && windowSize.width() > 0 && windowSize.height() > 0 && gl->makeCurrent(window))
+ sgrc->initialize(gl);
syncAndRender();
}
processEvents();
QCoreApplication::processEvents();
- if (!shouldExit
- && (pendingUpdate == 0 || m_windows.size() == 0)) {
- RLDEBUG(" Render: enter event loop (going to sleep)");
+ if (active && (pendingUpdate == 0 || !window)) {
+ QSG_RT_DEBUG("enter event loop (going to sleep)");
sleeping = true;
processEventsAndWaitForMore();
sleeping = false;
}
-
}
Q_ASSERT_X(!gl, "QSGRenderThread::run()", "The OpenGL context should be cleaned up before exiting the render thread...");
- RLDEBUG1(" Render: run() completed...");
+ QSG_RT_DEBUG("run() completed...");
delete animatorDriver;
animatorDriver = 0;
+
+ sgrc->moveToThread(wm->thread());
+ moveToThread(wm->thread());
}
QSGThreadedRenderLoop::QSGThreadedRenderLoop()
- : m_animation_timer(0)
- , m_update_timer(0)
- , m_sync_triggered_update(false)
+ : sg(QSGContext::createDefaultContext())
+ , m_animation_timer(0)
{
#if defined(QSG_RENDER_LOOP_DEBUG_BASIC) || defined (QSG_RENDER_LOOP_DEBUG_FULL)
qsgrl_timer.start();
#endif
- m_thread = new QSGRenderThread(this);
- m_thread->moveToThread(m_thread);
-
- m_animation_driver = m_thread->sg->createAnimationDriver(this);
+ m_animation_driver = sg->createAnimationDriver(this);
m_exhaust_delay = get_env_int("QML_EXHAUST_DELAY", 5);
@@ -723,14 +702,19 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop()
connect(m_animation_driver, SIGNAL(stopped()), this, SLOT(animationStopped()));
m_animation_driver->install();
- RLDEBUG1("GUI: QSGThreadedRenderLoop() created");
+ QSG_GUI_DEBUG((void *) 0, "QSGThreadedRenderLoop() created");
+}
+
+QSGRenderContext *QSGThreadedRenderLoop::createRenderContext(QSGContext *sg) const
+{
+ return new QSGRenderContext(sg);
}
-void QSGThreadedRenderLoop::maybePostPolishRequest()
+void QSGThreadedRenderLoop::maybePostPolishRequest(Window *w)
{
- if (m_update_timer == 0) {
- RLDEBUG("GUI: - posting update");
- m_update_timer = startTimer(m_exhaust_delay, Qt::PreciseTimer);
+ if (w->timerId == 0) {
+ QSG_GUI_DEBUG(w->window, " - posting update");
+ w->timerId = startTimer(m_exhaust_delay, Qt::PreciseTimer);
}
}
@@ -741,7 +725,7 @@ QAnimationDriver *QSGThreadedRenderLoop::animationDriver() const
QSGContext *QSGThreadedRenderLoop::sceneGraphContext() const
{
- return m_thread->sg;
+ return sg;
}
bool QSGThreadedRenderLoop::anyoneShowing() const
@@ -761,35 +745,79 @@ bool QSGThreadedRenderLoop::interleaveIncubation() const
void QSGThreadedRenderLoop::animationStarted()
{
- RLDEBUG("GUI: animationStarted()");
- if (!anyoneShowing() && m_animation_timer == 0)
- m_animation_timer = startTimer(qsgrl_animation_interval());
- maybePostPolishRequest();
+ QSG_GUI_DEBUG((void *) 0, "animationStarted()");
+ startOrStopAnimationTimer();
+
+ for (int i=0; i<m_windows.size(); ++i)
+ maybePostPolishRequest(const_cast<Window *>(&m_windows.at(i)));
}
void QSGThreadedRenderLoop::animationStopped()
{
- RLDEBUG("GUI: animationStopped()");
- if (!anyoneShowing()) {
+ QSG_GUI_DEBUG((void *) 0, "animationStopped()");
+ startOrStopAnimationTimer();
+}
+
+
+void QSGThreadedRenderLoop::startOrStopAnimationTimer()
+{
+ int exposedWindows = 0;
+ Window *theOne = 0;
+ for (int i=0; i<m_windows.size(); ++i) {
+ Window &w = m_windows[i];
+ if (w.window->isVisible() && w.window->isExposed()) {
+ ++exposedWindows;
+ theOne = &w;
+ }
+ }
+
+ if (m_animation_timer != 0 && (exposedWindows == 1 || !m_animation_driver->isRunning())) {
killTimer(m_animation_timer);
m_animation_timer = 0;
+ // If animations are running, make sure we keep on animating
+ if (m_animation_driver->isRunning())
+ maybePostPolishRequest(theOne);
+
+ } else if (m_animation_timer == 0 && exposedWindows != 1 && m_animation_driver->isRunning()) {
+ m_animation_timer = startTimer(qsgrl_animation_interval());
}
}
-
-
/*
- Adds this window to the list of tracked windowes in this window
+ Adds this window to the list of tracked windows in this window
manager. show() does not trigger rendering to start, that happens
in expose.
*/
void QSGThreadedRenderLoop::show(QQuickWindow *window)
{
- RLDEBUG1("GUI: show()");
+ QSG_GUI_DEBUG(window, "show()");
+
+ if (Window *w = windowFor(m_windows, window)) {
+ /* Safeguard ourselves against misbehaving platform plugins.
+ *
+ * When being shown, the window should not be exposed as the
+ * platform plugin is only told to show after we send the show
+ * event. If we are already shown at this time and we don't have
+ * an active rendering thread we don't trust the plugin to send
+ * us another expose event, so make this explicit call to
+ * handleExposure.
+ *
+ * REF: QTCREATORBUG-10699
+ */
+ if (window->isExposed() && (!w->thread || !w->thread->window))
+ handleExposure(w);
+ return;
+ }
+
+ QSG_GUI_DEBUG(window, " - now tracking new window");
Window win;
win.window = window;
+ win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
+ win.timerId = 0;
+ win.updateDuringSync = false;
+ win.gotBrokenExposeFromPlatformPlugin = false;
m_windows << win;
}
@@ -803,19 +831,12 @@ void QSGThreadedRenderLoop::show(QQuickWindow *window)
void QSGThreadedRenderLoop::hide(QQuickWindow *window)
{
- RLDEBUG1("GUI: hide()");
+ QSG_GUI_DEBUG(window, "hide()");
if (window->isExposed())
- handleObscurity(window);
+ handleObscurity(windowFor(m_windows, window));
releaseResources(window);
-
- for (int i=0; i<m_windows.size(); ++i) {
- if (m_windows.at(i).window == window) {
- m_windows.removeAt(i);
- break;
- }
- }
}
@@ -826,26 +847,51 @@ void QSGThreadedRenderLoop::hide(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::windowDestroyed(QQuickWindow *window)
{
- RLDEBUG1("GUI: windowDestroyed()");
+ QSG_GUI_DEBUG(window, "windowDestroyed()");
if (window->isVisible())
hide(window);
releaseResources(window, true);
- RLDEBUG1("GUI: - done with windowDestroyed()");
+ for (int i=0; i<m_windows.size(); ++i) {
+ if (m_windows.at(i).window == window) {
+ QSGRenderThread *thread = m_windows.at(i).thread;
+ while (thread->isRunning())
+ QThread::yieldCurrentThread();
+ Q_ASSERT(thread->thread() == QThread::currentThread());
+ delete thread;
+ m_windows.removeAt(i);
+ break;
+ }
+ }
+
+ QSG_GUI_DEBUG(window, " - done with windowDestroyed()");
}
void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window)
{
- RLDEBUG1("GUI: exposureChanged()");
- if (windowFor(m_windows, window) == 0)
+ QSG_GUI_DEBUG(window, "exposureChanged()");
+ Window *w = windowFor(m_windows, window);
+ if (!w)
return;
if (window->isExposed()) {
- handleExposure(window);
+ handleExposure(w);
} else {
- handleObscurity(window);
+ handleObscurity(w);
+ }
+}
+
+void QSGThreadedRenderLoop::resize(QQuickWindow *window)
+{
+ Window *w = windowFor(m_windows, window);
+ if (w
+ && w->gotBrokenExposeFromPlatformPlugin
+ && window->width() > 0 && window->height() > 0
+ && w->window->geometry().intersects(w->window->screen()->availableGeometry())) {
+ w->gotBrokenExposeFromPlatformPlugin = false;
+ handleExposure(w);
}
}
@@ -854,49 +900,64 @@ void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window)
Will post an event to the render thread that this window should
start to render.
*/
-void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
+void QSGThreadedRenderLoop::handleExposure(Window *w)
{
- RLDEBUG1("GUI: handleExposure");
+ QSG_GUI_DEBUG(w->window, "handleExposure");
+
+ if (w->window->width() <= 0 || w->window->height() <= 0
+ || !w->window->geometry().intersects(w->window->screen()->availableGeometry())) {
+#ifndef QT_NO_DEBUG
+ qWarning("QSGThreadedRenderLoop: expose event received for window with invalid geometry.");
+#endif
+ w->gotBrokenExposeFromPlatformPlugin = true;
+ return;
+ }
// Because we are going to bind a GL context to it, make sure it
// is created.
- if (!window->handle())
- window->create();
-
- m_thread->postEvent(new WMExposeEvent(window));
+ if (!w->window->handle())
+ w->window->create();
// Start render thread if it is not running
- if (!m_thread->isRunning()) {
- m_thread->shouldExit = false;
-
- RLDEBUG1("GUI: - starting render thread...");
+ if (!w->thread->isRunning()) {
+
+ QSG_GUI_DEBUG(w->window, " - starting render thread...");
+
+ if (!w->thread->gl) {
+ w->thread->gl = new QOpenGLContext();
+ if (QSGContext::sharedOpenGLContext())
+ w->thread->gl->setShareContext(QSGContext::sharedOpenGLContext());
+ w->thread->gl->setFormat(w->window->requestedFormat());
+ if (!w->thread->gl->create()) {
+ delete w->thread->gl;
+ w->thread->gl = 0;
+ qWarning("QtQuick: failed to create OpenGL context");
+ return;
+ }
- if (!m_thread->gl) {
- QOpenGLContext *ctx = new QOpenGLContext();
- ctx->setFormat(window->requestedFormat());
- ctx->create();
- ctx->moveToThread(m_thread);
- m_thread->gl = ctx;
+ w->thread->gl->moveToThread(w->thread);
+ QSG_GUI_DEBUG(w->window, " - OpenGL context created...");
}
- QQuickAnimatorController *controller = QQuickWindowPrivate::get(window)->animationController;
- if (controller->thread() != m_thread)
- controller->moveToThread(m_thread);
+ QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController;
+ if (controller->thread() != w->thread)
+ controller->moveToThread(w->thread);
- m_thread->start();
+ w->thread->active = true;
+ if (w->thread->thread() == QThread::currentThread()) {
+ w->thread->sgrc->moveToThread(w->thread);
+ w->thread->moveToThread(w->thread);
+ }
+ w->thread->start();
} else {
- RLDEBUG1("GUI: - render thread already running");
+ QSG_GUI_DEBUG(w->window, " - render thread already running");
}
- polishAndSync();
-
- // Kill non-visual animation timer if it is running
- if (m_animation_timer) {
- killTimer(m_animation_timer);
- m_animation_timer = 0;
- }
+ w->thread->postEvent(new WMExposeEvent(w->window));
+ polishAndSync(w);
+ startOrStopAnimationTimer();
}
/*!
@@ -906,43 +967,51 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
It also starts up the non-vsync animation tick if no more windows
are showing.
*/
-void QSGThreadedRenderLoop::handleObscurity(QQuickWindow *window)
+void QSGThreadedRenderLoop::handleObscurity(Window *w)
{
- RLDEBUG1("GUI: handleObscurity");
- if (m_thread->isRunning())
- m_thread->postEvent(new WMWindowEvent(window, WM_Obscure));
-
- if (!anyoneShowing() && m_animation_driver->isRunning() && m_animation_timer == 0) {
- m_animation_timer = startTimer(qsgrl_animation_interval());
+ QSG_GUI_DEBUG(w->window, "handleObscurity");
+ if (w->thread->isRunning()) {
+ w->thread->mutex.lock();
+ w->thread->postEvent(new WMWindowEvent(w->window, WM_Obscure));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ w->thread->mutex.unlock();
}
+
+ startOrStopAnimationTimer();
}
+void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
+{
+ Window *w = windowFor(m_windows, window);
+ if (w)
+ maybeUpdate(w);
+}
+
/*!
Called whenever the QML scene has changed. Will post an event to
ourselves that a sync is needed.
*/
-void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
+void QSGThreadedRenderLoop::maybeUpdate(Window *w)
{
- Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || m_thread->guiIsLocked,
+ Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || m_locked,
"QQuickItem::update()",
"Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
- RLDEBUG("GUI: maybeUpdate...");
- Window *w = windowFor(m_windows, window);
- if (!w || !m_thread->isRunning()) {
+ QSG_GUI_DEBUG(w->window, "maybeUpdate...");
+ if (!w || !w->thread->isRunning()) {
return;
}
// Call this function from the Gui thread later as startTimer cannot be
// called from the render thread.
- if (QThread::currentThread() == m_thread) {
- RLDEBUG("GUI: - on render thread, will update later..");
- m_sync_triggered_update = true;
+ if (QThread::currentThread() == w->thread) {
+ QSG_GUI_DEBUG(w->window, " - on render thread, will update later..");
+ w->updateDuringSync = true;
return;
}
- maybePostPolishRequest();
+ maybePostPolishRequest(w);
}
/*!
@@ -952,15 +1021,19 @@ void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::update(QQuickWindow *window)
{
- if (QThread::currentThread() == m_thread) {
- RLDEBUG("Gui: update called on render thread");
- m_thread->requestRepaint();
+ Window *w = windowFor(m_windows, window);
+ if (!w)
+ return;
+
+ if (w->thread == QThread::currentThread()) {
+ QSG_RT_DEBUG("QQuickWindow::update called on render thread");
+ w->thread->requestRepaint();
return;
}
- RLDEBUG("Gui: update called");
- m_thread->postEvent(new QEvent(WM_RequestRepaint));
- maybeUpdate(window);
+ QSG_GUI_DEBUG(w->window, "update called");
+ w->thread->postEvent(new QEvent(WM_RequestRepaint));
+ maybeUpdate(w);
}
@@ -971,28 +1044,34 @@ void QSGThreadedRenderLoop::update(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window, bool inDestructor)
{
- RLDEBUG1("GUI: releaseResources requested...");
+ QSG_GUI_DEBUG(window, "releaseResources requested...");
+
+ Window *w = windowFor(m_windows, window);
+ if (!w)
+ return;
- m_thread->mutex.lock();
- if (m_thread->isRunning() && !m_thread->shouldExit) {
- RLDEBUG1("GUI: - posting release request to render thread");
- m_thread->postEvent(new WMTryReleaseEvent(window, inDestructor));
- m_thread->waitCondition.wait(&m_thread->mutex);
+ w->thread->mutex.lock();
+ if (w->thread->isRunning() && w->thread->active) {
+ QSG_GUI_DEBUG(w->window, " - posting release request to render thread");
+ w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor));
+ w->thread->waitCondition.wait(&w->thread->mutex);
}
- m_thread->mutex.unlock();
+ w->thread->mutex.unlock();
}
-void QSGThreadedRenderLoop::polishAndSync()
+void QSGThreadedRenderLoop::polishAndSync(Window *w)
{
- if (!anyoneShowing()) {
- killTimer(m_update_timer);
- m_update_timer = 0;
+ QSG_GUI_DEBUG(w->window, "polishAndSync()");
+
+ if (!w->window->isExposed() || !w->window->isVisible() || w->window->size().isEmpty()) {
+ QSG_GUI_DEBUG(w->window, " - not exposed, aborting...");
+ killTimer(w->timerId);
+ w->timerId = 0;
return;
}
- RLDEBUG("GUI: polishAndSync()");
#ifndef QSG_NO_RENDER_TIMING
QElapsedTimer timer;
@@ -1004,52 +1083,51 @@ void QSGThreadedRenderLoop::polishAndSync()
timer.start();
#endif
- // Polish as the last thing we do before we allow the sync to take place
- for (int i=0; i<m_windows.size(); ++i) {
- const Window &w = m_windows.at(i);
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w.window);
- d->polishItems();
- }
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(w->window);
+ d->polishItems();
+
#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
polishTime = timer.nsecsElapsed();
#endif
- m_sync_triggered_update = false;
+ w->updateDuringSync = false;
- RLDEBUG("GUI: - lock for sync...");
- m_thread->mutex.lock();
- m_thread->guiIsLocked = true;
- m_thread->postEvent(new QEvent(WM_RequestSync));
+ QSG_GUI_DEBUG(w->window, " - lock for sync...");
+ w->thread->mutex.lock();
+ m_locked = true;
+ w->thread->postEvent(new QEvent(WM_RequestSync));
- RLDEBUG("GUI: - wait for sync...");
+ QSG_GUI_DEBUG(w->window, " - wait for sync...");
#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
waitTime = timer.nsecsElapsed();
#endif
- m_thread->waitCondition.wait(&m_thread->mutex);
- m_thread->guiIsLocked = false;
- m_thread->mutex.unlock();
- RLDEBUG("GUI: - unlocked after sync...");
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ m_locked = false;
+ w->thread->mutex.unlock();
+ QSG_GUI_DEBUG(w->window, " - unlocked after sync...");
#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
syncTime = timer.nsecsElapsed();
#endif
- killTimer(m_update_timer);
- m_update_timer = 0;
+ killTimer(w->timerId);
+ w->timerId = 0;
- if (m_animation_driver->isRunning()) {
- RLDEBUG("GUI: - animations advancing");
+ if (m_animation_timer == 0 && m_animation_driver->isRunning()) {
+ QSG_GUI_DEBUG(w->window, " - animations advancing");
m_animation_driver->advance();
- RLDEBUG("GUI: - animations done");
+ QSG_GUI_DEBUG(w->window, " - animations done");
// We need to trigger another sync to keep animations running...
- maybePostPolishRequest();
- } else if (m_sync_triggered_update) {
- maybePostPolishRequest();
+ maybePostPolishRequest(w);
+ emit timeToIncubate();
+ } else if (w->updateDuringSync) {
+ maybePostPolishRequest(w);
}
+
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing)
qDebug(" - on GUI: polish=%d, lock=%d, block/sync=%d -- animations=%d",
@@ -1073,15 +1151,26 @@ bool QSGThreadedRenderLoop::event(QEvent *e)
{
switch ((int) e->type()) {
- case QEvent::Timer:
- if (static_cast<QTimerEvent *>(e)->timerId() == m_animation_timer) {
- RLDEBUG("GUI: QEvent::Timer -> non-visual animation");
+ case QEvent::Timer: {
+ QTimerEvent *te = static_cast<QTimerEvent *>(e);
+ if (te->timerId() == m_animation_timer) {
+ QSG_GUI_DEBUG((void *) 0, "QEvent::Timer -> non-visual animation");
m_animation_driver->advance();
- } else if (static_cast<QTimerEvent *>(e)->timerId() == m_update_timer) {
- RLDEBUG("GUI: QEvent::Timer -> Polish & Sync");
- polishAndSync();
+ emit timeToIncubate();
+ } else {
+ QSG_GUI_DEBUG((void *) 0, "QEvent::Timer -> Polish & Sync");
+ Window *w = 0;
+ for (int i=0; i<m_windows.size(); ++i) {
+ if (m_windows.at(i).timerId == te->timerId()) {
+ w = const_cast<Window *>(&m_windows.at(i));
+ break;
+ }
+ }
+ if (w)
+ polishAndSync(w);
}
return true;
+ }
default:
break;
@@ -1104,26 +1193,30 @@ bool QSGThreadedRenderLoop::event(QEvent *e)
QImage QSGThreadedRenderLoop::grab(QQuickWindow *window)
{
- RLDEBUG("GUI: grab");
- if (!m_thread->isRunning())
+ QSG_GUI_DEBUG(window, "grab");
+
+ Window *w = windowFor(m_windows, window);
+ Q_ASSERT(w);
+
+ if (!w->thread->isRunning())
return QImage();
if (!window->handle())
window->create();
- RLDEBUG1("GUI: - polishing items...");
+ QSG_GUI_DEBUG(w->window, " - polishing items...");
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
d->polishItems();
QImage result;
- m_thread->mutex.lock();
- RLDEBUG1("GUI: - locking, posting grab event");
- m_thread->postEvent(new WMGrabEvent(window, &result));
- m_thread->waitCondition.wait(&m_thread->mutex);
- RLDEBUG1("GUI: - locking, grab done, unlocking");
- m_thread->mutex.unlock();
-
- RLDEBUG1("Gui: - grab complete");
+ w->thread->mutex.lock();
+ QSG_GUI_DEBUG(w->window, " - locking, posting grab event");
+ w->thread->postEvent(new WMGrabEvent(window, &result));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ QSG_GUI_DEBUG(w->window, " - locking, grab done, unlocking");
+ w->thread->mutex.unlock();
+
+ QSG_GUI_DEBUG(w->window, " - grab complete");
return result;
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index b943739a0d..844d180788 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -60,18 +60,17 @@ public:
void show(QQuickWindow *window);
void hide(QQuickWindow *window);
+ void resize(QQuickWindow *window);
void windowDestroyed(QQuickWindow *window);
void exposureChanged(QQuickWindow *window);
- void handleExposure(QQuickWindow *window);
- void handleObscurity(QQuickWindow *window);
-
QImage grab(QQuickWindow *);
void update(QQuickWindow *window);
void maybeUpdate(QQuickWindow *window);
QSGContext *sceneGraphContext() const;
+ QSGRenderContext *createRenderContext(QSGContext *) const;
QAnimationDriver *animationDriver() const;
@@ -86,6 +85,14 @@ public Q_SLOTS:
void animationStopped();
private:
+ struct Window {
+ QQuickWindow *window;
+ QSGRenderThread *thread;
+ int timerId;
+ uint updateDuringSync : 1;
+ uint gotBrokenExposeFromPlatformPlugin : 1;
+ };
+
friend class QSGRenderThread;
void releaseResources(QQuickWindow *window, bool inDestructor);
@@ -94,25 +101,24 @@ private:
bool anyoneShowing() const;
void initialize();
- void maybePostPolishRequest();
-
+ void startOrStopAnimationTimer();
+ void maybePostPolishRequest(Window *w);
void waitForReleaseComplete();
+ void polishAndSync(Window *w);
+ void maybeUpdate(Window *window);
- void polishAndSync();
+ void handleExposure(Window *w);
+ void handleObscurity(Window *w);
- struct Window {
- QQuickWindow *window;
- };
- QSGRenderThread *m_thread;
+ QSGContext *sg;
QAnimationDriver *m_animation_driver;
QList<Window> m_windows;
int m_animation_timer;
- int m_update_timer;
int m_exhaust_delay;
- bool m_sync_triggered_update;
+ bool m_locked;
};
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 95584d0f5d..0c128d5cae 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -85,6 +85,8 @@ QSGWindowsRenderLoop::QSGWindowsRenderLoop()
qsg_debug_timer.start();
#endif
+ m_rc = new QSGRenderContext(m_sg);
+
m_animationDriver = m_sg->createAnimationDriver(m_sg);
m_animationDriver->install();
@@ -102,6 +104,12 @@ QSGWindowsRenderLoop::QSGWindowsRenderLoop()
#endif
}
+QSGWindowsRenderLoop::~QSGWindowsRenderLoop()
+{
+ delete m_rc;
+ delete m_sg;
+}
+
bool QSGWindowsRenderLoop::interleaveIncubation() const
{
return m_animationDriver->isRunning() && anyoneShowing();
@@ -170,13 +178,22 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
RLDEBUG(" - creating GL context");
m_gl = new QOpenGLContext();
m_gl->setFormat(window->requestedFormat());
- m_gl->create();
+ if (QSGContext::sharedOpenGLContext())
+ m_gl->setShareContext(QSGContext::sharedOpenGLContext());
+ bool created = m_gl->create();
+ if (!created) {
+ qWarning("QtQuick: failed to create OpenGL context");
+ delete m_gl;
+ m_gl = 0;
+ return;
+ }
QSG_RENDER_TIMING_SAMPLE(time_created);
RLDEBUG(" - making current");
- m_gl->makeCurrent(window);
+ bool current = m_gl->makeCurrent(window);
RLDEBUG(" - initializing SG");
QSG_RENDER_TIMING_SAMPLE(time_current);
- m_sg->initialize(m_gl);
+ if (current)
+ m_rc->initialize(m_gl);
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing) {
@@ -230,7 +247,8 @@ void QSGWindowsRenderLoop::hide(QQuickWindow *window)
// potentially clean up.
if (m_windows.size() == 0) {
if (!cd->persistentSceneGraph) {
- m_sg->invalidate();
+ QQuickWindowPrivate::get(window)->context->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
if (!cd->persistentGLContext) {
delete m_gl;
m_gl = 0;
@@ -246,7 +264,8 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
// If this is the last tracked window, clean up SG and GL.
if (m_windows.size() == 0) {
- m_sg->invalidate();
+ QQuickWindowPrivate::get(window)->context->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete m_gl;
m_gl = 0;
}
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop_p.h b/src/quick/scenegraph/qsgwindowsrenderloop_p.h
index cb01e1e04b..e4ee688c9f 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop_p.h
+++ b/src/quick/scenegraph/qsgwindowsrenderloop_p.h
@@ -51,11 +51,14 @@
QT_BEGIN_NAMESPACE
+class QSGRenderContext;
+
class QSGWindowsRenderLoop : public QSGRenderLoop
{
Q_OBJECT
public:
explicit QSGWindowsRenderLoop();
+ ~QSGWindowsRenderLoop();
void show(QQuickWindow *window);
void hide(QQuickWindow *window);
@@ -71,14 +74,13 @@ public:
QAnimationDriver *animationDriver() const { return m_animationDriver; }
QSGContext *sceneGraphContext() const { return m_sg; }
+ QSGRenderContext *createRenderContext(QSGContext *) const { return m_rc; }
void releaseResources(QQuickWindow *) { }
void render();
void renderWindow(QQuickWindow *window);
- void resize(QQuickWindow *, const QSize &) { }
-
bool event(QEvent *event);
bool anyoneShowing() const;
@@ -102,6 +104,7 @@ private:
QOpenGLContext *m_gl;
QSGContext *m_sg;
+ QSGRenderContext *m_rc;
QAnimationDriver *m_animationDriver;
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 3b8221264b..6f64c881a8 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -10,7 +10,8 @@ HEADERS += \
$$PWD/coreapi/qsgnodeupdater_p.h \
$$PWD/coreapi/qsgrenderer_p.h \
$$PWD/coreapi/qsgrendernode_p.h \
- $$PWD/coreapi/qsggeometry_p.h
+ $$PWD/coreapi/qsggeometry_p.h \
+ $$PWD/coreapi/qsgmaterialshader_p.h
SOURCES += \
$$PWD/coreapi/qsgbatchrenderer.cpp \
@@ -20,8 +21,7 @@ SOURCES += \
$$PWD/coreapi/qsgnodeupdater.cpp \
$$PWD/coreapi/qsgrenderer.cpp \
$$PWD/coreapi/qsgrendernode.cpp \
- $$PWD/coreapi/qsgshaderrewriter.cpp \
- scenegraph/util/qsgsimplematerial.cpp
+ $$PWD/coreapi/qsgshaderrewriter.cpp
# Util API
HEADERS += \
@@ -39,7 +39,8 @@ HEADERS += \
$$PWD/util/qsgtexture_p.h \
$$PWD/util/qsgtextureprovider.h \
$$PWD/util/qsgpainternode_p.h \
- $$PWD/util/qsgdistancefieldutil_p.h
+ $$PWD/util/qsgdistancefieldutil_p.h \
+ $$PWD/util/qsgshadersourcebuilder_p.h
SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
@@ -53,7 +54,9 @@ SOURCES += \
$$PWD/util/qsgtexture.cpp \
$$PWD/util/qsgtextureprovider.cpp \
$$PWD/util/qsgpainternode.cpp \
- $$PWD/util/qsgdistancefieldutil.cpp
+ $$PWD/util/qsgdistancefieldutil.cpp \
+ $$PWD/util/qsgsimplematerial.cpp \
+ $$PWD/util/qsgshadersourcebuilder.cpp
# QML / Adaptations API
HEADERS += \
@@ -67,7 +70,6 @@ HEADERS += \
$$PWD/qsgdefaultglyphnode_p_p.h \
$$PWD/qsgdefaultimagenode_p.h \
$$PWD/qsgdefaultrectanglenode_p.h \
- $$PWD/qsgflashnode_p.h \
$$PWD/qsgshareddistancefieldglyphcache_p.h \
$$PWD/qsgrenderloop_p.h \
$$PWD/qsgthreadedrenderloop_p.h \
@@ -84,8 +86,77 @@ SOURCES += \
$$PWD/qsgdistancefieldglyphnode_p.cpp \
$$PWD/qsgdefaultimagenode.cpp \
$$PWD/qsgdefaultrectanglenode.cpp \
- $$PWD/qsgflashnode.cpp \
$$PWD/qsgshareddistancefieldglyphcache.cpp \
$$PWD/qsgrenderloop.cpp \
$$PWD/qsgthreadedrenderloop.cpp \
$$PWD/qsgwindowsrenderloop.cpp
+
+RESOURCES += \
+ $$PWD/scenegraph.qrc
+
+OTHER_FILES += \
+ $$PWD/shaders/24bittextmask.frag \
+ $$PWD/shaders/8bittextmask.frag \
+ $$PWD/shaders/distancefieldoutlinetext.frag \
+ $$PWD/shaders/distancefieldshiftedtext.frag \
+ $$PWD/shaders/distancefieldshiftedtext.vert \
+ $$PWD/shaders/distancefieldtext.frag \
+ $$PWD/shaders/distancefieldtext.vert \
+ $$PWD/shaders/flatcolor.frag \
+ $$PWD/shaders/flatcolor.vert \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext.frag \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext.vert \
+ $$PWD/shaders/loqsubpixeldistancefieldtext.frag \
+ $$PWD/shaders/loqsubpixeldistancefieldtext.vert \
+ $$PWD/shaders/opaquetexture.frag \
+ $$PWD/shaders/opaquetexture.vert \
+ $$PWD/shaders/outlinedtext.frag \
+ $$PWD/shaders/outlinedtext.vert \
+ $$PWD/shaders/rendernode.frag \
+ $$PWD/shaders/rendernode.vert \
+ $$PWD/shaders/smoothcolor.frag \
+ $$PWD/shaders/smoothcolor.vert \
+ $$PWD/shaders/smoothtexture.frag \
+ $$PWD/shaders/smoothtexture.vert \
+ $$PWD/shaders/stencilclip.frag \
+ $$PWD/shaders/stencilclip.vert \
+ $$PWD/shaders/styledtext.frag \
+ $$PWD/shaders/styledtext.vert \
+ $$PWD/shaders/textmask.frag \
+ $$PWD/shaders/textmask.vert \
+ $$PWD/shaders/texture.frag \
+ $$PWD/shaders/vertexcolor.frag \
+ $$PWD/shaders/vertexcolor.vert \
+ $$PWD/shaders/24bittextmask_core.frag \
+ $$PWD/shaders/8bittextmask_core.frag \
+ $$PWD/shaders/distancefieldoutlinetext_core.frag \
+ $$PWD/shaders/distancefieldshiftedtext_core.frag \
+ $$PWD/shaders/distancefieldshiftedtext_core.vert \
+ $$PWD/shaders/distancefieldtext_core.frag \
+ $$PWD/shaders/distancefieldtext_core.vert \
+ $$PWD/shaders/flatcolor_core.frag \
+ $$PWD/shaders/flatcolor_core.vert \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext_core.frag \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext_core.vert \
+ $$PWD/shaders/loqsubpixeldistancefieldtext_core.frag \
+ $$PWD/shaders/loqsubpixeldistancefieldtext_core.vert \
+ $$PWD/shaders/opaquetexture_core.frag \
+ $$PWD/shaders/opaquetexture_core.vert \
+ $$PWD/shaders/outlinedtext_core.frag \
+ $$PWD/shaders/outlinedtext_core.vert \
+ $$PWD/shaders/rendernode_core.frag \
+ $$PWD/shaders/rendernode_core.vert \
+ $$PWD/shaders/smoothcolor_core.frag \
+ $$PWD/shaders/smoothcolor_core.vert \
+ $$PWD/shaders/smoothtexture_core.frag \
+ $$PWD/shaders/smoothtexture_core.vert \
+ $$PWD/shaders/stencilclip_core.frag \
+ $$PWD/shaders/stencilclip_core.vert \
+ $$PWD/shaders/styledtext_core.frag \
+ $$PWD/shaders/styledtext_core.vert \
+ $$PWD/shaders/textmask_core.frag \
+ $$PWD/shaders/textmask_core.vert \
+ $$PWD/shaders/texture_core.frag \
+ $$PWD/shaders/vertexcolor_core.frag \
+ $$PWD/shaders/vertexcolor_core.vert
+
diff --git a/src/quick/scenegraph/scenegraph.qrc b/src/quick/scenegraph/scenegraph.qrc
new file mode 100644
index 0000000000..2be8b246d3
--- /dev/null
+++ b/src/quick/scenegraph/scenegraph.qrc
@@ -0,0 +1,68 @@
+<RCC>
+ <qresource prefix="/scenegraph">
+ <file>shaders/flatcolor.frag</file>
+ <file>shaders/flatcolor.vert</file>
+ <file>shaders/8bittextmask.frag</file>
+ <file>shaders/24bittextmask.frag</file>
+ <file>shaders/opaquetexture.frag</file>
+ <file>shaders/opaquetexture.vert</file>
+ <file>shaders/outlinedtext.frag</file>
+ <file>shaders/outlinedtext.vert</file>
+ <file>shaders/smoothcolor.frag</file>
+ <file>shaders/smoothcolor.vert</file>
+ <file>shaders/smoothtexture.frag</file>
+ <file>shaders/smoothtexture.vert</file>
+ <file>shaders/styledtext.frag</file>
+ <file>shaders/styledtext.vert</file>
+ <file>shaders/textmask.frag</file>
+ <file>shaders/textmask.vert</file>
+ <file>shaders/texture.frag</file>
+ <file>shaders/distancefieldoutlinetext.frag</file>
+ <file>shaders/distancefieldshiftedtext.frag</file>
+ <file>shaders/distancefieldshiftedtext.vert</file>
+ <file>shaders/distancefieldtext.frag</file>
+ <file>shaders/distancefieldtext.vert</file>
+ <file>shaders/hiqsubpixeldistancefieldtext.frag</file>
+ <file>shaders/hiqsubpixeldistancefieldtext.vert</file>
+ <file>shaders/loqsubpixeldistancefieldtext.frag</file>
+ <file>shaders/loqsubpixeldistancefieldtext.vert</file>
+ <file>shaders/vertexcolor.frag</file>
+ <file>shaders/vertexcolor.vert</file>
+ <file>shaders/rendernode.vert</file>
+ <file>shaders/rendernode.frag</file>
+ <file>shaders/stencilclip.frag</file>
+ <file>shaders/stencilclip.vert</file>
+ <file>shaders/8bittextmask_core.frag</file>
+ <file>shaders/24bittextmask_core.frag</file>
+ <file>shaders/distancefieldoutlinetext_core.frag</file>
+ <file>shaders/distancefieldshiftedtext_core.frag</file>
+ <file>shaders/distancefieldshiftedtext_core.vert</file>
+ <file>shaders/distancefieldtext_core.frag</file>
+ <file>shaders/distancefieldtext_core.vert</file>
+ <file>shaders/flatcolor_core.frag</file>
+ <file>shaders/flatcolor_core.vert</file>
+ <file>shaders/hiqsubpixeldistancefieldtext_core.frag</file>
+ <file>shaders/hiqsubpixeldistancefieldtext_core.vert</file>
+ <file>shaders/loqsubpixeldistancefieldtext_core.frag</file>
+ <file>shaders/loqsubpixeldistancefieldtext_core.vert</file>
+ <file>shaders/opaquetexture_core.frag</file>
+ <file>shaders/opaquetexture_core.vert</file>
+ <file>shaders/outlinedtext_core.frag</file>
+ <file>shaders/outlinedtext_core.vert</file>
+ <file>shaders/rendernode_core.frag</file>
+ <file>shaders/rendernode_core.vert</file>
+ <file>shaders/smoothcolor_core.frag</file>
+ <file>shaders/smoothcolor_core.vert</file>
+ <file>shaders/smoothtexture_core.frag</file>
+ <file>shaders/smoothtexture_core.vert</file>
+ <file>shaders/stencilclip_core.frag</file>
+ <file>shaders/stencilclip_core.vert</file>
+ <file>shaders/styledtext_core.frag</file>
+ <file>shaders/styledtext_core.vert</file>
+ <file>shaders/textmask_core.frag</file>
+ <file>shaders/textmask_core.vert</file>
+ <file>shaders/texture_core.frag</file>
+ <file>shaders/vertexcolor_core.frag</file>
+ <file>shaders/vertexcolor_core.vert</file>
+ </qresource>
+</RCC>
diff --git a/src/quick/scenegraph/shaders/24bittextmask.frag b/src/quick/scenegraph/shaders/24bittextmask.frag
new file mode 100644
index 0000000000..5c21e202f9
--- /dev/null
+++ b/src/quick/scenegraph/shaders/24bittextmask.frag
@@ -0,0 +1,10 @@
+varying highp vec2 sampleCoord;
+
+uniform lowp sampler2D _qt_texture;
+uniform lowp float color; // just the alpha, really...
+
+void main()
+{
+ lowp vec4 glyph = texture2D(_qt_texture, sampleCoord);
+ gl_FragColor = vec4(glyph.rgb * color, glyph.a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/24bittextmask_core.frag b/src/quick/scenegraph/shaders/24bittextmask_core.frag
new file mode 100644
index 0000000000..29d1f23017
--- /dev/null
+++ b/src/quick/scenegraph/shaders/24bittextmask_core.frag
@@ -0,0 +1,14 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform float color; // just the alpha, really...
+
+void main()
+{
+ vec4 glyph = texture(_qt_texture, sampleCoord);
+ fragColor = vec4(glyph.rgb * color, glyph.a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/8bittextmask.frag b/src/quick/scenegraph/shaders/8bittextmask.frag
new file mode 100644
index 0000000000..44ffb279cb
--- /dev/null
+++ b/src/quick/scenegraph/shaders/8bittextmask.frag
@@ -0,0 +1,9 @@
+varying highp vec2 sampleCoord;
+
+uniform lowp sampler2D _qt_texture;
+uniform lowp vec4 color;
+
+void main()
+{
+ gl_FragColor = color * texture2D(_qt_texture, sampleCoord).a;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/8bittextmask_core.frag b/src/quick/scenegraph/shaders/8bittextmask_core.frag
new file mode 100644
index 0000000000..2d67a4676a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/8bittextmask_core.frag
@@ -0,0 +1,13 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+
+void main()
+{
+ fragColor = color * texture(_qt_texture, sampleCoord).r;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldoutlinetext.frag b/src/quick/scenegraph/shaders/distancefieldoutlinetext.frag
new file mode 100644
index 0000000000..250ed322a1
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldoutlinetext.frag
@@ -0,0 +1,16 @@
+varying highp vec2 sampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform lowp vec4 styleColor;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+uniform mediump float outlineAlphaMax0;
+uniform mediump float outlineAlphaMax1;
+
+void main()
+{
+ mediump float d = texture2D(_qt_texture, sampleCoord).a;
+ gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d))
+ * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldoutlinetext_core.frag b/src/quick/scenegraph/shaders/distancefieldoutlinetext_core.frag
new file mode 100644
index 0000000000..80fa05ca3c
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldoutlinetext_core.frag
@@ -0,0 +1,20 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 styleColor;
+uniform float alphaMin;
+uniform float alphaMax;
+uniform float outlineAlphaMax0;
+uniform float outlineAlphaMax1;
+
+void main()
+{
+ float d = texture(_qt_texture, sampleCoord).r;
+ fragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d))
+ * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag b/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag
new file mode 100644
index 0000000000..60c1c7468b
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag
@@ -0,0 +1,17 @@
+varying highp vec2 sampleCoord;
+varying highp vec2 shiftedSampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform lowp vec4 styleColor;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+
+void main()
+{
+ highp float a = smoothstep(alphaMin, alphaMax, texture2D(_qt_texture, sampleCoord).a);
+ highp vec4 shifted = styleColor * smoothstep(alphaMin,
+ alphaMax,
+ texture2D(_qt_texture, shiftedSampleCoord).a);
+ gl_FragColor = mix(shifted, color, a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext.vert b/src/quick/scenegraph/shaders/distancefieldshiftedtext.vert
new file mode 100644
index 0000000000..800eadc4f1
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext.vert
@@ -0,0 +1,17 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+uniform highp vec2 shift;
+
+varying highp vec2 sampleCoord;
+varying highp vec2 shiftedSampleCoord;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ shiftedSampleCoord = (tCoord - shift) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.frag b/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.frag
new file mode 100644
index 0000000000..3f66965e78
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.frag
@@ -0,0 +1,20 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec2 shiftedSampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 styleColor;
+uniform float alphaMin;
+uniform float alphaMax;
+
+void main()
+{
+ float a = smoothstep(alphaMin, alphaMax, texture(_qt_texture, sampleCoord).r);
+ vec4 shifted = styleColor * smoothstep(alphaMin, alphaMax,
+ texture(_qt_texture, shiftedSampleCoord).r);
+ fragColor = mix(shifted, color, a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.vert b/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.vert
new file mode 100644
index 0000000000..b7a3ecc667
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.vert
@@ -0,0 +1,18 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+out vec2 shiftedSampleCoord;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform vec2 shift;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ shiftedSampleCoord = (tCoord - shift) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldtext.frag b/src/quick/scenegraph/shaders/distancefieldtext.frag
new file mode 100644
index 0000000000..951fb2a825
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldtext.frag
@@ -0,0 +1,13 @@
+varying highp vec2 sampleCoord;
+
+uniform mediump sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+
+void main()
+{
+ gl_FragColor = color * smoothstep(alphaMin,
+ alphaMax,
+ texture2D(_qt_texture, sampleCoord).a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldtext.vert b/src/quick/scenegraph/shaders/distancefieldtext.vert
new file mode 100644
index 0000000000..c4963977a5
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldtext.vert
@@ -0,0 +1,13 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldtext_core.frag b/src/quick/scenegraph/shaders/distancefieldtext_core.frag
new file mode 100644
index 0000000000..9c64a60d3d
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldtext_core.frag
@@ -0,0 +1,16 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform float alphaMin;
+uniform float alphaMax;
+
+void main()
+{
+ fragColor = color * smoothstep(alphaMin, alphaMax,
+ texture(_qt_texture, sampleCoord).r);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldtext_core.vert b/src/quick/scenegraph/shaders/distancefieldtext_core.vert
new file mode 100644
index 0000000000..7fc693d139
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldtext_core.vert
@@ -0,0 +1,15 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/flatcolor.frag b/src/quick/scenegraph/shaders/flatcolor.frag
new file mode 100644
index 0000000000..8c225bf5a4
--- /dev/null
+++ b/src/quick/scenegraph/shaders/flatcolor.frag
@@ -0,0 +1,6 @@
+uniform lowp vec4 color;
+
+void main()
+{
+ gl_FragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/flatcolor.vert b/src/quick/scenegraph/shaders/flatcolor.vert
new file mode 100644
index 0000000000..a61de97f85
--- /dev/null
+++ b/src/quick/scenegraph/shaders/flatcolor.vert
@@ -0,0 +1,7 @@
+attribute highp vec4 vCoord;
+uniform highp mat4 matrix;
+
+void main()
+{
+ gl_Position = matrix * vCoord;
+}
diff --git a/src/quick/scenegraph/shaders/flatcolor_core.frag b/src/quick/scenegraph/shaders/flatcolor_core.frag
new file mode 100644
index 0000000000..23a957ad7b
--- /dev/null
+++ b/src/quick/scenegraph/shaders/flatcolor_core.frag
@@ -0,0 +1,10 @@
+#version 150 core
+
+out vec4 fragColor;
+
+uniform vec4 color;
+
+void main()
+{
+ fragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/flatcolor_core.vert b/src/quick/scenegraph/shaders/flatcolor_core.vert
new file mode 100644
index 0000000000..e33c591b95
--- /dev/null
+++ b/src/quick/scenegraph/shaders/flatcolor_core.vert
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 vCoord;
+
+uniform mat4 matrix;
+
+void main()
+{
+ gl_Position = matrix * vCoord;
+}
diff --git a/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag
new file mode 100644
index 0000000000..9b65e5f79b
--- /dev/null
+++ b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag
@@ -0,0 +1,58 @@
+varying highp vec2 sampleCoord;
+varying highp vec3 sampleFarLeft;
+varying highp vec3 sampleNearLeft;
+varying highp vec3 sampleNearRight;
+varying highp vec3 sampleFarRight;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+
+void main()
+{
+ highp vec4 n;
+ n.x = texture2DProj(_qt_texture, sampleFarLeft).a;
+ n.y = texture2DProj(_qt_texture, sampleNearLeft).a;
+ highp float c = texture2D(_qt_texture, sampleCoord).a;
+ n.z = texture2DProj(_qt_texture, sampleNearRight).a;
+ n.w = texture2DProj(_qt_texture, sampleFarRight).a;
+#if 0
+ // Blurrier, faster.
+ n = smoothstep(alphaMin, alphaMax, n);
+ c = smoothstep(alphaMin, alphaMax, c);
+#else
+ // Sharper, slower.
+ highp vec2 d = min(abs(n.yw - n.xz) * 2., 0.67);
+ highp vec2 lo = mix(vec2(alphaMin), vec2(0.5), d);
+ highp vec2 hi = mix(vec2(alphaMax), vec2(0.5), d);
+ n = smoothstep(lo.xxyy, hi.xxyy, n);
+ c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c);
+#endif
+ gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w;
+}
+
+/*
+#extension GL_OES_standard_derivatives: enable
+
+varying highp vec2 sampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform highp float alphaMin;
+uniform highp float alphaMax;
+
+void main()
+{
+ highp vec2 delta = dFdx(sampleCoord);
+ highp vec4 n;
+ n.x = texture2D(_qt_texture, sampleCoord - 0.667 * delta).a;
+ n.y = texture2D(_qt_texture, sampleCoord - 0.333 * delta).a;
+ highp float c = texture2D(_qt_texture, sampleCoord).a;
+ n.z = texture2D(_qt_texture, sampleCoord + 0.333 * delta).a;
+ n.w = texture2D(_qt_texture, sampleCoord + 0.667 * delta).a;
+ n = smoothstep(alphaMin, alphaMax, n);
+ c = smoothstep(alphaMin, alphaMax, c);
+ gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w;
+};
+*/ \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert
new file mode 100644
index 0000000000..62768e88e1
--- /dev/null
+++ b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert
@@ -0,0 +1,34 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+uniform highp float fontScale;
+uniform highp vec4 vecDelta;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+varying highp vec3 sampleFarLeft;
+varying highp vec3 sampleNearLeft;
+varying highp vec3 sampleNearRight;
+varying highp vec3 sampleFarRight;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+
+ // Calculate neighbor pixel position in item space.
+ highp vec3 wDelta = gl_Position.w * vecDelta.xyw;
+ highp vec3 farLeft = vCoord.xyw - 0.667 * wDelta;
+ highp vec3 nearLeft = vCoord.xyw - 0.333 * wDelta;
+ highp vec3 nearRight = vCoord.xyw + 0.333 * wDelta;
+ highp vec3 farRight = vCoord.xyw + 0.667 * wDelta;
+
+ // Calculate neighbor texture coordinate.
+ highp vec2 scale = textureScale / fontScale;
+ highp vec2 base = sampleCoord - scale * vCoord.xy;
+ sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z);
+ sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z);
+ sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z);
+ sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.frag b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.frag
new file mode 100644
index 0000000000..cf6ba2b8d9
--- /dev/null
+++ b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.frag
@@ -0,0 +1,32 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec3 sampleFarLeft;
+in vec3 sampleNearLeft;
+in vec3 sampleNearRight;
+in vec3 sampleFarRight;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform float alphaMin;
+uniform float alphaMax;
+
+void main()
+{
+ vec4 n;
+ n.x = textureProj(_qt_texture, sampleFarLeft).r;
+ n.y = textureProj(_qt_texture, sampleNearLeft).r;
+ float c = texture(_qt_texture, sampleCoord).r;
+ n.z = textureProj(_qt_texture, sampleNearRight).r;
+ n.w = textureProj(_qt_texture, sampleFarRight).r;
+
+ vec2 d = min(abs(n.yw - n.xz) * 2., 0.67);
+ vec2 lo = mix(vec2(alphaMin), vec2(0.5), d);
+ vec2 hi = mix(vec2(alphaMax), vec2(0.5), d);
+ n = smoothstep(lo.xxyy, hi.xxyy, n);
+ c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c);
+
+ fragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.vert b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.vert
new file mode 100644
index 0000000000..936f74725b
--- /dev/null
+++ b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.vert
@@ -0,0 +1,36 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+out vec3 sampleFarLeft;
+out vec3 sampleNearLeft;
+out vec3 sampleNearRight;
+out vec3 sampleFarRight;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform float fontScale;
+uniform vec4 vecDelta;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+
+ // Calculate neighbor pixel position in item space.
+ vec3 wDelta = gl_Position.w * vecDelta.xyw;
+ vec3 farLeft = vCoord.xyw - 0.667 * wDelta;
+ vec3 nearLeft = vCoord.xyw - 0.333 * wDelta;
+ vec3 nearRight = vCoord.xyw + 0.333 * wDelta;
+ vec3 farRight = vCoord.xyw + 0.667 * wDelta;
+
+ // Calculate neighbor texture coordinate.
+ vec2 scale = textureScale / fontScale;
+ vec2 base = sampleCoord - scale * vCoord.xy;
+ sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z);
+ sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z);
+ sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z);
+ sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.frag b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.frag
new file mode 100644
index 0000000000..61b6c8dd9a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.frag
@@ -0,0 +1,17 @@
+varying highp vec3 sampleNearLeft;
+varying highp vec3 sampleNearRight;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+
+void main()
+{
+ highp vec2 n;
+ n.x = texture2DProj(_qt_texture, sampleNearLeft).a;
+ n.y = texture2DProj(_qt_texture, sampleNearRight).a;
+ n = smoothstep(alphaMin, alphaMax, n);
+ highp float c = 0.5 * (n.x + n.y);
+ gl_FragColor = vec4(n.x, c, n.y, c) * color.w;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.vert b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.vert
new file mode 100644
index 0000000000..33cb7efb19
--- /dev/null
+++ b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.vert
@@ -0,0 +1,27 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+uniform highp float fontScale;
+uniform highp vec4 vecDelta;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec3 sampleNearLeft;
+varying highp vec3 sampleNearRight;
+
+void main()
+{
+ highp vec2 sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+
+ // Calculate neighbor pixel position in item space.
+ highp vec3 wDelta = gl_Position.w * vecDelta.xyw;
+ highp vec3 nearLeft = vCoord.xyw - 0.25 * wDelta;
+ highp vec3 nearRight = vCoord.xyw + 0.25 * wDelta;
+
+ // Calculate neighbor texture coordinate.
+ highp vec2 scale = textureScale / fontScale;
+ highp vec2 base = sampleCoord - scale * vCoord.xy;
+ sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z);
+ sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.frag b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.frag
new file mode 100644
index 0000000000..2dd588d307
--- /dev/null
+++ b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.frag
@@ -0,0 +1,21 @@
+#version 150 core
+
+in vec3 sampleNearLeft;
+in vec3 sampleNearRight;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform float alphaMin;
+uniform float alphaMax;
+
+void main()
+{
+ vec2 n;
+ n.x = textureProj(_qt_texture, sampleNearLeft).r;
+ n.y = textureProj(_qt_texture, sampleNearRight).r;
+ n = smoothstep(alphaMin, alphaMax, n);
+ float c = 0.5 * (n.x + n.y);
+ fragColor = vec4(n.x, c, n.y, c) * color.w;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.vert b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.vert
new file mode 100644
index 0000000000..b887a70001
--- /dev/null
+++ b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.vert
@@ -0,0 +1,29 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec3 sampleNearLeft;
+out vec3 sampleNearRight;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform float fontScale;
+uniform vec4 vecDelta;
+
+void main()
+{
+ vec2 sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+
+ // Calculate neighbor pixel position in item space.
+ vec3 wDelta = gl_Position.w * vecDelta.xyw;
+ vec3 nearLeft = vCoord.xyw - 0.25 * wDelta;
+ vec3 nearRight = vCoord.xyw + 0.25 * wDelta;
+
+ // Calculate neighbor texture coordinate.
+ vec2 scale = textureScale / fontScale;
+ vec2 base = sampleCoord - scale * vCoord.xy;
+ sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z);
+ sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/opaquetexture.frag b/src/quick/scenegraph/shaders/opaquetexture.frag
new file mode 100644
index 0000000000..b7e07de385
--- /dev/null
+++ b/src/quick/scenegraph/shaders/opaquetexture.frag
@@ -0,0 +1,8 @@
+varying highp vec2 qt_TexCoord;
+
+uniform sampler2D qt_Texture;
+
+void main()
+{
+ gl_FragColor = texture2D(qt_Texture, qt_TexCoord);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/opaquetexture.vert b/src/quick/scenegraph/shaders/opaquetexture.vert
new file mode 100644
index 0000000000..32cf02df25
--- /dev/null
+++ b/src/quick/scenegraph/shaders/opaquetexture.vert
@@ -0,0 +1,12 @@
+uniform highp mat4 qt_Matrix;
+
+attribute highp vec4 qt_VertexPosition;
+attribute highp vec2 qt_VertexTexCoord;
+
+varying highp vec2 qt_TexCoord;
+
+void main()
+{
+ qt_TexCoord = qt_VertexTexCoord;
+ gl_Position = qt_Matrix * qt_VertexPosition;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/opaquetexture_core.frag b/src/quick/scenegraph/shaders/opaquetexture_core.frag
new file mode 100644
index 0000000000..5f30e68677
--- /dev/null
+++ b/src/quick/scenegraph/shaders/opaquetexture_core.frag
@@ -0,0 +1,12 @@
+#version 150 core
+
+in vec2 qt_TexCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D qt_Texture;
+
+void main()
+{
+ fragColor = texture(qt_Texture, qt_TexCoord);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/opaquetexture_core.vert b/src/quick/scenegraph/shaders/opaquetexture_core.vert
new file mode 100644
index 0000000000..419b1a825c
--- /dev/null
+++ b/src/quick/scenegraph/shaders/opaquetexture_core.vert
@@ -0,0 +1,14 @@
+#version 150 core
+
+uniform mat4 qt_Matrix;
+
+in vec4 qt_VertexPosition;
+in vec2 qt_VertexTexCoord;
+
+out vec2 qt_TexCoord;
+
+void main()
+{
+ qt_TexCoord = qt_VertexTexCoord;
+ gl_Position = qt_Matrix * qt_VertexPosition;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/outlinedtext.frag b/src/quick/scenegraph/shaders/outlinedtext.frag
new file mode 100644
index 0000000000..b3e5475d5d
--- /dev/null
+++ b/src/quick/scenegraph/shaders/outlinedtext.frag
@@ -0,0 +1,21 @@
+varying highp vec2 sampleCoord;
+varying highp vec2 sCoordUp;
+varying highp vec2 sCoordDown;
+varying highp vec2 sCoordLeft;
+varying highp vec2 sCoordRight;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform lowp vec4 styleColor;
+
+void main()
+{
+ lowp float glyph = texture2D(_qt_texture, sampleCoord).a;
+ lowp float outline = clamp(clamp(texture2D(_qt_texture, sCoordUp).a +
+ texture2D(_qt_texture, sCoordDown).a +
+ texture2D(_qt_texture, sCoordLeft).a +
+ texture2D(_qt_texture, sCoordRight).a,
+ 0.0, 1.0) - glyph,
+ 0.0, 1.0);
+ gl_FragColor = outline * styleColor + glyph * color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/outlinedtext.vert b/src/quick/scenegraph/shaders/outlinedtext.vert
new file mode 100644
index 0000000000..ced8afd034
--- /dev/null
+++ b/src/quick/scenegraph/shaders/outlinedtext.vert
@@ -0,0 +1,22 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+uniform highp vec2 shift;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+varying highp vec2 sCoordUp;
+varying highp vec2 sCoordDown;
+varying highp vec2 sCoordLeft;
+varying highp vec2 sCoordRight;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ sCoordUp = (tCoord - vec2(0.0, -1.0)) * textureScale;
+ sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale;
+ sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale;
+ sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/outlinedtext_core.frag b/src/quick/scenegraph/shaders/outlinedtext_core.frag
new file mode 100644
index 0000000000..e19c8937f9
--- /dev/null
+++ b/src/quick/scenegraph/shaders/outlinedtext_core.frag
@@ -0,0 +1,25 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec2 sCoordUp;
+in vec2 sCoordDown;
+in vec2 sCoordLeft;
+in vec2 sCoordRight;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 styleColor;
+
+void main()
+{
+ float glyph = texture(_qt_texture, sampleCoord).r;
+ float outline = clamp(clamp(texture(_qt_texture, sCoordUp).r +
+ texture(_qt_texture, sCoordDown).r +
+ texture(_qt_texture, sCoordLeft).r +
+ texture(_qt_texture, sCoordRight).r,
+ 0.0, 1.0) - glyph,
+ 0.0, 1.0);
+ fragColor = outline * styleColor + glyph * color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/outlinedtext_core.vert b/src/quick/scenegraph/shaders/outlinedtext_core.vert
new file mode 100644
index 0000000000..4aa13101fd
--- /dev/null
+++ b/src/quick/scenegraph/shaders/outlinedtext_core.vert
@@ -0,0 +1,24 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+out vec2 sCoordUp;
+out vec2 sCoordDown;
+out vec2 sCoordLeft;
+out vec2 sCoordRight;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform vec2 shift;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ sCoordUp = (tCoord - vec2(0.0, -1.0)) * textureScale;
+ sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale;
+ sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale;
+ sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/rendernode.frag b/src/quick/scenegraph/shaders/rendernode.frag
new file mode 100644
index 0000000000..b4e9b0209c
--- /dev/null
+++ b/src/quick/scenegraph/shaders/rendernode.frag
@@ -0,0 +1,8 @@
+uniform lowp sampler2D tex;
+
+varying highp vec2 t;
+
+void main()
+{
+ gl_FragColor = texture2D(tex, t);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/rendernode.vert b/src/quick/scenegraph/shaders/rendernode.vert
new file mode 100644
index 0000000000..fbfe9ef8ae
--- /dev/null
+++ b/src/quick/scenegraph/shaders/rendernode.vert
@@ -0,0 +1,10 @@
+attribute highp vec4 av;
+attribute highp vec2 at;
+
+varying highp vec2 t;
+
+void main()
+{
+ gl_Position = av;
+ t = at;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/rendernode_core.frag b/src/quick/scenegraph/shaders/rendernode_core.frag
new file mode 100644
index 0000000000..7c187265df
--- /dev/null
+++ b/src/quick/scenegraph/shaders/rendernode_core.frag
@@ -0,0 +1,12 @@
+#version 150 core
+
+uniform sampler2D tex;
+
+in vec2 t;
+
+out vec4 color;
+
+void main()
+{
+ fragColor = texture(tex, t);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/rendernode_core.vert b/src/quick/scenegraph/shaders/rendernode_core.vert
new file mode 100644
index 0000000000..a76d519a5a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/rendernode_core.vert
@@ -0,0 +1,12 @@
+#version 150 core
+
+in vec4 av;
+in vec2 at;
+
+out vec2 t;
+
+void main()
+{
+ gl_Position = av;
+ t = at;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothcolor.frag b/src/quick/scenegraph/shaders/smoothcolor.frag
new file mode 100644
index 0000000000..71de9dbfc2
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothcolor.frag
@@ -0,0 +1,6 @@
+varying lowp vec4 color;
+
+void main()
+{
+ gl_FragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothcolor.vert b/src/quick/scenegraph/shaders/smoothcolor.vert
new file mode 100644
index 0000000000..df70fea92a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothcolor.vert
@@ -0,0 +1,45 @@
+uniform highp vec2 pixelSize;
+uniform highp mat4 matrix;
+uniform lowp float opacity;
+
+attribute highp vec4 vertex;
+attribute lowp vec4 vertexColor;
+attribute highp vec2 vertexOffset;
+
+varying lowp vec4 color;
+
+void main()
+{
+ highp vec4 pos = matrix * vertex;
+ gl_Position = pos;
+
+ if (vertexOffset.x != 0.) {
+ highp vec4 delta = matrix[0] * vertexOffset.x;
+ highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ highp float numerator = dot(dir, ndir * pos.w * pos.w);
+ highp float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ }
+
+ if (vertexOffset.y != 0.) {
+ highp vec4 delta = matrix[1] * vertexOffset.y;
+ highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ highp float numerator = dot(dir, ndir * pos.w * pos.w);
+ highp float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ }
+
+ color = vertexColor * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothcolor_core.frag b/src/quick/scenegraph/shaders/smoothcolor_core.frag
new file mode 100644
index 0000000000..84533c2b40
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothcolor_core.frag
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 color;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothcolor_core.vert b/src/quick/scenegraph/shaders/smoothcolor_core.vert
new file mode 100644
index 0000000000..1eed751ccd
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothcolor_core.vert
@@ -0,0 +1,47 @@
+#version 150 core
+
+in vec4 vertex;
+in vec4 vertexColor;
+in vec2 vertexOffset;
+
+out vec4 color;
+
+uniform vec2 pixelSize;
+uniform mat4 matrix;
+uniform float opacity;
+
+void main()
+{
+ vec4 pos = matrix * vertex;
+ gl_Position = pos;
+
+ if (vertexOffset.x != 0.) {
+ vec4 delta = matrix[0] * vertexOffset.x;
+ vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ float numerator = dot(dir, ndir * pos.w * pos.w);
+ float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ }
+
+ if (vertexOffset.y != 0.) {
+ vec4 delta = matrix[1] * vertexOffset.y;
+ vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ float numerator = dot(dir, ndir * pos.w * pos.w);
+ float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ }
+
+ color = vertexColor * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothtexture.frag b/src/quick/scenegraph/shaders/smoothtexture.frag
new file mode 100644
index 0000000000..e4f6359f3d
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothtexture.frag
@@ -0,0 +1,9 @@
+uniform sampler2D qt_Texture;
+
+varying highp vec2 texCoord;
+varying lowp float vertexOpacity;
+
+void main()
+{
+ gl_FragColor = texture2D(qt_Texture, texCoord) * vertexOpacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothtexture.vert b/src/quick/scenegraph/shaders/smoothtexture.vert
new file mode 100644
index 0000000000..1ce824a68f
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothtexture.vert
@@ -0,0 +1,52 @@
+uniform highp vec2 pixelSize;
+uniform highp mat4 qt_Matrix;
+uniform lowp float opacity;
+
+attribute highp vec4 vertex;
+attribute highp vec2 multiTexCoord;
+attribute highp vec2 vertexOffset;
+attribute highp vec2 texCoordOffset;
+
+varying highp vec2 texCoord;
+varying lowp float vertexOpacity;
+
+void main()
+{
+ highp vec4 pos = qt_Matrix * vertex;
+ gl_Position = pos;
+ texCoord = multiTexCoord;
+
+ if (vertexOffset.x != 0.) {
+ highp vec4 delta = qt_Matrix[0] * vertexOffset.x;
+ highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ highp float numerator = dot(dir, ndir * pos.w * pos.w);
+ highp float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ texCoord.x += scale * texCoordOffset.x;
+ }
+
+ if (vertexOffset.y != 0.) {
+ highp vec4 delta = qt_Matrix[1] * vertexOffset.y;
+ highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ highp float numerator = dot(dir, ndir * pos.w * pos.w);
+ highp float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ texCoord.y += scale * texCoordOffset.y;
+ }
+
+ bool onEdge = any(notEqual(vertexOffset, vec2(0.)));
+ bool outerEdge = all(equal(texCoordOffset, vec2(0.)));
+ vertexOpacity = onEdge && outerEdge ? 0. : opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothtexture_core.frag b/src/quick/scenegraph/shaders/smoothtexture_core.frag
new file mode 100644
index 0000000000..8a9aefd4c8
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothtexture_core.frag
@@ -0,0 +1,13 @@
+#version 150 core
+
+in vec2 texCoord;
+in float vertexOpacity;
+
+out vec4 fragColor;
+
+uniform sampler2D qt_Texture;
+
+void main()
+{
+ fragColor = texture(qt_Texture, texCoord) * vertexOpacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothtexture_core.vert b/src/quick/scenegraph/shaders/smoothtexture_core.vert
new file mode 100644
index 0000000000..a2489a39c5
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothtexture_core.vert
@@ -0,0 +1,54 @@
+#version 150 core
+
+in vec4 vertex;
+in vec2 multiTexCoord;
+in vec2 vertexOffset;
+in vec2 texCoordOffset;
+
+out vec2 texCoord;
+out float vertexOpacity;
+
+uniform vec2 pixelSize;
+uniform mat4 qt_Matrix;
+uniform float opacity;
+
+void main()
+{
+ vec4 pos = qt_Matrix * vertex;
+ gl_Position = pos;
+ texCoord = multiTexCoord;
+
+ if (vertexOffset.x != 0.) {
+ vec4 delta = qt_Matrix[0] * vertexOffset.x;
+ vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ float numerator = dot(dir, ndir * pos.w * pos.w);
+ float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ texCoord.x += scale * texCoordOffset.x;
+ }
+
+ if (vertexOffset.y != 0.) {
+ vec4 delta = qt_Matrix[1] * vertexOffset.y;
+ vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ float numerator = dot(dir, ndir * pos.w * pos.w);
+ float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ texCoord.y += scale * texCoordOffset.y;
+ }
+
+ bool onEdge = any(notEqual(vertexOffset, vec2(0.)));
+ bool outerEdge = all(equal(texCoordOffset, vec2(0.)));
+ vertexOpacity = onEdge && outerEdge ? 0. : opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/stencilclip.frag b/src/quick/scenegraph/shaders/stencilclip.frag
new file mode 100644
index 0000000000..70b7717977
--- /dev/null
+++ b/src/quick/scenegraph/shaders/stencilclip.frag
@@ -0,0 +1,4 @@
+void main()
+{
+ gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); // Trolltech green ftw!
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/stencilclip.vert b/src/quick/scenegraph/shaders/stencilclip.vert
new file mode 100644
index 0000000000..0e546c8112
--- /dev/null
+++ b/src/quick/scenegraph/shaders/stencilclip.vert
@@ -0,0 +1,8 @@
+attribute highp vec4 vCoord;
+
+uniform highp mat4 matrix;
+
+void main()
+{
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/stencilclip_core.frag b/src/quick/scenegraph/shaders/stencilclip_core.frag
new file mode 100644
index 0000000000..4d05de4ca9
--- /dev/null
+++ b/src/quick/scenegraph/shaders/stencilclip_core.frag
@@ -0,0 +1,8 @@
+#version 150 core
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(0.81, 0.83, 0.12, 1.0); // Trolltech green ftw!
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/stencilclip_core.vert b/src/quick/scenegraph/shaders/stencilclip_core.vert
new file mode 100644
index 0000000000..37e240c735
--- /dev/null
+++ b/src/quick/scenegraph/shaders/stencilclip_core.vert
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 vCoord;
+
+uniform mat4 matrix;
+
+void main()
+{
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/styledtext.frag b/src/quick/scenegraph/shaders/styledtext.frag
new file mode 100644
index 0000000000..662dbef2fc
--- /dev/null
+++ b/src/quick/scenegraph/shaders/styledtext.frag
@@ -0,0 +1,14 @@
+varying highp vec2 sampleCoord;
+varying highp vec2 shiftedSampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform lowp vec4 styleColor;
+
+void main()
+{
+ lowp float glyph = texture2D(_qt_texture, sampleCoord).a;
+ lowp float style = clamp(texture2D(_qt_texture, shiftedSampleCoord).a - glyph,
+ 0.0, 1.0);
+ gl_FragColor = style * styleColor + glyph * color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/styledtext.vert b/src/quick/scenegraph/shaders/styledtext.vert
new file mode 100644
index 0000000000..3ad9497b65
--- /dev/null
+++ b/src/quick/scenegraph/shaders/styledtext.vert
@@ -0,0 +1,16 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+uniform highp vec2 shift;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+varying highp vec2 shiftedSampleCoord;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ shiftedSampleCoord = (tCoord - shift) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/styledtext_core.frag b/src/quick/scenegraph/shaders/styledtext_core.frag
new file mode 100644
index 0000000000..50f64c64a2
--- /dev/null
+++ b/src/quick/scenegraph/shaders/styledtext_core.frag
@@ -0,0 +1,18 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec2 shiftedSampleCoord;
+
+out vec4 color;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 styleColor;
+
+void main()
+{
+ float glyph = texture(_qt_texture, sampleCoord).a;
+ float style = clamp(texture(_qt_texture, shiftedSampleCoord).r - glyph,
+ 0.0, 1.0);
+ fragColor = style * styleColor + glyph * color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/styledtext_core.vert b/src/quick/scenegraph/shaders/styledtext_core.vert
new file mode 100644
index 0000000000..b7a3ecc667
--- /dev/null
+++ b/src/quick/scenegraph/shaders/styledtext_core.vert
@@ -0,0 +1,18 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+out vec2 shiftedSampleCoord;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform vec2 shift;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ shiftedSampleCoord = (tCoord - shift) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/textmask.frag b/src/quick/scenegraph/shaders/textmask.frag
new file mode 100644
index 0000000000..7715688ecc
--- /dev/null
+++ b/src/quick/scenegraph/shaders/textmask.frag
@@ -0,0 +1,10 @@
+varying highp vec2 sampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+
+void main()
+{
+ lowp vec4 glyph = texture2D(_qt_texture, sampleCoord);
+ gl_FragColor = vec4(glyph.rgb * color.a, glyph.a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/textmask.vert b/src/quick/scenegraph/shaders/textmask.vert
new file mode 100644
index 0000000000..1f45e9cf71
--- /dev/null
+++ b/src/quick/scenegraph/shaders/textmask.vert
@@ -0,0 +1,13 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+}
diff --git a/src/quick/scenegraph/shaders/textmask_core.frag b/src/quick/scenegraph/shaders/textmask_core.frag
new file mode 100644
index 0000000000..17dda53c97
--- /dev/null
+++ b/src/quick/scenegraph/shaders/textmask_core.frag
@@ -0,0 +1,14 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+
+void main()
+{
+ vec4 glyph = texture(_qt_texture, sampleCoord);
+ fragColor = vec4(glyph.rgb * color.a, glyph.a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/textmask_core.vert b/src/quick/scenegraph/shaders/textmask_core.vert
new file mode 100644
index 0000000000..619248dccb
--- /dev/null
+++ b/src/quick/scenegraph/shaders/textmask_core.vert
@@ -0,0 +1,15 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+}
diff --git a/src/quick/scenegraph/shaders/texture.frag b/src/quick/scenegraph/shaders/texture.frag
new file mode 100644
index 0000000000..2d97f2e66a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/texture.frag
@@ -0,0 +1,9 @@
+varying highp vec2 qt_TexCoord;
+
+uniform sampler2D qt_Texture;
+uniform lowp float opacity;
+
+void main()
+{
+ gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/texture_core.frag b/src/quick/scenegraph/shaders/texture_core.frag
new file mode 100644
index 0000000000..d9bdf6a238
--- /dev/null
+++ b/src/quick/scenegraph/shaders/texture_core.frag
@@ -0,0 +1,13 @@
+#version 150 core
+
+in vec2 qt_TexCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D qt_Texture;
+uniform float opacity;
+
+void main()
+{
+ fragColor = texture(qt_Texture, qt_TexCoord) * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/vertexcolor.frag b/src/quick/scenegraph/shaders/vertexcolor.frag
new file mode 100644
index 0000000000..71de9dbfc2
--- /dev/null
+++ b/src/quick/scenegraph/shaders/vertexcolor.frag
@@ -0,0 +1,6 @@
+varying lowp vec4 color;
+
+void main()
+{
+ gl_FragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/vertexcolor.vert b/src/quick/scenegraph/shaders/vertexcolor.vert
new file mode 100644
index 0000000000..750d520114
--- /dev/null
+++ b/src/quick/scenegraph/shaders/vertexcolor.vert
@@ -0,0 +1,13 @@
+attribute highp vec4 vertexCoord;
+attribute highp vec4 vertexColor;
+
+uniform highp mat4 matrix;
+uniform highp float opacity;
+
+varying lowp vec4 color;
+
+void main()
+{
+ gl_Position = matrix * vertexCoord;
+ color = vertexColor * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/vertexcolor_core.frag b/src/quick/scenegraph/shaders/vertexcolor_core.frag
new file mode 100644
index 0000000000..84533c2b40
--- /dev/null
+++ b/src/quick/scenegraph/shaders/vertexcolor_core.frag
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 color;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/vertexcolor_core.vert b/src/quick/scenegraph/shaders/vertexcolor_core.vert
new file mode 100644
index 0000000000..219b840913
--- /dev/null
+++ b/src/quick/scenegraph/shaders/vertexcolor_core.vert
@@ -0,0 +1,15 @@
+#version 150 core
+
+in vec4 vertexCoord;
+in vec4 vertexColor;
+
+out vec4 color;
+
+uniform mat4 matrix;
+uniform float opacity;
+
+void main()
+{
+ gl_Position = matrix * vertexCoord;
+ color = vertexColor * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index 3710f05b9a..8678d106ff 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -47,11 +47,14 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
+#include <QtGui/QSurface>
#include <private/qsgtexture_p.h>
#include <private/qqmlprofilerservice_p.h>
+QT_BEGIN_NAMESPACE
+
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@@ -89,26 +92,36 @@ static int qsg_envInt(const char *name, int defaultValue)
Manager::Manager()
: m_atlas(0)
{
- QSize screenSize = QGuiApplication::primaryScreen()->geometry().size();
+ QOpenGLContext *gl = QOpenGLContext::currentContext();
+ Q_ASSERT(gl);
+ QSurface *surface = gl->surface();
+ QSize surfaceSize = surface->size();
int max;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
- int w = qMin(max, qsg_envInt("QSG_ATLAS_WIDTH", qsg_powerOfTwo(screenSize.width())));
- int h = qMin(max, qsg_envInt("QSG_ATLAS_HEIGHT", qsg_powerOfTwo(screenSize.height())));
+
+ int w = qMin(max, qsg_envInt("QSG_ATLAS_WIDTH", qMax(512, qsg_powerOfTwo(surfaceSize.width()))));
+ int h = qMin(max, qsg_envInt("QSG_ATLAS_HEIGHT", qMax(512, qsg_powerOfTwo(surfaceSize.height()))));
m_atlas_size_limit = qsg_envInt("QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2);
m_atlas_size = QSize(w, h);
+
+ if (qEnvironmentVariableIsSet("QSG_INFO"))
+ qDebug() << "QSG: texture atlas dimensions:" << w << "x" << h;
}
Manager::~Manager()
{
- invalidate();
+ Q_ASSERT(m_atlas == 0);
}
void Manager::invalidate()
{
- delete m_atlas;
- m_atlas = 0;
+ if (m_atlas) {
+ m_atlas->invalidate();
+ m_atlas->deleteLater();
+ m_atlas = 0;
+ }
}
QSGTexture *Manager::create(const QImage &image)
@@ -118,10 +131,7 @@ QSGTexture *Manager::create(const QImage &image)
if (!m_atlas)
m_atlas = new Atlas(m_atlas_size);
t = m_atlas->create(image);
- if (t)
- return t;
}
-
return t;
}
@@ -139,6 +149,11 @@ Atlas::Atlas(const QSize &size)
|| strstr(ext, "GL_EXT_texture_format_BGRA8888")
|| strstr(ext, "GL_IMG_texture_format_BGRA8888")) {
m_internalFormat = m_externalFormat = GL_BGRA;
+#ifdef Q_OS_IOS
+ } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) {
+ m_internalFormat = GL_RGBA;
+ m_externalFormat = GL_BGRA;
+#endif
} else {
m_internalFormat = m_externalFormat = GL_RGBA;
}
@@ -153,13 +168,21 @@ Atlas::Atlas(const QSize &size)
Atlas::~Atlas()
{
- if (m_texture_id)
- glDeleteTextures(1, &m_texture_id);
+ Q_ASSERT(!m_texture_id);
}
+void Atlas::invalidate()
+{
+ Q_ASSERT(QOpenGLContext::currentContext());
+ if (m_texture_id) {
+ glDeleteTextures(1, &m_texture_id);
+ m_texture_id = 0;
+ }
+}
Texture *Atlas::create(const QImage &image)
{
+ // No need to lock, as manager already locked it.
QRect rect = m_allocator.allocate(QSize(image.width() + 2, image.height() + 2));
if (rect.width() > 0 && rect.height() > 0) {
Texture *t = new Texture(this, rect, image);
@@ -293,6 +316,9 @@ bool Atlas::bind(QSGTexture::Filtering filtering)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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);
+#endif
glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, 0);
#if 0
@@ -383,7 +409,6 @@ void Atlas::remove(Texture *t)
{
QRect atlasRect = t->atlasSubRect();
m_allocator.deallocate(atlasRect);
-
m_pending_uploads.removeOne(t);
}
@@ -428,3 +453,5 @@ QSGTexture *Texture::removedFromAtlas() const
}
}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h
index f8edd96f47..ade7b8f00e 100644
--- a/src/quick/scenegraph/util/qsgatlastexture_p.h
+++ b/src/quick/scenegraph/util/qsgatlastexture_p.h
@@ -50,6 +50,8 @@
#include <QtQuick/private/qsgtexture_p.h>
#include <QtQuick/private/qsgareaallocator_p.h>
+QT_BEGIN_NAMESPACE
+
namespace QSGAtlasTexture
{
@@ -69,19 +71,18 @@ public:
private:
Atlas *m_atlas;
- Atlas *m_secondary_atlas;
QSize m_atlas_size;
int m_atlas_size_limit;
};
-class Atlas
+class Atlas : public QObject
{
public:
Atlas(const QSize &size);
~Atlas();
- void initialize();
+ void invalidate();
int textureId() const;
bool bind(QSGTexture::Filtering filteing);
@@ -95,7 +96,6 @@ public:
QSize size() const { return m_size; }
private:
-
QSGAreaAllocator m_allocator;
GLuint m_texture_id;
QSize m_size;
@@ -153,4 +153,6 @@ private:
}
+QT_END_NAMESPACE
+
#endif
diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
index 83264e2930..c603c62a20 100644
--- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgflatcolormaterial.h"
+#include <private/qsgmaterialshader_p.h>
#include <qopenglshaderprogram.h>
@@ -48,6 +49,8 @@ QT_BEGIN_NAMESPACE
class FlatColorMaterialShader : public QSGMaterialShader
{
public:
+ FlatColorMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
@@ -55,8 +58,6 @@ public:
private:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrix_id;
int m_color_id;
@@ -64,6 +65,13 @@ private:
QSGMaterialType FlatColorMaterialShader::type;
+FlatColorMaterialShader::FlatColorMaterialShader()
+ : QSGMaterialShader(*new QSGMaterialShaderPrivate)
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/flatcolor.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/flatcolor.frag"));
+}
+
void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
@@ -98,23 +106,6 @@ void FlatColorMaterialShader::initialize()
m_color_id = program()->uniformLocation("color");
}
-const char *FlatColorMaterialShader::vertexShader() const {
- return
- "attribute highp vec4 vCoord; \n"
- "uniform highp mat4 matrix; \n"
- "void main() { \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *FlatColorMaterialShader::fragmentShader() const {
- return
- "uniform lowp vec4 color; \n"
- "void main() { \n"
- " gl_FragColor = color; \n"
- "}";
-}
-
/*!
diff --git a/src/quick/scenegraph/util/qsgpainternode.cpp b/src/quick/scenegraph/util/qsgpainternode.cpp
index d6bec550d3..797fc4d145 100644
--- a/src/quick/scenegraph/util/qsgpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgpainternode.cpp
@@ -111,7 +111,7 @@ QSGPainterNode::QSGPainterNode(QQuickPaintedItem *item)
, m_dirtyRenderTarget(false)
, m_dirtyTexture(false)
{
- m_context = static_cast<QQuickPaintedItemPrivate *>(QObjectPrivate::get(item))->sceneGraphContext();
+ m_context = static_cast<QQuickPaintedItemPrivate *>(QObjectPrivate::get(item))->sceneGraphRenderContext();
setMaterial(&m_materialO);
setOpaqueMaterial(&m_material);
@@ -260,7 +260,7 @@ void QSGPainterNode::updateRenderTarget()
if (m_actualRenderTarget == QQuickPaintedItem::FramebufferObject ||
m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject) {
- const QOpenGLContext *ctx = m_context->glContext();
+ const QOpenGLContext *ctx = m_context->openglContext();
if (m_fbo && !m_dirtyGeometry && (!ctx->format().samples() || !m_multisamplingSupported))
return;
@@ -323,7 +323,7 @@ void QSGPainterNode::updateFBOSize()
fboWidth = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qt_next_power_of_two(m_size.width()));
fboHeight = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qt_next_power_of_two(m_size.height()));
} else {
- QSize minimumFBOSize = m_context->minimumFBOSize();
+ QSize minimumFBOSize = m_context->sceneGraphContext()->minimumFBOSize();
fboWidth = qMax(minimumFBOSize.width(), m_size.width());
fboHeight = qMax(minimumFBOSize.height(), m_size.height());
}
diff --git a/src/quick/scenegraph/util/qsgpainternode_p.h b/src/quick/scenegraph/util/qsgpainternode_p.h
index bc1556672c..df0943d38e 100644
--- a/src/quick/scenegraph/util/qsgpainternode_p.h
+++ b/src/quick/scenegraph/util/qsgpainternode_p.h
@@ -113,7 +113,7 @@ private:
void updateRenderTarget();
void updateFBOSize();
- QSGContext *m_context;
+ QSGRenderContext *m_context;
QQuickPaintedItem::RenderTarget m_preferredRenderTarget;
QQuickPaintedItem::RenderTarget m_actualRenderTarget;
diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
new file mode 100644
index 0000000000..1a1963dbca
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and 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 "qsgshadersourcebuilder_p.h"
+
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglshaderprogram.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QSGShaderParser {
+
+struct Tokenizer {
+
+ enum Token {
+ Token_Invalid,
+ Token_Void,
+ Token_OpenBrace,
+ Token_CloseBrace,
+ Token_SemiColon,
+ Token_Identifier,
+ Token_Macro,
+ Token_Version,
+ Token_Extension,
+ Token_SingleLineComment,
+ Token_MultiLineCommentStart,
+ Token_MultiLineCommentEnd,
+ Token_NewLine,
+ Token_Unspecified,
+ Token_EOF
+ };
+
+ static const char *NAMES[];
+
+ void initialize(const char *input);
+ Token next();
+
+ const char *stream;
+ const char *pos;
+ const char *identifier;
+};
+
+const char *Tokenizer::NAMES[] = {
+ "Invalid",
+ "Void",
+ "OpenBrace",
+ "CloseBrace",
+ "SemiColon",
+ "Identifier",
+ "Macro",
+ "Version",
+ "Extension",
+ "SingleLineComment",
+ "MultiLineCommentStart",
+ "MultiLineCommentEnd",
+ "NewLine",
+ "Unspecified",
+ "EOF"
+};
+
+void Tokenizer::initialize(const char *input)
+{
+ stream = input;
+ pos = input;
+ identifier = input;
+}
+
+Tokenizer::Token Tokenizer::next()
+{
+ while (*pos != 0) {
+ char c = *pos++;
+ switch (c) {
+ case '/':
+ if (*pos == '/') {
+ // '//' comment
+ return Token_SingleLineComment;
+ } else if (*pos == '*') {
+ // /* */ comment
+ return Token_MultiLineCommentStart;
+ }
+ break;
+
+ case '*':
+ if (*pos == '/')
+ return Token_MultiLineCommentEnd;
+
+ case '\n':
+ return Token_NewLine;
+
+ case '\r':
+ if (*pos == '\n')
+ return Token_NewLine;
+
+ case '#': {
+ if (*pos == 'v' && pos[1] == 'e' && pos[2] == 'r' && pos[3] == 's'
+ && pos[4] == 'i' && pos[5] == 'o' && pos[6] == 'n') {
+ return Token_Version;
+ } else if (*pos == 'e' && pos[1] == 'x' && pos[2] == 't' && pos[3] == 'e'
+ && pos[4] == 'n' && pos[5] == 's' && pos[6] == 'i'&& pos[7] == 'o'
+ && pos[8] == 'n') {
+ return Token_Extension;
+ } else {
+ while (*pos != 0) {
+ if (*pos == '\n') {
+ ++pos;
+ break;
+ } else if (*pos == '\\') {
+ ++pos;
+ while (*pos != 0 && (*pos == ' ' || *pos == '\t'))
+ ++pos;
+ if (*pos != 0 && (*pos == '\n' || (*pos == '\r' && pos[1] == '\n')))
+ pos+=2;
+ } else {
+ ++pos;
+ }
+ }
+ }
+ break;
+ }
+
+ case ';':
+ return Token_SemiColon;
+
+ case 0:
+ return Token_EOF;
+
+ case '{':
+ return Token_OpenBrace;
+
+ case '}':
+ return Token_CloseBrace;
+
+ case ' ':
+ break;
+
+ case 'v': {
+ if (*pos == 'o' && pos[1] == 'i' && pos[2] == 'd') {
+ pos += 3;
+ return Token_Void;
+ }
+ // Fall-thru
+ }
+ default:
+ // Identifier...
+ if ((c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || c == '_') {
+ identifier = pos - 1;
+ while (*pos != 0 && ((*pos >= 'a' && *pos <= 'z')
+ || (*pos >= 'A' && *pos <= 'Z')
+ || *pos == '_'
+ || (*pos >= '0' && *pos <= '9'))) {
+ ++pos;
+ }
+ return Token_Identifier;
+ } else {
+ return Token_Unspecified;
+ }
+ }
+ }
+
+ return Token_Invalid;
+}
+
+} // namespace QSGShaderParser
+
+using namespace QSGShaderParser;
+
+QSGShaderSourceBuilder::QSGShaderSourceBuilder()
+{
+}
+
+void QSGShaderSourceBuilder::initializeProgramFromFiles(QOpenGLShaderProgram *program,
+ const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ Q_ASSERT(program);
+ program->removeAllShaders();
+
+ QSGShaderSourceBuilder builder;
+
+ builder.appendSourceFile(vertexShader);
+ program->addShaderFromSourceCode(QOpenGLShader::Vertex, builder.source());
+ builder.clear();
+
+ builder.appendSourceFile(fragmentShader);
+ program->addShaderFromSourceCode(QOpenGLShader::Fragment, builder.source());
+}
+
+QByteArray QSGShaderSourceBuilder::source() const
+{
+ return m_source;
+}
+
+void QSGShaderSourceBuilder::clear()
+{
+ m_source.clear();
+}
+
+void QSGShaderSourceBuilder::appendSource(const QByteArray &source)
+{
+ m_source += source;
+}
+
+void QSGShaderSourceBuilder::appendSourceFile(const QString &fileName)
+{
+ const QString resolvedFileName = resolveShaderPath(fileName);
+ QFile f(resolvedFileName);
+ if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qWarning() << "Failed to find shader" << resolvedFileName;
+ return;
+ }
+ m_source += f.readAll();
+}
+
+void QSGShaderSourceBuilder::addDefinition(const QByteArray &definition)
+{
+ if (definition.isEmpty())
+ return;
+
+ Tokenizer tok;
+ const char *input = m_source.constData();
+ tok.initialize(input);
+
+ // First find #version, #extension's and "void main() { ... "
+ const char *versionPos = 0;
+ const char *extensionPos = 0;
+ bool inSingleLineComment = false;
+ bool inMultiLineComment = false;
+ bool foundVersionStart = false;
+ bool foundExtensionStart = false;
+
+ Tokenizer::Token lt = Tokenizer::Token_Unspecified;
+ Tokenizer::Token t = tok.next();
+ while (t != Tokenizer::Token_EOF) {
+ // Handle comment blocks
+ if (t == Tokenizer::Token_MultiLineCommentStart )
+ inMultiLineComment = true;
+ if (t == Tokenizer::Token_MultiLineCommentEnd)
+ inMultiLineComment = false;
+ if (t == Tokenizer::Token_SingleLineComment)
+ inSingleLineComment = true;
+ if (t == Tokenizer::Token_NewLine && inSingleLineComment && !inMultiLineComment)
+ inSingleLineComment = false;
+
+ // Have we found #version, #extension or void main()?
+ if (t == Tokenizer::Token_Version && !inSingleLineComment && !inMultiLineComment)
+ foundVersionStart = true;
+
+ if (t == Tokenizer::Token_Extension && !inSingleLineComment && !inMultiLineComment)
+ foundExtensionStart = true;
+
+ if (foundVersionStart && t == Tokenizer::Token_NewLine) {
+ versionPos = tok.pos;
+ foundVersionStart = false;
+ } else if (foundExtensionStart && t == Tokenizer::Token_NewLine) {
+ extensionPos = tok.pos;
+ foundExtensionStart = false;
+ } else if (lt == Tokenizer::Token_Void && t == Tokenizer::Token_Identifier) {
+ if (qstrncmp("main", tok.identifier, 4) == 0)
+ break;
+ }
+
+ // Scan to next token
+ lt = t;
+ t = tok.next();
+ }
+
+ // Determine where to insert the definition.
+ // If we found #extension directives, insert after last one,
+ // else, if we found #version insert after #version
+ // otherwise, insert at beginning.
+ const char *insertionPos = extensionPos ? extensionPos : (versionPos ? versionPos : input);
+
+ // Construct a new shader string, inserting the definition
+ QByteArray newSource;
+ newSource.reserve(m_source.size() + definition.size() + 9);
+ newSource += QByteArray::fromRawData(input, insertionPos - input);
+ newSource += QByteArrayLiteral("#define ") + definition + QByteArrayLiteral("\n");
+ newSource += QByteArray::fromRawData(insertionPos, m_source.size() - (insertionPos - input));
+
+ m_source = newSource;
+}
+
+void QSGShaderSourceBuilder::removeVersion()
+{
+ Tokenizer tok;
+ const char *input = m_source.constData();
+ tok.initialize(input);
+
+ // First find #version beginning and end (if present)
+ const char *versionStartPos = 0;
+ const char *versionEndPos = 0;
+ bool inSingleLineComment = false;
+ bool inMultiLineComment = false;
+ bool foundVersionStart = false;
+
+ Tokenizer::Token lt = Tokenizer::Token_Unspecified;
+ Tokenizer::Token t = tok.next();
+ while (t != Tokenizer::Token_EOF) {
+ // Handle comment blocks
+ if (t == Tokenizer::Token_MultiLineCommentStart )
+ inMultiLineComment = true;
+ if (t == Tokenizer::Token_MultiLineCommentEnd)
+ inMultiLineComment = false;
+ if (t == Tokenizer::Token_SingleLineComment)
+ inSingleLineComment = true;
+ if (t == Tokenizer::Token_NewLine && inSingleLineComment && !inMultiLineComment)
+ inSingleLineComment = false;
+
+ // Have we found #version, #extension or void main()?
+ if (t == Tokenizer::Token_Version && !inSingleLineComment && !inMultiLineComment) {
+ versionStartPos = tok.pos - 1;
+ foundVersionStart = true;
+ } else if (foundVersionStart && t == Tokenizer::Token_NewLine) {
+ versionEndPos = tok.pos;
+ break;
+ } else if (lt == Tokenizer::Token_Void && t == Tokenizer::Token_Identifier) {
+ if (qstrncmp("main", tok.identifier, 4) == 0)
+ break;
+ }
+
+ // Scan to next token
+ lt = t;
+ t = tok.next();
+ }
+
+ if (versionStartPos == 0)
+ return;
+
+ // Construct a new shader string, inserting the definition
+ QByteArray newSource;
+ newSource.reserve(m_source.size() - (versionEndPos - versionStartPos));
+ newSource += QByteArray::fromRawData(input, versionStartPos - input);
+ newSource += QByteArray::fromRawData(versionEndPos, m_source.size() - (versionEndPos - versionStartPos));
+
+ m_source = newSource;
+}
+
+QString QSGShaderSourceBuilder::resolveShaderPath(const QString &path) const
+{
+ if (contextProfile() != QSurfaceFormat::CoreProfile) {
+ return path;
+ } else {
+ int idx = path.lastIndexOf(QStringLiteral("."));
+ QString resolvedPath;
+ if (idx != -1)
+ resolvedPath = path.left(idx)
+ + QStringLiteral("_core")
+ + path.right(path.length() - idx);
+ return resolvedPath;
+ }
+}
+
+QSurfaceFormat::OpenGLContextProfile QSGShaderSourceBuilder::contextProfile() const
+{
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ QSurfaceFormat::OpenGLContextProfile profile = QSurfaceFormat::NoProfile;
+ Q_ASSERT(context);
+ profile = context->format().profile();
+ return profile;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h b/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h
new file mode 100644
index 0000000000..63f2d78767
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and 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 QSGSHADERSOURCEBUILDER_P_H
+#define QSGSHADERSOURCEBUILDER_P_H
+
+#include <private/qtquickglobal_p.h>
+
+#include <QtGui/qsurfaceformat.h>
+#include <QtCore/qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLShaderProgram;
+
+class Q_QUICK_PRIVATE_EXPORT QSGShaderSourceBuilder
+{
+public:
+ QSGShaderSourceBuilder();
+
+ static void initializeProgramFromFiles(QOpenGLShaderProgram *program,
+ const QString &vertexShader,
+ const QString &fragmentShader);
+
+ QByteArray source() const;
+ void clear();
+
+ void appendSource(const QByteArray &source);
+ void appendSourceFile(const QString &fileName);
+ void addDefinition(const QByteArray &definition);
+ void removeVersion();
+
+protected:
+ virtual QString resolveShaderPath(const QString &path) const;
+
+private:
+ QSurfaceFormat::OpenGLContextProfile contextProfile() const;
+
+ QByteArray m_source;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSHADERSOURCEBUILDER_P_H
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index b079100a37..51b3bafaf7 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -682,16 +682,21 @@ void QSGPlainTexture::bind()
GLenum externalFormat = GL_RGBA;
GLenum internalFormat = GL_RGBA;
- const char *extensions = (const char *) glGetString(GL_EXTENSIONS);
- if (strstr(extensions, "GL_EXT_bgra")) {
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ if (context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"))) {
externalFormat = GL_BGRA;
#ifdef QT_OPENGL_ES
internalFormat = GL_BGRA;
#endif
- } else if (strstr(extensions, "GL_EXT_texture_format_BGRA8888")
- || strstr(extensions, "GL_IMG_texture_format_BGRA8888")) {
+ } else if (context->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888"))
+ || context->hasExtension(QByteArrayLiteral("GL_IMG_texture_format_BGRA8888"))) {
externalFormat = GL_BGRA;
internalFormat = GL_BGRA;
+#ifdef Q_OS_IOS
+ } else if (context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGBA;
+#endif
} else {
qsg_swizzleBGRAToRGBA(&tmp);
}
@@ -711,8 +716,7 @@ void QSGPlainTexture::bind()
if (m_has_mipmaps) {
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ context->functions()->glGenerateMipmap(GL_TEXTURE_2D);
m_mipmaps_generated = true;
}
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index ba98c83682..df55404504 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -54,36 +54,15 @@ inline static bool isPowerOfTwo(int x)
}
#endif
-const char qt_scenegraph_texture_material_vertex_code[] =
- "uniform highp mat4 qt_Matrix; \n"
- "attribute highp vec4 qt_VertexPosition; \n"
- "attribute highp vec2 qt_VertexTexCoord; \n"
- "varying highp vec2 qt_TexCoord; \n"
- "void main() { \n"
- " qt_TexCoord = qt_VertexTexCoord; \n"
- " gl_Position = qt_Matrix * qt_VertexPosition; \n"
- "}";
-
-const char qt_scenegraph_texture_material_fragment[] =
- "varying highp vec2 qt_TexCoord; \n"
- "uniform sampler2D qt_Texture; \n"
- "void main() { \n"
- " gl_FragColor = texture2D(qt_Texture, qt_TexCoord);\n"
- "}";
-
-
-const char *QSGOpaqueTextureMaterialShader::vertexShader() const
-{
- return qt_scenegraph_texture_material_vertex_code;
-}
+QSGMaterialType QSGOpaqueTextureMaterialShader::type;
-const char *QSGOpaqueTextureMaterialShader::fragmentShader() const
+QSGOpaqueTextureMaterialShader::QSGOpaqueTextureMaterialShader()
+ : QSGMaterialShader()
{
- return qt_scenegraph_texture_material_fragment;
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/opaquetexture.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/opaquetexture.frag"));
}
-QSGMaterialType QSGOpaqueTextureMaterialShader::type;
-
char const *const *QSGOpaqueTextureMaterialShader::attributeNames() const
{
static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 };
@@ -353,14 +332,6 @@ int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
a material in the scene graph.
*/
-static const char qt_scenegraph_texture_material_opacity_fragment[] =
- "varying highp vec2 qt_TexCoord; \n"
- "uniform sampler2D qt_Texture; \n"
- "uniform lowp float opacity; \n"
- "void main() { \n"
- " gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * opacity; \n"
- "}";
-
QSGMaterialType QSGTextureMaterialShader::type;
@@ -385,6 +356,12 @@ QSGMaterialShader *QSGTextureMaterial::createShader() const
return new QSGTextureMaterialShader;
}
+QSGTextureMaterialShader::QSGTextureMaterialShader()
+ : QSGOpaqueTextureMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/texture.frag"));
+}
+
void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
@@ -400,9 +377,4 @@ void QSGTextureMaterialShader::initialize()
m_opacity_id = program()->uniformLocation("opacity");
}
-const char *QSGTextureMaterialShader::fragmentShader() const
-{
- return qt_scenegraph_texture_material_opacity_fragment;
-}
-
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgtexturematerial_p.h b/src/quick/scenegraph/util/qsgtexturematerial_p.h
index 077337d211..db65d85738 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial_p.h
+++ b/src/quick/scenegraph/util/qsgtexturematerial_p.h
@@ -50,6 +50,8 @@ QT_BEGIN_NAMESPACE
class Q_QUICK_PRIVATE_EXPORT QSGOpaqueTextureMaterialShader : public QSGMaterialShader
{
public:
+ QSGOpaqueTextureMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
@@ -57,8 +59,6 @@ public:
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrix_id;
};
@@ -66,14 +66,14 @@ protected:
class QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader
{
public:
+ QSGTextureMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual void initialize();
static QSGMaterialType type;
protected:
- virtual const char *fragmentShader() const;
-
int m_opacity_id;
};
diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
index f205f34ce4..ef2455f702 100644
--- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -48,6 +48,8 @@ QT_BEGIN_NAMESPACE
class QSGVertexColorMaterialShader : public QSGMaterialShader
{
public:
+ QSGVertexColorMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
@@ -55,8 +57,6 @@ public:
private:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrix_id;
int m_opacity_id;
@@ -64,6 +64,13 @@ private:
QSGMaterialType QSGVertexColorMaterialShader::type;
+QSGVertexColorMaterialShader::QSGVertexColorMaterialShader()
+ : QSGMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/vertexcolor.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/vertexcolor.frag"));
+}
+
void QSGVertexColorMaterialShader::updateState(const RenderState &state, QSGMaterial * /*newEffect*/, QSGMaterial *)
{
if (state.isOpacityDirty())
@@ -85,28 +92,6 @@ void QSGVertexColorMaterialShader::initialize()
m_opacity_id = program()->uniformLocation("opacity");
}
-const char *QSGVertexColorMaterialShader::vertexShader() const {
- return
- "attribute highp vec4 vertexCoord; \n"
- "attribute highp vec4 vertexColor; \n"
- "uniform highp mat4 matrix; \n"
- "uniform highp float opacity; \n"
- "varying lowp vec4 color; \n"
- "void main() { \n"
- " gl_Position = matrix * vertexCoord; \n"
- " color = vertexColor * opacity; \n"
- "}";
-}
-
-const char *QSGVertexColorMaterialShader::fragmentShader() const {
- return
- "varying lowp vec4 color; \n"
- "void main() { \n"
- " gl_FragColor = color; \n"
- "}";
-}
-
-
/*!
\class QSGVertexColorMaterial
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 6a762bea68..f743acc249 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -673,7 +673,7 @@ QQuickAbstractAnimation::ThreadingModel QQuickAbstractAnimation::threadingModel(
}
\endcode
- \sa {Animation and Transitions in Qt Quick}, {qml/animation/basics}{Animation basics example}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickPauseAnimation::QQuickPauseAnimation(QObject *parent)
: QQuickAbstractAnimation(*(new QQuickPauseAnimationPrivate), parent)
@@ -752,7 +752,7 @@ QAbstractAnimationJob* QQuickPauseAnimation::transition(QQuickStateActions &acti
\l{PropertyAnimation::}{properties} are explicitly set for the animation,
then those are used instead.
- \sa {Animation and Transitions in Qt Quick}, {qml/animation/basics}{Animation basics example}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickColorAnimation::QQuickColorAnimation(QObject *parent)
: QQuickPropertyAnimation(parent)
@@ -1275,7 +1275,7 @@ QAbstractAnimationJob* QQuickPropertyAction::transition(QQuickStateActions &acti
changes in the number value that it is tracking. If this is the case, use
SmoothedAnimation instead.
- \sa {Animation and Transitions in Qt Quick}, {qml/animation/basics}{Animation basics example}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickNumberAnimation::QQuickNumberAnimation(QObject *parent)
: QQuickPropertyAnimation(parent)
@@ -1378,7 +1378,7 @@ void QQuickNumberAnimation::setTo(qreal t)
sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
variety of methods for creating animations.
- \sa {Animation and Transitions in Qt Quick}, {qml/animation/basics}{Animation basics example}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickVector3dAnimation::QQuickVector3dAnimation(QObject *parent)
: QQuickPropertyAnimation(parent)
@@ -1478,7 +1478,7 @@ void QQuickVector3dAnimation::setTo(QVector3D t)
sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
variety of methods for creating animations.
- \sa {Animation and Transitions in Qt Quick}, {qml/animation/basics}{Animation basics example}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QVariant _q_interpolateShortestRotation(qreal &f, qreal &t, qreal progress)
{
@@ -1648,7 +1648,8 @@ QQuickAnimationGroup::QQuickAnimationGroup(QQuickAnimationGroupPrivate &dd, QObj
void QQuickAnimationGroupPrivate::append_animation(QQmlListProperty<QQuickAbstractAnimation> *list, QQuickAbstractAnimation *a)
{
- if (QQuickAnimationGroup *q = qmlobject_cast<QQuickAnimationGroup *>(list->object))
+ QQuickAnimationGroup *q = qmlobject_cast<QQuickAnimationGroup *>(list->object);
+ if (q && a)
a->setGroup(q);
}
@@ -1711,7 +1712,7 @@ QQmlListProperty<QQuickAbstractAnimation> QQuickAnimationGroup::animations()
ParallelAnimation, it cannot be individually started and stopped; the
SequentialAnimation or ParallelAnimation must be started and stopped as a group.
- \sa ParallelAnimation, {Animation and Transitions in Qt Quick}, {qml/animation/basics}{Animation basics example}
+ \sa ParallelAnimation, {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickSequentialAnimation::QQuickSequentialAnimation(QObject *parent) :
@@ -1801,7 +1802,7 @@ QAbstractAnimationJob* QQuickSequentialAnimation::transition(QQuickStateActions
ParallelAnimation, it cannot be individually started and stopped; the
SequentialAnimation or ParallelAnimation must be started and stopped as a group.
- \sa SequentialAnimation, {Animation and Transitions in Qt Quick}, {qml/animation/basics}{Animation basics example}
+ \sa SequentialAnimation, {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickParallelAnimation::QQuickParallelAnimation(QObject *parent) :
QQuickAnimationGroup(parent)
@@ -1984,7 +1985,7 @@ void QQuickBulkValueAnimator::topLevelAnimationLoopChanged()
Note that PropertyAnimation inherits the abstract \l Animation type.
This includes additional properties and methods for controlling the animation.
- \sa {Animation and Transitions in Qt Quick}, {qml/animation/basics}{Animation basics example}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickPropertyAnimation::QQuickPropertyAnimation(QObject *parent)
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index 82c66b431d..7991dd8110 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -48,54 +48,82 @@
#include <QtGui/qscreen.h>
+#include <QtCore/qcoreapplication.h>
+
QT_BEGIN_NAMESPACE
QQuickAnimatorController::QQuickAnimatorController()
- : window(0)
+ : m_window(0)
{
}
QQuickAnimatorController::~QQuickAnimatorController()
{
- qDeleteAll(activeRootAnimations);
+ // The proxy job might already have been deleted, in which case we
+ // need to avoid calling functions on them. Then delete the job.
+ foreach (QAbstractAnimationJob *job, m_deleting) {
+ m_starting.take(job);
+ m_stopping.take(job);
+ m_animatorRoots.take(job);
+ delete job;
+ }
+
+ foreach (QQuickAnimatorProxyJob *proxy, m_animatorRoots)
+ proxy->controllerWasDeleted();
+ qDeleteAll(m_animatorRoots.keys());
+
+ // Delete those who have been started, stopped and are now still
+ // pending for restart.
+ foreach (QAbstractAnimationJob *job, m_starting.keys()) {
+ if (!m_animatorRoots.contains(job))
+ delete job;
+ }
}
void QQuickAnimatorController::itemDestroyed(QObject *o)
{
- deletedSinceLastFrame << (QQuickItem *) o;
+ m_deletedSinceLastFrame << (QQuickItem *) o;
}
void QQuickAnimatorController::advance()
{
bool running = false;
- for (QSet<QAbstractAnimationJob *>::const_iterator it = activeRootAnimations.constBegin();
- !running && it != activeRootAnimations.constEnd(); ++it) {
- if ((*it)->isRunning())
+ for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
+ !running && it != m_animatorRoots.constEnd(); ++it) {
+ if (it.key()->isRunning())
running = true;
}
// It was tempting to only run over the active animations, but we need to push
// the values for the transforms that finished in the last frame and those will
// have been removed already...
- for (QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *>::const_iterator it = transforms.constBegin();
- it != transforms.constEnd(); ++it) {
+ lock();
+ for (QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *>::const_iterator it = m_transforms.constBegin();
+ it != m_transforms.constEnd(); ++it) {
+ QQuickTransformAnimatorJob::Helper *xform = *it;
+ // Set to zero when the item was deleted in beforeNodeSync().
+ if (!xform->item)
+ continue;
(*it)->apply();
}
+ unlock();
if (running)
- window->update();
+ m_window->update();
}
static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c)
{
if (job->isRenderThreadJob()) {
QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
- if (!j->target())
+ if (!j->target()) {
return;
- else if (c->deletedSinceLastFrame.contains(j->target()))
+ } else if (c->m_deletedSinceLastFrame.contains(j->target())) {
j->targetWasDeleted();
- else
+ } else {
+ j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange);
j->initialize(c);
+ }
} else if (job->isGroup()) {
QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
@@ -105,90 +133,117 @@ static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorC
void QQuickAnimatorController::beforeNodeSync()
{
- // Force a render pass if we are adding new animations
- // so that advance will be called..
- if (starting.size())
- window->update();
-
- for (int i=0; i<starting.size(); ++i) {
- QAbstractAnimationJob *job = starting.at(i);
- job->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
+ foreach (QAbstractAnimationJob *job, m_deleting) {
+ m_starting.take(job);
+ m_stopping.take(job);
+ m_animatorRoots.take(job);
+ job->stop();
+ delete job;
+ }
+ m_deleting.clear();
+
+ if (m_starting.size())
+ m_window->update();
+ foreach (QQuickAnimatorProxyJob *proxy, m_starting) {
+ QAbstractAnimationJob *job = proxy->job();
+ job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
qquick_initialize_helper(job, this);
+ m_animatorRoots[job] = proxy;
job->start();
+ proxy->startedByController();
}
- starting.clear();
+ m_starting.clear();
- for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
- it != activeLeafAnimations.constEnd(); ++it) {
- QQuickAnimatorJob *job = *it;
+ foreach (QQuickAnimatorProxyJob *proxy, m_stopping) {
+ QAbstractAnimationJob *job = proxy->job();
+ job->stop();
+ }
+ m_stopping.clear();
+
+ foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
if (!job->target())
continue;
- else if (deletedSinceLastFrame.contains(job->target()))
+ else if (m_deletedSinceLastFrame.contains(job->target()))
job->targetWasDeleted();
else if (job->isTransform()) {
- QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(*it);
+ QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(job);
xform->transformHelper()->sync();
}
}
- deletedSinceLastFrame.clear();
+ foreach (QQuickItem *wiped, m_deletedSinceLastFrame) {
+ QQuickTransformAnimatorJob::Helper *helper = m_transforms.value(wiped);
+ if (helper)
+ helper->item = 0;
+ }
+
+ m_deletedSinceLastFrame.clear();
}
void QQuickAnimatorController::afterNodeSync()
{
- for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
- it != activeLeafAnimations.constEnd(); ++it) {
- QQuickAnimatorJob *job = *it;
- if (job->isUniform() && job->target()) {
- QQuickUniformAnimatorJob *job = static_cast<QQuickUniformAnimatorJob *>(*it);
- job->afterNodeSync();
- }
+ foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
+ if (job->isUniform() && job->target())
+ static_cast<QQuickUniformAnimatorJob *>(job)->afterNodeSync();
}
}
-
-void QQuickAnimatorController::startAnimation(QAbstractAnimationJob *job)
+void QQuickAnimatorController::animationFinished(QAbstractAnimationJob *job)
{
- mutex.lock();
- starting << job;
- mutex.unlock();
+ /* We are currently on the render thread and m_deleting is primarily
+ * being written on the GUI Thread and read during sync. However, we don't
+ * need to lock here as this is a direct result of animationDriver->advance()
+ * which is already locked. For non-threaded render loops no locking is
+ * needed in any case.
+ */
+ if (!m_deleting.contains(job)) {
+ QQuickAnimatorProxyJob *proxy = m_animatorRoots[job];
+ if (proxy)
+ QCoreApplication::postEvent(proxy, new QEvent(QEvent::User));
+ // else already gone...
+ }
}
-void QQuickAnimatorController::animationsStarted()
+void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job,
+ QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State oldState)
{
- window->update();
+ Q_ASSERT(job->isRenderThreadJob());
+ QQuickAnimatorJob *animator = static_cast<QQuickAnimatorJob *>(job);
+ if (newState == QAbstractAnimationJob::Running) {
+ m_activeLeafAnimations << animator;
+ animator->setHasBeenRunning(true);
+ } else if (oldState == QAbstractAnimationJob::Running) {
+ m_activeLeafAnimations.remove(animator);
+ }
}
-void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job,
- QAbstractAnimationJob::State newState,
- QAbstractAnimationJob::State)
+
+
+void QQuickAnimatorController::requestSync()
{
- if (newState == QAbstractAnimationJob::Running)
- activeRootAnimations << job;
- else
- activeRootAnimations.remove(job);
+ // Force a "sync" pass as the newly started animation needs to sync properties from GUI.
+ m_window->maybeUpdate();
}
-bool QQuickAnimatorController::event(QEvent *e)
+// These functions are called on the GUI thread.
+void QQuickAnimatorController::startJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job)
{
- if ((int) e->type() == StopAnimation) {
- QAbstractAnimationJob *job = static_cast<Event *>(e)->job;
- mutex.lock();
- starting.removeOne(job);
- mutex.unlock();
- job->stop();
- return true;
+ m_starting[job] = proxy;
+ requestSync();
+}
- } else if ((uint) e->type() == DeleteAnimation) {
- QAbstractAnimationJob *job = static_cast<Event *>(e)->job;
- mutex.lock();
- starting.removeOne(job);
- mutex.unlock();
- job->stop();
- delete job;
- return true;
- }
+void QQuickAnimatorController::stopJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job)
+{
+ m_stopping[job] = proxy;
+ requestSync();
+}
- return QObject::event(e);
+void QQuickAnimatorController::deleteJob(QAbstractAnimationJob *job)
+{
+ lock();
+ m_deleting << job;
+ requestSync();
+ unlock();
}
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h
index ab08bf05db..6223a9938f 100644
--- a/src/quick/util/qquickanimatorcontroller_p.h
+++ b/src/quick/util/qquickanimatorcontroller_p.h
@@ -47,6 +47,7 @@
#include <QtQuick/qquickitem.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
QT_BEGIN_NAMESPACE
@@ -55,27 +56,6 @@ class QQuickAnimatorController : public QObject, public QAnimationJobChangeListe
Q_OBJECT
public:
-
- enum EventType {
- // GUI to RT events
- StartAnimation = QEvent::User + 1,
- StopAnimation,
- DeleteAnimation,
-
- // RT back to GUI events
- AnimationFinished
- };
-
- class Event : public QEvent {
- public:
- Event(QAbstractAnimationJob *j, EventType type)
- : QEvent(QEvent::Type(type))
- , job(j)
- {
- }
- QAbstractAnimationJob *job;
- };
-
QQuickAnimatorController();
~QQuickAnimatorController();
@@ -83,32 +63,35 @@ public:
void beforeNodeSync();
void afterNodeSync();
- bool event(QEvent *);
+ void animationFinished(QAbstractAnimationJob *job);
+ void animationStateChanged(QAbstractAnimationJob *job, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
- void startAnimation(QAbstractAnimationJob *job);
+ void requestSync();
- void animationStateChanged(QAbstractAnimationJob *job,
- QAbstractAnimationJob::State newState,
- QAbstractAnimationJob::State oldState);
+ // These are called from the GUI thread (the proxy)
+ void startJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job);
+ void stopJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job);
+ void deleteJob(QAbstractAnimationJob *job);
+
+ void lock() { m_mutex.lock(); }
+ void unlock() { m_mutex.unlock(); }
public Q_SLOTS:
- void animationsStarted();
void itemDestroyed(QObject *);
public:
- QList<QAbstractAnimationJob *> starting;
- QList<QAbstractAnimationJob *> stopped;
-
- QSet<QAbstractAnimationJob *> activeRootAnimations;
- QSet<QQuickAnimatorJob *> activeLeafAnimations;
-
- QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *> transforms;
-
- QSet<QQuickItem *> deletedSinceLastFrame;
-
- QQuickWindow *window;
-
- QMutex mutex;
+ // These are manipulated from the GUI thread and should only
+ // be updated during the sync() phase.
+ QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *> m_starting;
+ QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *> m_stopping;
+ QSet<QAbstractAnimationJob *> m_deleting;
+
+ QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *> m_animatorRoots;
+ QSet<QQuickAnimatorJob *> m_activeLeafAnimations;
+ QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *> m_transforms;
+ QSet<QQuickItem *> m_deletedSinceLastFrame;
+ QQuickWindow *m_window;
+ QMutex m_mutex;
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 78708bdf81..fa6f615649 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -72,8 +72,6 @@ QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObje
// be negligiblie compared to animating and re-rendering the scene on the render thread.
m_duration = -1;
- job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
-
QObject *ctx = findAnimationContext(m_animation);
if (!ctx) {
qWarning("QtQuick: unable to find animation context for RT animation...");
@@ -100,7 +98,7 @@ void QQuickAnimatorProxyJob::deleteJob()
{
if (m_job) {
if (m_controller && m_internalState != State_Starting)
- QCoreApplication::postEvent(m_controller, new QQuickAnimatorController::Event(m_job, QQuickAnimatorController::DeleteAnimation));
+ m_controller->deleteJob(m_job);
else if (m_internalState == State_Starting)
delete m_job;
m_job = 0;
@@ -122,18 +120,15 @@ void QQuickAnimatorProxyJob::updateCurrentTime(int)
void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
{
if (m_state == Running) {
- if (m_controller) {
- m_internalState = State_Running;
- startOnRenderThread();
- } else {
- m_internalState = State_Starting;
- }
+ m_internalState = State_Starting;
+ if (m_controller)
+ m_controller->startJob(this, m_job);
} else if (newState == Stopped) {
syncBackCurrentValues();
if (m_internalState == State_Starting)
m_internalState = State_Stopped;
else if (m_controller) {
- QCoreApplication::postEvent(m_controller, new QQuickAnimatorController::Event(m_job, QQuickAnimatorController::StopAnimation));
+ m_controller->stopJob(this, m_job);
}
}
}
@@ -143,23 +138,28 @@ void QQuickAnimatorProxyJob::windowChanged(QQuickWindow *window)
setWindow(window);
}
+void QQuickAnimatorProxyJob::controllerWasDeleted()
+{
+ m_controller = 0;
+ m_job = 0;
+}
+
void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window)
{
if (!window) {
- m_controller = 0;
// Stop will trigger syncBackCurrentValues so best to do it before
// we delete m_job.
stop();
deleteJob();
return;
- }
- m_controller = QQuickWindowPrivate::get(window)->animationController;
-
- if (window->openglContext())
- readyToAnimate();
- else
- connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(sceneGraphInitialized()));
+ } else if (!m_controller && m_job) {
+ m_controller = QQuickWindowPrivate::get(window)->animationController;
+ if (window->openglContext())
+ readyToAnimate();
+ else
+ connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(sceneGraphInitialized()));
+ }
}
void QQuickAnimatorProxyJob::sceneGraphInitialized()
@@ -170,36 +170,24 @@ void QQuickAnimatorProxyJob::sceneGraphInitialized()
void QQuickAnimatorProxyJob::readyToAnimate()
{
- if (m_internalState == State_Starting) {
- startOnRenderThread();
- }
+ if (m_internalState == State_Starting)
+ m_controller->startJob(this, m_job);
}
-void QQuickAnimatorProxyJob::animationFinished(QAbstractAnimationJob *job)
+void QQuickAnimatorProxyJob::startedByController()
{
- QCoreApplication::postEvent(this, new QQuickAnimatorController::Event(job, QQuickAnimatorController::AnimationFinished));
+ m_internalState = State_Running;
}
bool QQuickAnimatorProxyJob::event(QEvent *e)
{
- if ((uint) e->type() == QQuickAnimatorController::AnimationFinished) {
- // Update the duration of this proxy to the current time and stop it so
- // that parent animations can progress gracefully
+ if (e->type() == QEvent::User) {
stop();
return true;
}
-
return QObject::event(e);
}
-void QQuickAnimatorProxyJob::startOnRenderThread()
-{
- m_internalState = State_Running;
- // Force a "sync" pass as the newly started animation needs to sync properties from GUI.
- m_controller->startAnimation(m_job);
- QQuickWindowPrivate::get(m_controller->window)->dirtyItem(0);
-}
-
static void qquick_syncback_helper(QAbstractAnimationJob *job)
{
if (job->isRenderThreadJob()) {
@@ -216,7 +204,8 @@ static void qquick_syncback_helper(QAbstractAnimationJob *job)
void QQuickAnimatorProxyJob::syncBackCurrentValues()
{
- qquick_syncback_helper(m_job);
+ if (m_job)
+ qquick_syncback_helper(m_job);
}
QQuickAnimatorJob::QQuickAnimatorJob()
@@ -236,9 +225,9 @@ QQuickAnimatorJob::QQuickAnimatorJob()
qreal QQuickAnimatorJob::value() const
{
qreal v;
- m_controller->mutex.lock();
+ m_controller->lock();
v = m_value;
- m_controller->mutex.unlock();
+ m_controller->unlock();
return v;
}
@@ -258,21 +247,6 @@ void QQuickAnimatorJob::targetWasDeleted()
m_controller = 0;
}
-void QQuickAnimatorJob::updateState(State newState, State oldState)
-{
- if (!m_controller) {
- stop();
- return;
- }
-
- if (newState == Running) {
- m_controller->activeLeafAnimations << this;
- m_hasBeenRunning = true;
- } else if (oldState == Running) {
- m_controller->activeLeafAnimations.remove(this);
- }
-}
-
QQuickTransformAnimatorJob::QQuickTransformAnimatorJob()
: m_helper(0)
{
@@ -282,7 +256,7 @@ QQuickTransformAnimatorJob::QQuickTransformAnimatorJob()
QQuickTransformAnimatorJob::~QQuickTransformAnimatorJob()
{
if (m_helper && --m_helper->ref == 0) {
- m_controller->transforms.remove(m_helper->item);
+ m_controller->m_transforms.remove(m_helper->item);
delete m_helper;
}
}
@@ -292,11 +266,11 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
QQuickAnimatorJob::initialize(controller);
if (m_controller) {
- m_helper = m_controller->transforms.value(m_target);
+ m_helper = m_controller->m_transforms.value(m_target);
if (!m_helper) {
m_helper = new Helper();
m_helper->item = m_target;
- m_controller->transforms.insert(m_target, m_helper);
+ m_controller->m_transforms.insert(m_target, m_helper);
QObject::connect(m_target, SIGNAL(destroyed(QObject *)), m_controller, SLOT(itemDestroyed(QObject*)), Qt::DirectConnection);
} else {
++m_helper->ref;
@@ -307,16 +281,12 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
}
}
-QQuickTransformAnimatorJob::Helper::~Helper()
-{
-}
-
-
void QQuickTransformAnimatorJob::Helper::sync()
{
const quint32 mask = QQuickItemPrivate::Position
| QQuickItemPrivate::BasicTransform
- | QQuickItemPrivate::TransformOrigin;
+ | QQuickItemPrivate::TransformOrigin
+ | QQuickItemPrivate::Size;
QQuickItemPrivate *d = QQuickItemPrivate::get(item);
if (d->extra.isAllocated()
@@ -347,7 +317,7 @@ void QQuickTransformAnimatorJob::Helper::sync()
rotation = item->rotation();
}
- if (dirty & QQuickItemPrivate::TransformOrigin) {
+ if (dirty & (QQuickItemPrivate::TransformOrigin | QQuickItemPrivate::Size)) {
QPointF o = item->transformOriginPoint();
ox = o.x();
oy = o.y();
@@ -382,7 +352,7 @@ void QQuickXAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
m_helper->dx = m_value;
@@ -399,7 +369,7 @@ void QQuickYAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
m_helper->dy = m_value;
@@ -452,7 +422,7 @@ void QQuickOpacityAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
m_opacityNode->setOpacity(m_value);
@@ -468,7 +438,7 @@ void QQuickScaleAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
m_helper->scale = m_value;
@@ -488,7 +458,7 @@ void QQuickRotationAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
float t = m_easing.valueForProgress(time / (qreal) m_duration);
switch (m_direction) {
@@ -563,7 +533,7 @@ void QQuickUniformAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
if (!m_node || m_uniformIndex == -1 || m_uniformType == -1)
return;
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index bc9c65c347..8aae121106 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -63,7 +63,7 @@ class QQuickShaderEffectNode;
class QSGOpacityNode;
-class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorProxyJob : public QObject, public QAbstractAnimationJob, public QAnimationJobChangeListener
+class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorProxyJob : public QObject, public QAbstractAnimationJob
{
Q_OBJECT
@@ -73,7 +73,10 @@ public:
int duration() const { return m_duration; }
- virtual void animationFinished(QAbstractAnimationJob *);
+ QAbstractAnimationJob *job() const { return m_job; }
+
+ void startedByController();
+ void controllerWasDeleted();
protected:
bool event(QEvent *);
@@ -91,7 +94,6 @@ private:
void readyToAnimate();
void setWindow(QQuickWindow *window);
static QObject *findAnimationContext(QQuickAbstractAnimation *);
- void startOnRenderThread();
QQuickAnimatorController *m_controller;
QQuickAbstractAnimation *m_animation;
@@ -134,6 +136,7 @@ public:
bool isUniform() const { return m_isUniform; }
bool hasBeenRunning() const { return m_hasBeenRunning; }
+ void setHasBeenRunning(bool has) { m_hasBeenRunning = has; }
qreal value() const;
@@ -141,7 +144,6 @@ public:
protected:
QQuickAnimatorJob();
- void updateState(State newState, State oldState);
QQuickItem *m_target;
QQuickAnimatorController *m_controller;
@@ -180,8 +182,6 @@ public:
{
}
- ~Helper();
-
void sync();
void apply();
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index 53e3520bde..9e9e6cb419 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -242,6 +242,9 @@ qreal QSmoothedAnimation::easeFollow(qreal time_seconds)
void QSmoothedAnimation::updateCurrentTime(int t)
{
+ if (!isRunning() && !isPaused()) // This can happen if init() stops the animation in some cases
+ return;
+
qreal time_seconds = useDelta ? qreal(QQmlAnimationTimer::instance()->currentDelta()) / 1000. : qreal(t - lastTime) / 1000.;
if (useDelta)
useDelta = false;
@@ -351,7 +354,7 @@ void QSmoothedAnimation::init()
sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
variety of methods for creating animations.
- \sa SpringAnimation, NumberAnimation, {Animation and Transitions in Qt Quick}, {declarative/animation/basics}{Animation basics example}
+ \sa SpringAnimation, NumberAnimation, {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
*/
QQuickSmoothedAnimation::QQuickSmoothedAnimation(QObject *parent)
diff --git a/src/quick/util/qquickspringanimation.cpp b/src/quick/util/qquickspringanimation.cpp
index f663491a58..36aae36459 100644
--- a/src/quick/util/qquickspringanimation.cpp
+++ b/src/quick/util/qquickspringanimation.cpp
@@ -308,7 +308,8 @@ void QSpringAnimation::updateCurrentTime(int time)
QQmlPropertyPrivate::DontRemoveBinding);
if (stopped && old_to == to) { // do not stop if we got restarted
- stopTime = animationTemplate->elapsed.elapsed();
+ if (animationTemplate)
+ stopTime = animationTemplate->elapsed.elapsed();
stop();
}
}
@@ -365,7 +366,7 @@ void QQuickSpringAnimationPrivate::updateMode()
sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
variety of methods for creating animations.
- \sa SmoothedAnimation, {Animation and Transitions in Qt Quick}, {declarative/animation/basics}{Animation basics example}, {declarative/toys/clocks}{Clocks example}
+ \sa SmoothedAnimation, {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}, {Qt Quick Demo - Clocks}
*/
QQuickSpringAnimation::QQuickSpringAnimation(QObject *parent)
diff --git a/src/src.pro b/src/src.pro
index 758482304f..fb61d49ed9 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -14,3 +14,5 @@ SUBDIRS += \
plugins \
imports \
qmldevtools
+
+qmldevtools.CONFIG = host_build
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 09ab868367..8809693647 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -6,6 +6,8 @@ SUBDIRS=\
cmake \
installed_cmake
+qmldevtools.CONFIG = host_build
+
!mac {
SUBDIRS += \
quick \
diff --git a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
index a832c58ae3..5a1148e92e 100644
--- a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
+++ b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
@@ -211,19 +211,8 @@ void tst_QPauseAnimationJob::multiplePauseAnimations()
#endif
QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
- QTest::qWait(550);
-
-#ifdef Q_OS_WIN
- if (animation2.state() != QAbstractAnimationJob::Stopped)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped);
-
-#ifdef Q_OS_WIN
- if (animation2.m_updateCurrentTimeCount != 3)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QCOMPARE(animation2.m_updateCurrentTimeCount, 3);
+ QTRY_COMPARE(animation2.state(), QAbstractAnimationJob::Stopped);
+ QVERIFY(animation2.m_updateCurrentTimeCount >= 3);
}
void tst_QPauseAnimationJob::pauseAndPropertyAnimations()
@@ -240,19 +229,17 @@ void tst_QPauseAnimationJob::pauseAndPropertyAnimations()
QTest::qWait(100);
animation.start();
- QVERIFY(animation.state() == QAbstractAnimationJob::Running);
- QVERIFY(pause.state() == QAbstractAnimationJob::Running);
- QCOMPARE(pause.m_updateCurrentTimeCount, 2);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
- QTest::qWait(animation.totalDuration() + 100);
+ QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Running);
+ QVERIFY(pause.state() == QAbstractAnimationJob::Running);
+ QVERIFY2(pause.m_updateCurrentTimeCount >= 2,
+ QByteArrayLiteral("pause.m_updateCurrentTimeCount=") + QByteArray::number(pause.m_updateCurrentTimeCount));
-#ifdef Q_OS_WIN
- if (animation.state() != QAbstractAnimationJob::Stopped)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
- QVERIFY(pause.state() == QAbstractAnimationJob::Stopped);
- QVERIFY(pause.m_updateCurrentTimeCount > 3);
+ QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Stopped);
+ QCOMPARE(pause.state(), QAbstractAnimationJob::Stopped);
+ QVERIFY2(pause.m_updateCurrentTimeCount > 3,
+ QByteArrayLiteral("pause.m_updateCurrentTimeCount=") + QByteArray::number(pause.m_updateCurrentTimeCount));
}
void tst_QPauseAnimationJob::pauseResume()
@@ -260,19 +247,15 @@ void tst_QPauseAnimationJob::pauseResume()
TestablePauseAnimation animation;
animation.setDuration(400);
animation.start();
- QVERIFY(animation.state() == QAbstractAnimationJob::Running);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
QTest::qWait(200);
animation.pause();
- QVERIFY(animation.state() == QAbstractAnimationJob::Paused);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Paused);
animation.start();
QTest::qWait(300);
- QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
-
-#ifdef Q_OS_WIN
- if (animation.m_updateCurrentTimeCount != 3)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QCOMPARE(animation.m_updateCurrentTimeCount, 3);
+ QTRY_VERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY2(animation.m_updateCurrentTimeCount >= 3,
+ QByteArrayLiteral("animation.m_updateCurrentTimeCount=") + QByteArray::number(animation.m_updateCurrentTimeCount));
}
void tst_QPauseAnimationJob::sequentialPauseGroup()
@@ -423,7 +406,7 @@ void tst_QPauseAnimationJob::multipleSequentialGroups()
if (group.state() != QAbstractAnimationJob::Stopped)
QEXPECT_FAIL("", winTimerError, Abort);
#endif
- QVERIFY(group.state() == QAbstractAnimationJob::Stopped);
+ QTRY_VERIFY(group.state() == QAbstractAnimationJob::Stopped);
#ifdef Q_OS_WIN
if (subgroup1.state() != QAbstractAnimationJob::Stopped)
diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro
index 15abbcc7ab..aa3ad6a3a3 100644
--- a/tests/auto/qml/debugger/debugger.pro
+++ b/tests/auto/qml/debugger/debugger.pro
@@ -2,7 +2,7 @@ TEMPLATE = subdirs
PUBLICTESTS += \
qqmlenginedebugservice \
-# qqmldebugjs \
+ qqmldebugjs \
qpacketprotocol \
# qv8profilerservice \
# qdebugmessageservice \
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
index 9318372e2c..2fee7cfc92 100644
--- a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
+++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
@@ -48,7 +48,6 @@
#include <QtCore/QString>
#include <QtTest/QtTest>
-const char *ENABLE_DEBUG= "-enable-debugger";
const char *NORMALMODE = "-qmljsdebugger=port:3777,3787,block";
const char *QMLFILE = "test.qml";
@@ -183,7 +182,7 @@ void tst_QDebugMessageService::init()
m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml", this);
m_client = new QQmlDebugMsgClient(m_connection);
- m_process->start(QStringList() << QLatin1String(ENABLE_DEBUG) << QLatin1String(NORMALMODE) << QQmlDataTest::instance()->testFile(QMLFILE));
+ m_process->start(QStringList() << QLatin1String(NORMALMODE) << QQmlDataTest::instance()->testFile(QMLFILE));
QVERIFY2(m_process->waitForSessionStart(),
"Could not launch application, or did not get 'Waiting for connection'.");
diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
index 9bf2d8849e..2cf6ee958a 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
+++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -100,13 +100,10 @@ const char *SCOPES = "scopes";
const char *SCRIPTS = "scripts";
const char *SOURCE = "source";
const char *SETBREAKPOINT = "setbreakpoint";
-const char *CHANGEBREAKPOINT = "changebreakpoint";
const char *CLEARBREAKPOINT = "clearbreakpoint";
const char *SETEXCEPTIONBREAK = "setexceptionbreak";
-const char *V8FLAGS = "v8flags";
const char *VERSION = "version";
const char *DISCONNECT = "disconnect";
-const char *LISTBREAKPOINTS = "listbreakpoints";
const char *GARBAGECOLLECTOR = "gc";
//const char *PROFILE = "profile";
@@ -129,7 +126,6 @@ const char *UNCAUGHT = "uncaught";
//const char *PAUSE = "pause";
//const char *RESUME = "resume";
-const char *ENABLE_DEBUG= "-enable-debugger";//flag needed for debugger with qml binary
const char *BLOCKMODE = "-qmljsdebugger=port:3771,3800,block";
const char *NORMALMODE = "-qmljsdebugger=port:3771,3800";
const char *TEST_QMLFILE = "test.qml";
@@ -182,14 +178,8 @@ private slots:
void getVersion();
// void getVersionWhenAttaching();
- void applyV8Flags();
-
void disconnect();
- void gc();
-
- void listBreakpoints();
-
void setBreakpointInScriptOnCompleted();
void setBreakpointInScriptOnComponentCreated();
void setBreakpointInScriptOnTimerCallback();
@@ -197,21 +187,17 @@ private slots:
void setBreakpointInScriptOnComment();
void setBreakpointInScriptOnEmptyLine();
void setBreakpointInScriptOnOptimizedBinding();
- void setBreakpointInScriptWithCondition();
+// void setBreakpointInScriptWithCondition(); // Not supported yet.
void setBreakpointInScriptThatQuits();
//void setBreakpointInFunction(); //NOT SUPPORTED
- void setBreakpointOnEvent();
+// void setBreakpointOnEvent();
// void setBreakpointWhenAttaching();
- void changeBreakpoint();
- void changeBreakpointOnCondition();
-
void clearBreakpoint();
void setExceptionBreak();
void stepNext();
- void stepNextWithCount();
void stepIn();
void stepOut();
void continueDebugging();
@@ -222,15 +208,11 @@ private slots:
void getScopeDetails();
- void evaluateInGlobalScope();
- void evaluateInLocalScope();
-
- void getScopes();
+// void evaluateInGlobalScope(); // Not supported yet.
+// void evaluateInLocalScope(); // Not supported yet.
void getScripts();
- void getSource();
-
// void profile(); //NOT SUPPORTED
// void verifyQMLOptimizerDisabled();
@@ -277,25 +259,19 @@ public:
void connect();
void interrupt();
- void continueDebugging(StepAction stepAction, int stepCount = 1);
+ void continueDebugging(StepAction stepAction);
void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
void lookup(QList<int> handles, bool includeSource = false);
void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
void frame(int number = -1);
void scope(int number = -1, int frameNumber = -1);
- void scopes(int frameNumber = -1);
void scripts(int types = 4, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
- void source(int frame = -1, int fromLine = -1, int toLine = -1);
void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = true, QString condition = QString(), int ignoreCount = -1);
- void changeBreakpoint(int breakpoint, bool enabled = true, QString condition = QString(), int ignoreCount = -1);
void clearBreakpoint(int breakpoint);
void setExceptionBreak(Exception type, bool enabled = false);
- void v8flags(QString flags);
void version();
//void profile(ProfileCommand command); //NOT SUPPORTED
void disconnect();
- void gc();
- void listBreakpoints();
protected:
//inherited from QQmlDebugClient
@@ -338,7 +314,7 @@ void QJSDebugClient::interrupt()
sendMessage(packMessage(INTERRUPT));
}
-void QJSDebugClient::continueDebugging(StepAction action, int count)
+void QJSDebugClient::continueDebugging(StepAction action)
{
// { "seq" : <number>,
// "type" : "request",
@@ -362,8 +338,6 @@ void QJSDebugClient::continueDebugging(StepAction action, int count)
default:break;
}
if (!args.isUndefined()) {
- if (count != 1)
- args.setProperty(QLatin1String(STEPCOUNT),QJSValue(count));
jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
}
}
@@ -527,30 +501,6 @@ void QJSDebugClient::scope(int number, int frameNumber)
sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
}
-void QJSDebugClient::scopes(int frameNumber)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "scopes",
- // "arguments" : { "frameNumber" : <frame number, optional uses selected frame if missing>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SCOPES)));
-
- if (frameNumber != -1) {
- QJSValue args = parser.call(QJSValueList() << obj);
- args.setProperty(QLatin1String(FRAMENUMBER),QJSValue(frameNumber));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
void QJSDebugClient::scripts(int types, QList<int> ids, bool includeSource, QVariant /*filter*/)
{
// { "seq" : <number>,
@@ -595,39 +545,6 @@ void QJSDebugClient::scripts(int types, QList<int> ids, bool includeSource, QVar
sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
}
-void QJSDebugClient::source(int frame, int fromLine, int toLine)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "source",
- // "arguments" : { "frame" : <frame number (default selected frame)>
- // "fromLine" : <from line within the source default is line 0>
- // "toLine" : <to line within the source this line is not included in
- // the result default is the number of lines in the script>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SOURCE)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- if (frame != -1)
- args.setProperty(QLatin1String(FRAME),QJSValue(frame));
-
- if (fromLine != -1)
- args.setProperty(QLatin1String(FROMLINE),QJSValue(fromLine));
-
- if (toLine != -1)
- args.setProperty(QLatin1String(TOLINE),QJSValue(toLine));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
void QJSDebugClient::setBreakpoint(QString type, QString target, int line, int column, bool enabled, QString condition, int ignoreCount)
{
// { "seq" : <number>,
@@ -681,39 +598,6 @@ void QJSDebugClient::setBreakpoint(QString type, QString target, int line, int c
}
}
-void QJSDebugClient::changeBreakpoint(int breakpoint, bool enabled, QString condition, int ignoreCount)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "changebreakpoint",
- // "arguments" : { "breakpoint" : <number of the break point to clear>
- // "enabled" : <initial enabled state. True or false, default is true>
- // "condition" : <string with break point condition>
- // "ignoreCount" : <number specifying the number of break point hits }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(CHANGEBREAKPOINT)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- args.setProperty(QLatin1String(BREAKPOINT),QJSValue(breakpoint));
-
- args.setProperty(QLatin1String(ENABLED),QJSValue(enabled));
-
- if (!condition.isEmpty())
- args.setProperty(QLatin1String(CONDITION),QJSValue(condition));
-
- if (ignoreCount != -1)
- args.setProperty(QLatin1String(IGNORECOUNT),QJSValue(ignoreCount));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
void QJSDebugClient::clearBreakpoint(int breakpoint)
{
// { "seq" : <number>,
@@ -767,29 +651,6 @@ void QJSDebugClient::setExceptionBreak(Exception type, bool enabled)
sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
}
-void QJSDebugClient::v8flags(QString flags)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "v8flags",
- // "arguments" : { "flags" : <string: a sequence of v8 flags just like those used on the command line>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(V8FLAGS)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- args.setProperty(QLatin1String(FLAGS),QJSValue(flags));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
void QJSDebugClient::version()
{
// { "seq" : <number>,
@@ -842,42 +703,6 @@ void QJSDebugClient::disconnect()
sendMessage(packMessage(DISCONNECT, json.toString().toUtf8()));
}
-void QJSDebugClient::gc()
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "gc",
- // "arguments" : { "type" : <string: "all">,
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(GARBAGECOLLECTOR)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- args.setProperty(QLatin1String(TYPE),QJSValue(QLatin1String(ALL)));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::listBreakpoints()
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "listbreakpoints",
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(LISTBREAKPOINTS)));
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
void QJSDebugClient::stateChanged(State state)
{
if (state == Enabled) {
@@ -919,9 +744,7 @@ void QJSDebugClient::messageReceived(const QByteArray &data)
debugCommand == "lookup" ||
debugCommand == "setbreakpoint" ||
debugCommand == "evaluate" ||
- debugCommand == "listbreakpoints" ||
debugCommand == "version" ||
- debugCommand == "v8flags" ||
debugCommand == "disconnect" ||
debugCommand == "gc" ||
debugCommand == "changebreakpoint" ||
@@ -1010,13 +833,13 @@ void tst_QQmlDebugJS::cleanupTestCase()
bool tst_QQmlDebugJS::init(const QString &qmlFile, bool blockMode)
{
connection = new QQmlDebugConnection();
- process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml", this);
+ process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this);
client = new QJSDebugClient(connection);
if (blockMode)
- process->start(QStringList() << QLatin1String(ENABLE_DEBUG) << QLatin1String(BLOCKMODE) << testFile(qmlFile));
+ process->start(QStringList() << QLatin1String(BLOCKMODE) << testFile(qmlFile));
else
- process->start(QStringList() << QLatin1String(ENABLE_DEBUG) << QLatin1String(NORMALMODE) << testFile(qmlFile));
+ process->start(QStringList() << QLatin1String(NORMALMODE) << testFile(qmlFile));
if (!process->waitForSessionStart()) {
qDebug() << "could not launch application, or did not get 'Waiting for connection'.";
@@ -1104,17 +927,6 @@ void tst_QQmlDebugJS::getVersionWhenAttaching()
}
*/
-void tst_QQmlDebugJS::applyV8Flags()
-{
- //void v8flags(QString flags)
-
- QVERIFY(init());
- client->connect();
-
- client->v8flags(QString());
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
void tst_QQmlDebugJS::disconnect()
{
//void disconnect()
@@ -1126,45 +938,6 @@ void tst_QQmlDebugJS::disconnect()
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
}
-void tst_QQmlDebugJS::gc()
-{
- //void gc()
-
- QVERIFY(init());
- client->connect();
-
- client->gc();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::listBreakpoints()
-{
- //void listBreakpoints()
-
- int sourceLine1 = 53;
- int sourceLine2 = 54;
- int sourceLine3 = 55;
-
- QVERIFY(init());
- client->connect();
-
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TEST_QMLFILE), sourceLine1, -1, true);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TEST_QMLFILE), sourceLine2, -1, true);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TEST_QMLFILE), sourceLine3, -1, true);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
- client->listBreakpoints();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QList<QVariant> breakpoints = value.value("body").toMap().value("breakpoints").toList();
-
- QCOMPARE(breakpoints.count(), 3);
-}
-
void tst_QQmlDebugJS::setBreakpointInScriptOnCompleted()
{
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
@@ -1308,8 +1081,11 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
}
+#if 0
void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
{
+ QFAIL("conditional breakpoints are not yet supported");
+
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
int out = 10;
@@ -1340,6 +1116,7 @@ void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
QVERIFY(body.value("value").toInt() > out);
}
+#endif
void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
{
@@ -1396,8 +1173,11 @@ void tst_QQmlDebugJS::setBreakpointWhenAttaching()
// QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(QMLFILE));
//}
+#if 0
void tst_QQmlDebugJS::setBreakpointOnEvent()
{
+ QFAIL("Not implemented in V4.");
+
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
QVERIFY(init(TIMER_QMLFILE));
@@ -1414,97 +1194,7 @@ void tst_QQmlDebugJS::setBreakpointOnEvent()
QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(TIMER_QMLFILE));
}
-
-
-void tst_QQmlDebugJS::changeBreakpoint()
-{
- //void changeBreakpoint(int breakpoint, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
-
- int sourceLine1 = 50;
- int sourceLine2 = 51;
- QVERIFY(init(CHANGEBREAKPOINT_QMLFILE));
-
- client->connect();
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true);
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
-
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- //Will hit 1st brakpoint, change this breakpoint enable = false
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
- QList<QVariant> breakpointsHit = body.value("breakpoints").toList();
-
- int breakpoint = breakpointsHit.at(0).toInt();
- client->changeBreakpoint(breakpoint,false);
-
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-
- //Continue with debugging
- client->continueDebugging(QJSDebugClient::Continue);
- //Hit 2nd breakpoint
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- //Continue with debugging
- client->continueDebugging(QJSDebugClient::Continue);
- //Should stop at 2nd breakpoint
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- jsonString = client->response;
- value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
-}
-
-void tst_QQmlDebugJS::changeBreakpointOnCondition()
-{
- //void changeBreakpoint(int breakpoint, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
-
- int sourceLine1 = 50;
- int sourceLine2 = 51;
-
- QVERIFY(init(CHANGEBREAKPOINT_QMLFILE));
-
- client->connect();
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true);
-
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- //Will hit 1st brakpoint, change this breakpoint enable = false
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
- QList<QVariant> breakpointsHit = body.value("breakpoints").toList();
-
- int breakpoint = breakpointsHit.at(0).toInt();
- client->changeBreakpoint(breakpoint, false, QLatin1String("d == 0"));
-
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-
- //Continue with debugging
- client->continueDebugging(QJSDebugClient::Continue);
- //Hit 2nd breakpoint
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- //Continue with debugging
- client->continueDebugging(QJSDebugClient::Continue);
- //Should stop at 2nd breakpoint
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- jsonString = client->response;
- value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
-
-}
+#endif
void tst_QQmlDebugJS::clearBreakpoint()
{
@@ -1583,29 +1273,6 @@ void tst_QQmlDebugJS::stepNext()
QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
}
-void tst_QQmlDebugJS::stepNextWithCount()
-{
- //void continueDebugging(StepAction stepAction, int stepCount = 1);
-
- int sourceLine = 50;
- QVERIFY(init(STEPACTION_QMLFILE));
-
- client->connect();
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->continueDebugging(QJSDebugClient::Next, 2);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine + 2);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
-}
-
void tst_QQmlDebugJS::stepIn()
{
//void continueDebugging(StepAction stepAction, int stepCount = 1);
@@ -1724,6 +1391,7 @@ void tst_QQmlDebugJS::getScopeDetails()
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
}
+#if 0
void tst_QQmlDebugJS::evaluateInGlobalScope()
{
//void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
@@ -1742,7 +1410,9 @@ void tst_QQmlDebugJS::evaluateInGlobalScope()
QCOMPARE(body.value("text").toString(),QLatin1String("undefined"));
}
+#endif
+#if 0
void tst_QQmlDebugJS::evaluateInLocalScope()
{
//void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
@@ -1776,21 +1446,7 @@ void tst_QQmlDebugJS::evaluateInLocalScope()
QCOMPARE(body.value("value").toInt(),10);
}
-
-void tst_QQmlDebugJS::getScopes()
-{
- //void scopes(int frameNumber = -1);
-
- int sourceLine = 47;
- QVERIFY(init(ONCOMPLETED_QMLFILE));
-
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->scopes();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
+#endif
void tst_QQmlDebugJS::getScripts()
{
@@ -1798,7 +1454,9 @@ void tst_QQmlDebugJS::getScripts()
QVERIFY(init());
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QString(TEST_QMLFILE), 48, -1, true);
client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->scripts();
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(scriptsResult())));
@@ -1808,22 +1466,8 @@ void tst_QQmlDebugJS::getScripts()
QList<QVariant> scripts = value.value("body").toList();
- QCOMPARE(scripts.count(), 3);
-}
-
-void tst_QQmlDebugJS::getSource()
-{
- //void source(int frame = -1, int fromLine = -1, int toLine = -1);
-
- int sourceLine = 47;
- QVERIFY(init(ONCOMPLETED_QMLFILE));
-
- client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->source();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+ QCOMPARE(scripts.count(), 1);
+ QVERIFY(scripts.first().toMap()[QStringLiteral("name")].toString().endsWith(QStringLiteral("data/test.qml")));
}
QTEST_MAIN(tst_QQmlDebugJS)
diff --git a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
index 231e37c6fb..efb130d789 100644
--- a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
@@ -110,7 +110,7 @@ void tst_QQmlEngineDebugInspectorIntegration::init()
// ### Still using qmlscene because of QTBUG-33376
m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath)
+ "/qmlscene", this);
- m_process->start(QStringList() << QLatin1String("-enable-debugger") << argument << testFile("qtquick2.qml"));
+ m_process->start(QStringList() << argument << testFile("qtquick2.qml"));
QVERIFY2(m_process->waitForSessionStart(),
"Could not launch application, or did not get 'Waiting for connection'.");
diff --git a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
index 2eeb4ce5b2..6a9ecdfa73 100644
--- a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
+++ b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
@@ -91,7 +91,7 @@ void tst_QQmlInspector::startQmlsceneProcess(const char * /* qmlFile */)
// ### This should be using qml instead of qmlscene, but can't because of QTBUG-33376 (same as the XFAIL testcase)
m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this);
- m_process->start(QStringList() << QLatin1String("-enable-debugger") << argument << testFile("qtquick2.qml"));
+ m_process->start(QStringList() << argument << testFile("qtquick2.qml"));
QVERIFY2(m_process->waitForSessionStart(),
"Could not launch application, or did not get 'Waiting for connection'.");
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index 902e525dd6..f2b82db630 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -300,8 +300,6 @@ void tst_QQmlProfilerService::connect(bool block, const QString &testFile)
// ### Still using qmlscene due to QTBUG-33377
const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene";
QStringList arguments;
- arguments << QLatin1String("-enable-debugger");
-
if (block)
arguments << QString("-qmljsdebugger=port:" STR_PORT_FROM "," STR_PORT_TO ",block");
else
@@ -450,8 +448,9 @@ void tst_QQmlProfilerService::scenegraphData()
QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
m_client->setTraceState(true);
- QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
- QVERIFY(m_process->output().indexOf(QLatin1String("tick")) != -1);
+
+ while (!m_process->output().contains(QLatin1String("tick")))
+ QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
diff --git a/tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp b/tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp
index f0485fb68a..a461519c75 100644
--- a/tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp
+++ b/tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp
@@ -206,7 +206,6 @@ bool tst_QV8ProfilerService::connect(bool block, const QString &testFile,
{
const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml";
QStringList arguments;
- arguments << QLatin1String("-enable-debugger");
if (block)
arguments << QString("-qmljsdebugger=port:" STR_PORT_FROM "," STR_PORT_TO ",block");
diff --git a/tests/auto/qml/debugger/shared/qqmldebugclient.cpp b/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
index 95674ce6d7..6474a04796 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
+++ b/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
@@ -449,6 +449,7 @@ QString QQmlDebugClient::stateString() const
case Unavailable: return QLatin1String("Unavailable");
case Enabled: return QLatin1String("Enabled");
}
+ return QLatin1String("Invalid");
}
void QQmlDebugClient::sendMessage(const QByteArray &message)
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index 2b8da26dc9..e73edc812a 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -2206,7 +2206,7 @@ void tst_QJSValue::strictlyEquals()
{
QJSValue var1 = eng.toScriptValue(QVariant(QPoint(1, 2)));
QJSValue var2 = eng.toScriptValue(QVariant(QPoint(1, 2)));
- QVERIFY(!var1.strictlyEquals(var2));
+ QVERIFY(var1.strictlyEquals(var2));
}
{
QJSValue var1 = eng.toScriptValue(QVariant(QPoint(1, 2)));
diff --git a/tests/auto/qml/qqmlecmascript/data/idAsLValue.qml b/tests/auto/qml/qqmlecmascript/data/idAsLValue.qml
new file mode 100644
index 0000000000..1035f844b4
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/idAsLValue.qml
@@ -0,0 +1,7 @@
+import QtQml 2.0
+QtObject {
+ id: root
+ Component.onCompleted: {
+ root = "hello"
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/misctypetest.qml b/tests/auto/qml/qqmlecmascript/data/misctypetest.qml
new file mode 100644
index 0000000000..60ff53a2b4
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/misctypetest.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ MiscTypeTest {
+ id: mtt
+ }
+
+ function test_invalid_url_equal()
+ {
+ return mtt.invalidUrl() == mtt.invalidUrl();
+ }
+
+ function test_invalid_url_refequal()
+ {
+ return mtt.invalidUrl() === mtt.invalidUrl();
+ }
+
+ function test_valid_url_equal()
+ {
+ return mtt.validUrl() == mtt.validUrl();
+ }
+
+ function test_valid_url_refequal()
+ {
+ return mtt.validUrl() === mtt.validUrl();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug34792.qml b/tests/auto/qml/qqmlecmascript/data/qtbug34792.qml
new file mode 100644
index 0000000000..37c551b587
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug34792.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.1
+Rectangle {
+ function foo()
+ {
+ for (var i = 0; i < 1; i++)
+ {
+ if (i >= 0)
+ break
+
+ return
+ }
+
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_33754.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_33754.qml
new file mode 100644
index 0000000000..705334fbfa
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_33754.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ property int a: 0
+ property int b: 0
+
+ Component.onCompleted: {
+ for (var i = ((a > b) ? b : a); i < ((a > b) ? a : b); i++)
+ {
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_34493.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_34493.qml
new file mode 100644
index 0000000000..7e7d350aae
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_34493.qml
@@ -0,0 +1,19 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ function doIt() {
+ d.hello("World")
+ }
+
+ property QtObject subobject: QtObject {
+ id: d
+ function hello(input) {
+ var temp = "Hello " + input;
+ var input = temp + "!";
+ prop = input
+ }
+ }
+
+ property string prop
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml
index 962e8dd474..a3f306f717 100644
--- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml
@@ -72,4 +72,17 @@ Item {
if (!verifyExpected(msco.intListProperty, 4))
success = false;
}
+
+ function indexOf() {
+ if (msco.qstringListProperty.length != 4)
+ success = false;
+ if (msco.qstringListProperty.indexOf("first") != 0)
+ success = false;
+ if (msco.qstringListProperty.indexOf("second") != 1)
+ success = false;
+ if (msco.qstringListProperty.indexOf("third") != 2)
+ success = false;
+ if (msco.qstringListProperty.indexOf("fourth") != 3)
+ success = false;
+ }
}
diff --git a/tests/auto/qml/qqmlecmascript/data/setPropertyOnNull.qml b/tests/auto/qml/qqmlecmascript/data/setPropertyOnNull.qml
new file mode 100644
index 0000000000..a3288f47d7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/setPropertyOnNull.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.2
+
+QtObject {
+ Component.onCompleted: null.bug = 0
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/setPropertyOnUndefined.qml b/tests/auto/qml/qqmlecmascript/data/setPropertyOnUndefined.qml
new file mode 100644
index 0000000000..6655c47e5f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/setPropertyOnUndefined.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.2
+
+QtObject {
+ Component.onCompleted: undefined.bug = 0
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/singletonTest.qml b/tests/auto/qml/qqmlecmascript/data/singletonTest.qml
new file mode 100644
index 0000000000..6d296cd613
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/singletonTest.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Canonical Limited 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import Test 1.0
+
+Item {
+ property bool qobjectTest: MyInheritedQmlObjectSingleton.isItYouQObject(MyInheritedQmlObjectSingleton)
+ property bool myQmlObjectTest: MyInheritedQmlObjectSingleton.isItYouMyQmlObject(MyInheritedQmlObjectSingleton)
+ property bool myInheritedQmlObjectTest: MyInheritedQmlObjectSingleton.isItYouMyInheritedQmlObject(MyInheritedQmlObjectSingleton)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/singletonTest2.qml b/tests/auto/qml/qqmlecmascript/data/singletonTest2.qml
new file mode 100644
index 0000000000..ec457589de
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/singletonTest2.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Canonical Limited 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import Test 1.0
+
+Item {
+ property bool myInheritedQmlObjectTest1: false
+ property bool myInheritedQmlObjectTest2: false
+ property bool myInheritedQmlObjectTest3: false
+ property bool myQmlObjectTest1: false
+ property bool myQmlObjectTest2: false
+ property bool myQmlObjectTest3: false
+ property bool qobjectTest1: false
+ property bool qobjectTest2: false
+ property bool qobjectTest3: false
+ property bool singletonEqualToItself: true
+
+ Component.onCompleted: {
+ MyInheritedQmlObjectSingleton.myInheritedQmlObjectProperty = MyInheritedQmlObjectSingleton;
+ myInheritedQmlObjectTest1 = MyInheritedQmlObjectSingleton.myInheritedQmlObjectProperty == MyInheritedQmlObjectSingleton;
+ myInheritedQmlObjectTest2 = MyInheritedQmlObjectSingleton.myInheritedQmlObjectProperty == MyInheritedQmlObjectSingleton.myInheritedQmlObjectProperty;
+ myInheritedQmlObjectTest3 = MyInheritedQmlObjectSingleton == MyInheritedQmlObjectSingleton.myInheritedQmlObjectProperty;
+
+ MyInheritedQmlObjectSingleton.myQmlObjectProperty = MyInheritedQmlObjectSingleton;
+ myQmlObjectTest1 = MyInheritedQmlObjectSingleton.myQmlObjectProperty == MyInheritedQmlObjectSingleton;
+ myQmlObjectTest2 = MyInheritedQmlObjectSingleton.myQmlObjectProperty == MyInheritedQmlObjectSingleton.myQmlObjectProperty;
+ myQmlObjectTest3 = MyInheritedQmlObjectSingleton == MyInheritedQmlObjectSingleton.myQmlObjectProperty;
+
+ MyInheritedQmlObjectSingleton.qobjectProperty = MyInheritedQmlObjectSingleton;
+ qobjectTest1 = MyInheritedQmlObjectSingleton.qobjectProperty == MyInheritedQmlObjectSingleton;
+ qobjectTest2 = MyInheritedQmlObjectSingleton.qobjectProperty == MyInheritedQmlObjectSingleton.qobjectProperty;
+ qobjectTest3 = MyInheritedQmlObjectSingleton == MyInheritedQmlObjectSingleton.qobjectProperty;
+
+ singletonEqualToItself = MyInheritedQmlObjectSingleton == MyInheritedQmlObjectSingleton;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/thisObject.qml b/tests/auto/qml/qqmlecmascript/data/thisObject.qml
new file mode 100644
index 0000000000..c93d0302cf
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/thisObject.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+QtObject {
+ property int value: 1
+ property QtObject subObject: QtObject {
+ property int value: 2
+ property int test: {
+ return this.value;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/updateCall.qml b/tests/auto/qml/qqmlecmascript/data/updateCall.qml
new file mode 100644
index 0000000000..341a360d25
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/updateCall.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.1
+
+Rectangle {
+ MouseArea {
+ anchors.fill: parent;
+ Component.onCompleted: {
+ update();
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp
index a09bd9f3c6..41fa3672bd 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.cpp
+++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp
@@ -235,6 +235,21 @@ public:
}
};
+class MiscTypeTestClass : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE QUrl invalidUrl()
+ {
+ return QUrl();
+ }
+
+ Q_INVOKABLE QUrl validUrl()
+ {
+ return QUrl("http://wwww.qt-project.org");
+ }
+};
+
class MyStringClass : public QObject
{
Q_OBJECT
@@ -257,10 +272,34 @@ public:
}
};
+static MyInheritedQmlObject *theSingletonObject = 0;
+
+static QObject *inheritedQmlObject_provider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
+{
+ theSingletonObject = new MyInheritedQmlObject();
+ return theSingletonObject;
+}
+
+bool MyInheritedQmlObject::isItYouQObject(QObject *o)
+{
+ return o && o == theSingletonObject;
+}
+
+bool MyInheritedQmlObject::isItYouMyQmlObject(MyQmlObject *o)
+{
+ return o && o == theSingletonObject;
+}
+
+bool MyInheritedQmlObject::isItYouMyInheritedQmlObject(MyInheritedQmlObject *o)
+{
+ return o && o == theSingletonObject;
+}
+
void registerTypes()
{
qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObjectAlias");
qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObject");
+ qmlRegisterSingletonType<MyInheritedQmlObject>("Test", 1, 0, "MyInheritedQmlObjectSingleton", inheritedQmlObject_provider);
qmlRegisterType<MyDeferredObject>("Qt.test", 1,0, "MyDeferredObject");
qmlRegisterType<MyVeryDeferredObject>("Qt.test", 1,0, "MyVeryDeferredObject");
qmlRegisterType<MyQmlContainer>("Qt.test", 1,0, "MyQmlContainer");
@@ -329,6 +368,7 @@ void registerTypes()
qmlRegisterType<MyDateClass>("Qt.test", 1, 0, "MyDateClass");
qmlRegisterType<MyStringClass>("Qt.test", 1, 0, "MyStringClass");
+ qmlRegisterType<MiscTypeTestClass>("Qt.test", 1, 0, "MiscTypeTest");
qmlRegisterSingletonType<testImportOrderApi>("Qt.test.importOrderApi",1,0,"Data",testImportOrder_api);
qmlRegisterSingletonType<testImportOrderApi>("NamespaceAndType",1,0,"NamespaceAndType",testImportOrder_api);
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index 0fdcdafb95..556cc32fd3 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.h
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -291,6 +291,34 @@ Q_DECLARE_METATYPE(QQmlListProperty<MyQmlObject>)
QML_DECLARE_TYPEINFO(MyQmlObject, QML_HAS_ATTACHED_PROPERTIES)
+class MyInheritedQmlObject : public MyQmlObject
+{
+ Q_OBJECT
+ Q_PROPERTY(MyInheritedQmlObject *myInheritedQmlObjectProperty READ myInheritedQmlObject WRITE setMyInheritedQmlObject)
+ Q_PROPERTY(MyQmlObject *myQmlObjectProperty READ myQmlObject WRITE setMyQmlObject)
+ Q_PROPERTY(QObject *qobjectProperty READ qobject WRITE setQObject)
+public:
+ MyInheritedQmlObject() : m_myInheritedQmlObject(0), m_myQmlObject(0), m_qobject(0) {}
+
+ MyInheritedQmlObject *myInheritedQmlObject() const { return m_myInheritedQmlObject; }
+ void setMyInheritedQmlObject(MyInheritedQmlObject * o) { m_myInheritedQmlObject = o; }
+
+ MyQmlObject *myQmlObject() const { return m_myQmlObject; }
+ void setMyQmlObject(MyQmlObject * o) { m_myQmlObject = o; }
+
+ QObject *qobject() const { return m_qobject; }
+ void setQObject(QObject * o) { m_qobject = o; }
+
+ Q_INVOKABLE bool isItYouQObject(QObject *o);
+ Q_INVOKABLE bool isItYouMyQmlObject(MyQmlObject *o);
+ Q_INVOKABLE bool isItYouMyInheritedQmlObject(MyInheritedQmlObject *o);
+private:
+ MyInheritedQmlObject *m_myInheritedQmlObject;
+ MyQmlObject *m_myQmlObject;
+ QObject *m_qobject;
+};
+QML_DECLARE_TYPE(MyInheritedQmlObject)
+
class MyQmlContainer : public QObject
{
Q_OBJECT
@@ -993,7 +1021,7 @@ class MyRevisionedClass : public MyRevisionedBaseClassUnregistered
Q_PROPERTY(qreal prop2 READ prop2 WRITE setProp2 NOTIFY prop2Changed REVISION 1)
public:
- MyRevisionedClass() {}
+ MyRevisionedClass() : m_p1(0), m_p2(0) {}
qreal prop1() const { return m_p1; }
void setProp1(qreal p) {
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index e764ae783c..6b19c13109 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -304,9 +304,21 @@ private slots:
void propertyOverride();
void concatenatedStringPropertyAccess();
void jsOwnedObjectsDeletedOnEngineDestroy();
+ void updateCall();
void numberParsing();
void stringParsing();
+ void push_and_shift();
void qtbug_32801();
+ void thisObject();
+ void qtbug_33754();
+ void qtbug_34493();
+ void singletonFromQMLToCpp();
+ void singletonFromQMLAndBackAndCompare();
+ void setPropertyOnInvalid();
+ void miscTypeTest();
+ void stackLimits();
+ void idsAsLValues();
+ void qtbug_34792();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -1304,6 +1316,7 @@ void tst_qqmlecmascript::scope()
QVERIFY(object != 0);
QCOMPARE(object->property("test1").toBool(), true);
+ QEXPECT_FAIL("", "Properties resolvable at compile time come before the global object, which is not 100% compatible with older QML versions", Continue);
QCOMPARE(object->property("test2").toBool(), true);
QCOMPARE(object->property("test3").toBool(), true);
@@ -2257,15 +2270,16 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::ValueRef o, cons
QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->current;
QV4::Scope scope(ctx);
- try {
- QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
- if (!function)
- return false;
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- function->call(d);
- } catch (...) {
+ QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
+ if (scope.engine->hasException) {
+ ctx->catchException();
+ return true;
+ }
+ QV4::ScopedCallData d(scope, 1);
+ d->args[0] = o;
+ d->thisObject = engine->global();
+ function->call(d);
+ if (scope.engine->hasException) {
ctx->catchException();
return true;
}
@@ -2284,21 +2298,24 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::ValueRef o,
QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->current;
QV4::Scope scope(ctx);
- try {
- QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
- if (!function)
- return false;
-
- QV4::ScopedValue value(scope);
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- value = function->call(d);
- return __qmljs_strict_equal(value, result);
- } catch (...) {
+ QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
+ if (scope.engine->hasException) {
ctx->catchException();
+ return false;
}
- return false;
+ if (!function)
+ return false;
+
+ QV4::ScopedValue value(scope);
+ QV4::ScopedCallData d(scope, 1);
+ d->args[0] = o;
+ d->thisObject = engine->global();
+ value = function->call(d);
+ if (scope.engine->hasException) {
+ ctx->catchException();
+ return false;
+ }
+ return __qmljs_strict_equal(value, result);
}
static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::ValueRef o,
@@ -2312,18 +2329,23 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::ValueRef
QV4::Script program(QV8Engine::getV4(engine)->rootContext, functionSource);
program.inheritContext = true;
- try {
- QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
- if (!function)
- return QV4::Encode::undefined();
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- return function->call(d);
- } catch (...) {
+
+ QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
+ if (scope.engine->hasException) {
+ ctx->catchException();
+ return QV4::Encode::undefined();
+ }
+ if (!function)
+ return QV4::Encode::undefined();
+ QV4::ScopedCallData d(scope, 1);
+ d->args[0] = o;
+ d->thisObject = engine->global();
+ QV4::ScopedValue result(scope, function->call(d));
+ if (scope.engine->hasException) {
ctx->catchException();
+ return QV4::Encode::undefined();
}
- return QV4::Encode::undefined();
+ return result.asReturnedValue();
}
#define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
@@ -3479,9 +3501,9 @@ void tst_qqmlecmascript::compiled()
QCOMPARE(object->property("test15").toBool(), false);
QCOMPARE(object->property("test16").toBool(), true);
- QCOMPARE(object->property("test17").toInt(), 5);
+ QCOMPARE(object->property("test17").toInt(), 4);
QCOMPARE(object->property("test18").toReal(), qreal(176));
- QCOMPARE(object->property("test19").toInt(), 7);
+ QCOMPARE(object->property("test19").toInt(), 6);
QCOMPARE(object->property("test20").toReal(), qreal(6.7));
QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
@@ -3506,7 +3528,7 @@ void tst_qqmlecmascript::numberAssignment()
QCOMPARE(object->property("test3"), QVariant((qreal)6));
QCOMPARE(object->property("test4"), QVariant((qreal)6));
- QCOMPARE(object->property("test5"), QVariant((int)7));
+ QCOMPARE(object->property("test5"), QVariant((int)6));
QCOMPARE(object->property("test6"), QVariant((int)7));
QCOMPARE(object->property("test7"), QVariant((int)6));
QCOMPARE(object->property("test8"), QVariant((int)6));
@@ -3880,15 +3902,15 @@ void tst_qqmlecmascript::singletonTypeResolution()
void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) {
QQmlContextData *childCtxt = ctxt->childContexts;
- if (!ctxt->importedScripts.isEmpty()) {
+ if (!ctxt->importedScripts.isNullOrUndefined()) {
QV8Engine *engine = QV8Engine::get(ctxt->engine);
- foreach (const QV4::PersistentValue& qmlglobal, ctxt->importedScripts) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Scope scope(v4);
+ QV4::ScopedArrayObject scripts(scope, ctxt->importedScripts);
+ QV4::ScopedValue qml(scope);
+ for (quint32 i = 0; i < scripts->arrayLength(); ++i) {
QQmlContextData *scriptContext, *newContext;
-
- if (qmlglobal.isUndefined())
- continue;
- QV4::Scope scope(QV8Engine::getV4((engine)));
- QV4::ScopedValue qml(scope, qmlglobal.value());
+ qml = scripts->getIndexed(i);
scriptContext = QV4::QmlContextWrapper::getContext(qml);
qml = QV4::Encode::undefined();
@@ -3900,7 +3922,7 @@ void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) {
}
engine->gc();
- qml = qmlglobal.value();
+ qml = scripts->getIndexed(i);
newContext = QV4::QmlContextWrapper::getContext(qml);
QVERIFY(scriptContext == newContext);
}
@@ -5411,6 +5433,8 @@ void tst_qqmlecmascript::sequenceConversionIndexes()
QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
QMetaObject::invokeMethod(object, "indexedAccess");
QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "indexOf");
+ QVERIFY(object->property("success").toBool());
delete object;
}
@@ -6435,7 +6459,7 @@ void tst_qqmlecmascript::realToInt()
QMetaObject::invokeMethod(object, "test1");
QCOMPARE(object->value(), int(4));
QMetaObject::invokeMethod(object, "test2");
- QCOMPARE(object->value(), int(8));
+ QCOMPARE(object->value(), int(7));
}
void tst_qqmlecmascript::urlProperty()
@@ -7261,6 +7285,17 @@ void tst_qqmlecmascript::jsOwnedObjectsDeletedOnEngineDestroy()
delete object;
}
+void tst_qqmlecmascript::updateCall()
+{
+ // update is a slot on QQuickItem. Even though it's not
+ // documented it can be called from within QML. Make sure
+ // we don't crash when calling it.
+ QString file("updateCall.qml");
+ QQmlComponent component(&engine, testFileUrl(file));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+}
+
void tst_qqmlecmascript::numberParsing()
{
for (int i = 1; i < 8; ++i) {
@@ -7289,6 +7324,18 @@ void tst_qqmlecmascript::stringParsing()
}
}
+void tst_qqmlecmascript::push_and_shift()
+{
+ QJSEngine e;
+ const QString program =
+ "var array = []; "
+ "for (var i = 0; i < 10000; i++) {"
+ " array.push(5); array.unshift(5); array.push(5);"
+ "}"
+ "array.length;";
+ QVERIFY(e.evaluate(program).toNumber() == 30000);
+}
+
void tst_qqmlecmascript::qtbug_32801()
{
QQmlComponent component(&engine, testFileUrl("qtbug_32801.qml"));
@@ -7301,6 +7348,149 @@ void tst_qqmlecmascript::qtbug_32801()
QVERIFY(QMetaObject::invokeMethod(obj.data(), "emitTestSignal"));
}
+void tst_qqmlecmascript::thisObject()
+{
+ QQmlComponent component(&engine, testFileUrl("thisObject.qml"));
+ QObject *object = component.create();
+ QVERIFY(object);
+ QCOMPARE(qvariant_cast<QObject*>(object->property("subObject"))->property("test").toInt(), 2);
+ delete object;
+}
+
+void tst_qqmlecmascript::qtbug_33754()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_33754.qml"));
+
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != 0);
+}
+
+void tst_qqmlecmascript::qtbug_34493()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_34493.qml"));
+
+ QScopedPointer<QObject> obj(component.create());
+ if (component.errors().size())
+ qDebug() << component.errors();
+ QVERIFY(component.errors().isEmpty());
+ QVERIFY(obj != 0);
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "doIt"));
+ QTRY_VERIFY(obj->property("prop").toString() == QLatin1String("Hello World!"));
+}
+
+// Check that a Singleton can be passed from QML to C++
+// as its type*, it's parent type* and as QObject*
+void tst_qqmlecmascript::singletonFromQMLToCpp()
+{
+ QQmlComponent component(&engine, testFile("singletonTest.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (component.errors().size())
+ qDebug() << component.errors();
+ QVERIFY(component.errors().isEmpty());
+ QVERIFY(obj != 0);
+
+ QCOMPARE(obj->property("qobjectTest"), QVariant(true));
+ QCOMPARE(obj->property("myQmlObjectTest"), QVariant(true));
+ QCOMPARE(obj->property("myInheritedQmlObjectTest"), QVariant(true));
+}
+
+// Check that a Singleton can be passed from QML to C++
+// as its type*, it's parent type* and as QObject*
+// and correctly compares to itself
+void tst_qqmlecmascript::singletonFromQMLAndBackAndCompare()
+{
+ QQmlComponent component(&engine, testFile("singletonTest2.qml"));
+ QScopedPointer<QObject> o(component.create());
+ if (component.errors().size())
+ qDebug() << component.errors();
+ QVERIFY(component.errors().isEmpty());
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("myInheritedQmlObjectTest1"), QVariant(true));
+ QCOMPARE(o->property("myInheritedQmlObjectTest2"), QVariant(true));
+ QCOMPARE(o->property("myInheritedQmlObjectTest3"), QVariant(true));
+
+ QCOMPARE(o->property("myQmlObjectTest1"), QVariant(true));
+ QCOMPARE(o->property("myQmlObjectTest2"), QVariant(true));
+ QCOMPARE(o->property("myQmlObjectTest3"), QVariant(true));
+
+ QCOMPARE(o->property("qobjectTest1"), QVariant(true));
+ QCOMPARE(o->property("qobjectTest2"), QVariant(true));
+ QCOMPARE(o->property("qobjectTest3"), QVariant(true));
+
+ QCOMPARE(o->property("singletonEqualToItself"), QVariant(true));
+}
+
+void tst_qqmlecmascript::setPropertyOnInvalid()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("setPropertyOnNull.qml"));
+ QString warning = component.url().toString() + ":4: TypeError: Type error";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+ QObject *object = component.create();
+ QVERIFY(object);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("setPropertyOnUndefined.qml"));
+ QString warning = component.url().toString() + ":4: TypeError: Type error";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+ QObject *object = component.create();
+ QVERIFY(object);
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::miscTypeTest()
+{
+ QQmlComponent component(&engine, testFileUrl("misctypetest.qml"));
+
+ QObject *object = component.create();
+ if (object == 0)
+ qDebug() << component.errorString();
+ QVERIFY(object != 0);
+
+ QVariant q;
+ QMetaObject::invokeMethod(object, "test_invalid_url_equal", Q_RETURN_ARG(QVariant, q));
+ QVERIFY(q.toBool() == true);
+ QMetaObject::invokeMethod(object, "test_invalid_url_strictequal", Q_RETURN_ARG(QVariant, q));
+ QVERIFY(q.toBool() == true);
+ QMetaObject::invokeMethod(object, "test_valid_url_equal", Q_RETURN_ARG(QVariant, q));
+ QVERIFY(q.toBool() == true);
+ QMetaObject::invokeMethod(object, "test_valid_url_strictequal", Q_RETURN_ARG(QVariant, q));
+ QVERIFY(q.toBool() == true);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::stackLimits()
+{
+ QJSEngine engine;
+ engine.evaluate(QStringLiteral("function foo() {foo();} try {foo()} catch(e) { }"));
+}
+
+void tst_qqmlecmascript::idsAsLValues()
+{
+ QString err = QString(QLatin1String("%1:5 left-hand side of assignment operator is not an lvalue\n")).arg(testFileUrl("idAsLValue.qml").toString());
+ QQmlComponent component(&engine, testFileUrl("idAsLValue.qml"));
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(!object);
+ QCOMPARE(component.errorString(), err);
+}
+
+void tst_qqmlecmascript::qtbug_34792()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug34792.qml"));
+
+ QObject *object = component.create();
+ if (object == 0)
+ qDebug() << component.errorString();
+ QVERIFY(object != 0);
+ delete object;
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlengine/data/interception/imports/Test.2/qmldir b/tests/auto/qml/qqmlengine/data/interception/imports/Test.2/qmldir
new file mode 100644
index 0000000000..971812c162
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/imports/Test.2/qmldir
@@ -0,0 +1 @@
+This qmldir file is intentionally invalid, as the URL interception should prevent it being accessed.
diff --git a/tests/auto/qml/qqmlengine/data/interception/module/intercepted/Intercepted.qml b/tests/auto/qml/qqmlengine/data/interception/module/intercepted/Intercepted.qml
new file mode 100644
index 0000000000..5416ef5dcc
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/module/intercepted/Intercepted.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+QtObject {
+ property url filePath: "doesNotExist.file"
+ property url resolvedUrl: Qt.resolvedUrl("doesNotExist.file");
+ property url absoluteUrl: Qt.resolvedUrl("file:///doesNotExist.file");
+ property string childString: "intercepted"
+ property string scriptString: "intercepted"
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/module/intercepted/comment b/tests/auto/qml/qqmlengine/data/interception/module/intercepted/comment
new file mode 100644
index 0000000000..b10233e48d
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/module/intercepted/comment
@@ -0,0 +1 @@
+Note that the paths are relative the the qmldir file in the actual module path, not the intercepted qmldir file
diff --git a/tests/auto/qml/qqmlengine/data/interception/module/intercepted/qmldir b/tests/auto/qml/qqmlengine/data/interception/module/intercepted/qmldir
new file mode 100644
index 0000000000..c5457b232a
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/module/intercepted/qmldir
@@ -0,0 +1 @@
+TestObject 2.0 ../../module/intercepted/Intercepted.qml
diff --git a/tests/auto/qml/qqmlengine/data/interception/module/urlInterceptor.qml b/tests/auto/qml/qqmlengine/data/interception/module/urlInterceptor.qml
new file mode 100644
index 0000000000..b79a783582
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/module/urlInterceptor.qml
@@ -0,0 +1,3 @@
+import Test 2.0 //This import will be intercepted to make this file valid
+
+TestObject {}
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 42e17d5624..382bfe4b73 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -54,7 +54,7 @@
#include <QQmlExpression>
#include <QQmlIncubationController>
#include <private/qqmlengine_p.h>
-#include <QQmlAbstractUrlInterceptor>
+#include <private/qqmlabstracturlinterceptor_p.h>
class tst_qqmlengine : public QQmlDataTest
{
@@ -680,6 +680,7 @@ void tst_qqmlengine::qtqmlModule()
class CustomSelector : public QQmlAbstractUrlInterceptor
{
public:
+ CustomSelector(const QUrl &base):m_base(base){}
virtual QUrl intercept(const QUrl &url, QQmlAbstractUrlInterceptor::DataType d)
{
if (url.scheme() != QStringLiteral("file"))
@@ -687,6 +688,9 @@ public:
if (!m_interceptionPoints.contains(d))
return url;
+ if (url.path().endsWith("Test.2/qmldir"))//Special case
+ return QUrl::fromLocalFile(m_base.path() + "interception/module/intercepted/qmldir");
+
QString alteredPath = url.path();
int a = alteredPath.lastIndexOf('/');
if (a < 0)
@@ -698,6 +702,7 @@ public:
return ret;
}
QList<QQmlAbstractUrlInterceptor::DataType> m_interceptionPoints;
+ QUrl m_base;
};
Q_DECLARE_METATYPE(QList<QQmlAbstractUrlInterceptor::DataType>);
@@ -729,6 +734,15 @@ void tst_qqmlengine::urlInterceptor_data()
<< testFileUrl("interception/qmldir/intercepted/doesNotExist.file").toString()
<< QStringLiteral("file:///intercepted/doesNotExist.file");
+ QTest::newRow("InterceptModule")//just a Test{}, needs to intercept the module import for it to work
+ << testFileUrl("interception/module/urlInterceptor.qml")
+ << (QList<QQmlAbstractUrlInterceptor::DataType>() << QQmlAbstractUrlInterceptor::QmldirFile )
+ << testFileUrl("interception/module/intercepted/doesNotExist.file").toString()
+ << QStringLiteral("intercepted")
+ << QStringLiteral("intercepted")
+ << testFileUrl("interception/module/intercepted/doesNotExist.file").toString()
+ << QStringLiteral("file:///doesNotExist.file");
+
QTest::newRow("InterceptStrings")
<< testFileUrl("interception/strings/urlInterceptor.qml")
<< (QList<QQmlAbstractUrlInterceptor::DataType>() << QQmlAbstractUrlInterceptor::UrlString)
@@ -751,7 +765,8 @@ void tst_qqmlengine::urlInterceptor()
QFETCH(QString, expectedAbsoluteUrl);
QQmlEngine e;
- CustomSelector cs;
+ e.setImportPathList(QStringList() << testFileUrl("interception/imports").toLocalFile());
+ CustomSelector cs(testFileUrl(""));
cs.m_interceptionPoints = interceptionPoint;
e.setUrlInterceptor(&cs);
QQmlComponent c(&e, testFile); //Note that this can get intercepted too
diff --git a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
index a583fd0c4c..a9c1c11549 100644
--- a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
+++ b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
@@ -43,6 +43,7 @@
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlFileSelector>
+#include <QQmlApplicationEngine>
#include <QFileSelector>
#include <QQmlContext>
#include <qqmlinfo.h>
@@ -56,17 +57,30 @@ public:
private slots:
void basicTest();
+ void applicationEngineTest();
};
void tst_qqmlfileselector::basicTest()
{
QQmlEngine engine;
- QFileSelector selector;
+ QQmlFileSelector selector(&engine);
selector.setExtraSelectors(QStringList() << "basic");
- QQmlFileSelector qmlSelector;
- qmlSelector.setSelector(&selector);
- engine.setUrlInterceptor(&qmlSelector);
+
+ QQmlComponent component(&engine, testFileUrl("basicTest.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("value").toString(), QString("selected"));
+
+ delete object;
+}
+
+void tst_qqmlfileselector::applicationEngineTest()
+{
+ QQmlApplicationEngine engine;
+ QQmlFileSelector* selector = QQmlFileSelector::get(&engine);
+ QVERIFY(selector != 0);
+ selector->setExtraSelectors(QStringList() << "basic");
QQmlComponent component(&engine, testFileUrl("basicTest.qml"));
QObject *object = component.create();
diff --git a/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml b/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml
new file mode 100644
index 0000000000..5dd322b5f5
--- /dev/null
+++ b/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml
@@ -0,0 +1,18 @@
+import QtQml 2.1
+import QtQuick 2.1
+
+Rectangle {
+ Instantiator {
+ objectName: "instantiator1"
+ model: model1
+ delegate: QtObject {
+ property string datum: model.text
+ }
+ }
+ Component.onCompleted: {
+ model1.add("Delta");
+ model1.add("Gamma");
+ model1.add("Beta");
+ model1.add("Alpha");
+ }
+}
diff --git a/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro b/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
index aa83da1509..719fd6c350 100644
--- a/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
+++ b/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
@@ -4,6 +4,7 @@ macx:CONFIG -= app_bundle
INCLUDEPATH += ../../shared/
SOURCES += tst_qqmlinstantiator.cpp
+HEADERS += stringmodel.h
include (../../shared/util.pri)
diff --git a/tests/auto/qml/qqmlinstantiator/stringmodel.h b/tests/auto/qml/qqmlinstantiator/stringmodel.h
new file mode 100644
index 0000000000..c66aa5886a
--- /dev/null
+++ b/tests/auto/qml/qqmlinstantiator/stringmodel.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Dmitrii Kosarev aka Kakadu <kakadu.hafanana@gmail.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$
+**
+****************************************************************************/
+#ifndef STRINGMODEL_H
+#define STRINGMODEL_H
+
+#include <QtCore/QObject>
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QDebug>
+
+class StringModel : public QAbstractItemModel
+{
+ Q_OBJECT
+ QVector<QString> items;
+ QHash<int, QByteArray> roles;
+ QString name;
+
+public:
+ explicit StringModel(const QString& name) : QAbstractItemModel(), name(name)
+ {
+ roles.insert(555, "text");
+ }
+
+ void drop(int count)
+ {
+ beginRemoveRows(QModelIndex(), 0, count-1);
+ for (int i=0; i<count; i++)
+ items.pop_front();
+ endRemoveRows();
+ }
+
+ Q_INVOKABLE void add(QString s)
+ {
+ beginInsertRows(QModelIndex(), 0, 0);
+ items.push_front(s);
+ endInsertRows();
+ }
+
+ int rowCount(const QModelIndex &) const
+ {
+ return items.count();
+ }
+
+ virtual QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE
+ {
+ return roles;
+ }
+
+ virtual int columnCount(const QModelIndex &) const
+ {
+ return 1;
+ }
+
+ virtual bool hasChildren(const QModelIndex &) const Q_DECL_OVERRIDE
+ {
+ return rowCount(QModelIndex()) > 0;
+ }
+
+ virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
+ {
+ Q_UNUSED(column);
+ if (row>=0 && row<rowCount(parent))
+ return createIndex(row,0);
+ else
+ return QModelIndex();
+ }
+
+ virtual QModelIndex parent(const QModelIndex &) const
+ {
+ return QModelIndex();
+ }
+
+ QVariant data (const QModelIndex & index, int role) const
+ {
+ int row = index.row();
+ if ((row<0) || (row>=items.count()))
+ return QVariant::Invalid;
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case 555:
+ return QVariant::fromValue(items.at(row));
+ default:
+ return QVariant();
+ }
+ }
+};
+
+#endif // STRINGMODEL_H
diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
index 3e90eb2cbe..1b31e55e2d 100644
--- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
+++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
@@ -45,7 +45,9 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/private/qqmlinstantiator_p.h>
+#include <QtQml/qqmlcontext.h>
#include "../../shared/util.h"
+#include "stringmodel.h"
class tst_qqmlinstantiator: public QQmlDataTest
{
@@ -58,6 +60,7 @@ private slots:
void stringModel();
void activeProperty();
void intModelChange();
+ void createAndRemove();
};
void tst_qqmlinstantiator::createNone()
@@ -193,6 +196,27 @@ void tst_qqmlinstantiator::intModelChange()
}
}
+void tst_qqmlinstantiator::createAndRemove()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("createAndRemove.qml"));
+ StringModel *model = new StringModel("model1");
+ engine.rootContext()->setContextProperty("model1", model);
+ QObject *rootObject = component.create();
+ QVERIFY(rootObject != 0);
+
+ QQmlInstantiator *instantiator =
+ qobject_cast<QQmlInstantiator*>(rootObject->findChild<QObject*>("instantiator1"));
+ QVERIFY(instantiator != 0);
+ model->drop(1);
+ QVector<QString> names;
+ names << "Beta" << "Gamma" << "Delta";
+ for (int i=0; i<3; i++) {
+ QObject *object = instantiator->objectAt(i);
+ QVERIFY(object);
+ QCOMPARE(object->property("datum").toString(), names[i]);
+ }
+}
QTEST_MAIN(tst_qqmlinstantiator)
#include "tst_qqmlinstantiator.moc"
diff --git a/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp b/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp
index a119607769..0cd4360e67 100644
--- a/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp
+++ b/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp
@@ -63,7 +63,6 @@ private slots:
void rectf();
void vector3d();
void vector4d();
- void time();
};
void tst_qqmlinstruction::dump()
@@ -688,12 +687,6 @@ void tst_qqmlinstruction::vector4d()
QCOMPARE(vector.w(), (qreal)(float)121.1);
}
-void tst_qqmlinstruction::time()
-{
- QCOMPARE(sizeof(QQmlInstruction::instr_storeTime::QTime), sizeof(QTime));
- QCOMPARE(Q_ALIGNOF(QQmlInstruction::instr_storeTime::QTime), Q_ALIGNOF(QTime));
-}
-
QTEST_MAIN(tst_qqmlinstruction)
#include "tst_qqmlinstruction.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/singleton/+basicSelector/SingletonType.qml b/tests/auto/qml/qqmllanguage/data/singleton/+basicSelector/SingletonType.qml
new file mode 100644
index 0000000000..3e289aed1a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/singleton/+basicSelector/SingletonType.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+pragma Singleton
+
+Item {
+ id: singletonId
+
+ property int testProp1: 625
+ property int testProp2: 525
+ property int testProp3: 455
+}
diff --git a/examples/quick/demos/samegame/content/settings.js b/tests/auto/qml/qqmllanguage/data/singleton/RegisteredCompositeSingletonType.qml
index e09dee9af3..cdc531ef0d 100644
--- a/examples/quick/demos/samegame/content/settings.js
+++ b/tests/auto/qml/qqmllanguage/data/singleton/RegisteredCompositeSingletonType.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2012 Research In Motion
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the examples of the Qt Toolkit.
@@ -38,19 +38,21 @@
**
****************************************************************************/
-.pragma library
+import QtQuick 2.0
+pragma Singleton
-//This should be switched over once a proper QML settings API exists
+Item {
+ id: singletonId
-var menuDelay = 500
+ property int testProp1: 925
+ property int testProp2: 825
+ property int testProp3: 755
-var headerHeight = 20 // 70 on BB10
-var footerHeight = 44 // 100 on BB10
+ width: 25; height: 25
-var fontPixelSize = 14 // 55 on BB10
-
-var blockSize = 32 // 64 on BB10
-
-var toolButtonHeight = 32 // 64 on BB10
-
-var menuButtonSpacing = 0 // 15 on BB10
+ Rectangle {
+ id: rectangle
+ border.color: "white"
+ anchors.fill: parent
+ }
+} \ No newline at end of file
diff --git a/examples/quick/demos/samegame/content/+blackberry/settings.js b/tests/auto/qml/qqmllanguage/data/singletonTest17.qml
index a86d2a9a1a..655e9d5a78 100644
--- a/examples/quick/demos/samegame/content/+blackberry/settings.js
+++ b/tests/auto/qml/qqmllanguage/data/singletonTest17.qml
@@ -38,19 +38,12 @@
**
****************************************************************************/
-.pragma library
+import QtQuick 2.0
+import org.qtproject.Test 1.0
-//This should be switched over once a proper QML settings API exists
+Item {
+ id: test
-var menuDelay = 500
-
-var headerHeight = 70
-var footerHeight = 100
-
-var fontPixelSize = 55
-
-var blockSize = 64
-
-var toolButtonHeight = 64
-
-var menuButtonSpacing = 15
+ property int value1: RegisteredSingleton.testProp1;
+ property string value2: "Test value: " + RegisteredSingleton.testProp3;
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 65afdb06d2..621061ab6a 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -49,6 +49,8 @@
#include <QtCore/qdir.h>
#include <QSignalSpy>
#include <QFont>
+#include <QQmlFileSelector>
+#include <QFileSelector>
#include <private/qqmlproperty_p.h>
#include <private/qqmlmetatype_p.h>
@@ -209,6 +211,8 @@ private slots:
void compositeSingletonQmlDirError();
void compositeSingletonRemote();
void compositeSingletonJavaScriptPragma();
+ void compositeSingletonSelectors();
+ void compositeSingletonRegistered();
private:
QQmlEngine engine;
@@ -2844,6 +2848,9 @@ void tst_qqmllanguage::initTestCase()
QFile out(testFileUrl(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")).toLocalFile());
QVERIFY2(out.open(QIODevice::WriteOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(out.fileName(), out.errorString())));
out.write(in.readAll());
+
+ // Register a Composite Singleton.
+ qmlRegisterSingletonType(testFileUrl("singleton/RegisteredCompositeSingletonType.qml"), "org.qtproject.Test", 1, 0, "RegisteredSingleton");
}
void tst_qqmllanguage::aliasPropertyChangeSignals()
@@ -3501,6 +3508,32 @@ void tst_qqmllanguage::compositeSingletonJavaScriptPragma()
verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", 333);
}
+// Reads values from a Singleton accessed through selectors.
+void tst_qqmllanguage::compositeSingletonSelectors()
+{
+ QQmlEngine e2;
+ QQmlFileSelector qmlSelector(&e2);
+ qmlSelector.setExtraSelectors(QStringList() << "basicSelector");
+ QQmlComponent component(&e2, testFile("singletonTest1.qml"));
+ VERIFY_ERRORS(0);
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ verifyCompositeSingletonPropertyValues(o, "value1", 625, "value2", 455);
+}
+
+// Reads values from a Singleton that was registered through the C++ API:
+// qmlRegisterSingletonType.
+void tst_qqmllanguage::compositeSingletonRegistered()
+{
+ QQmlComponent component(&engine, testFile("singletonTest17.qml"));
+ VERIFY_ERRORS(0);
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
index 8e3626ddf2..d565ad557c 100644
--- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
+++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
@@ -910,7 +910,7 @@ void tst_qqmllocale::dateToLocaleTimeStringFormatted()
Q_ARG(QVariant, QVariant(format)));
QLocale l(locale);
- QCOMPARE(val.toString(), l.toString(dt.time(), format));
+ QCOMPARE(val.toString(), l.toString(dt, format));
}
void tst_qqmllocale::dateFromLocaleString_data()
diff --git a/tests/auto/qml/qqmlmoduleplugin/.gitignore b/tests/auto/qml/qqmlmoduleplugin/.gitignore
index b458285566..040a48c25f 100644
--- a/tests/auto/qml/qqmlmoduleplugin/.gitignore
+++ b/tests/auto/qml/qqmlmoduleplugin/.gitignore
@@ -1,2 +1,2 @@
imports/*/*/*
-!imports/com/nokia/PureQmlModule/*
+!imports/org/qtproject/PureQmlModule/*
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.2.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.2.qml
index a0ac0c72c7..97732d35d8 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.2.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.2.qml
@@ -1,4 +1,4 @@
-import com.nokia.AutoTestQmlMixedPluginType 1.5
+import org.qtproject.AutoTestQmlMixedPluginType 1.5
import QtQuick 2.0
Item {
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.qml
index 1346cbdb7b..f09c29b5a8 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/importsMixedQmlCppPlugin.qml
@@ -1,4 +1,4 @@
-import com.nokia.AutoTestQmlMixedPluginType 1.0
+import org.qtproject.AutoTestQmlMixedPluginType 1.0
import QtQuick 2.0
Item {
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.errors.txt b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.errors.txt
index 262193788b..de75f47c03 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.errors.txt
+++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.errors.txt
@@ -1 +1 @@
-1:1:module "com.nokia.AutoTestQmlNestedPluginType.Nested" is not installed
+1:1:module "org.qtproject.AutoTestQmlNestedPluginType.Nested" is not installed
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.qml
index b3f9ac6c3f..35fff29a69 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.qml
@@ -1,5 +1,5 @@
-import com.nokia.AutoTestQmlNestedPluginType.Nested 1.0
-import com.nokia.AutoTestQmlNestedPluginType 1.0
+import org.qtproject.AutoTestQmlNestedPluginType.Nested 1.0
+import org.qtproject.AutoTestQmlNestedPluginType 1.0
MyNestedPluginType {
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.2.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.2.qml
index cb8e0e33d1..ed4ddf2a1a 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.2.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.2.qml
@@ -1,5 +1,5 @@
-import com.nokia.AutoTestQmlNestedPluginType 1.0
-import com.nokia.AutoTestQmlNestedPluginType.Nested 1.0
+import org.qtproject.AutoTestQmlNestedPluginType 1.0
+import org.qtproject.AutoTestQmlNestedPluginType.Nested 1.0
MyNestedPluginType {
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.qml
index 69c6a34f46..b3dbf1741e 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.qml
@@ -1,4 +1,4 @@
-import com.nokia.AutoTestQmlNestedPluginType 1.0
+import org.qtproject.AutoTestQmlNestedPluginType 1.0
MyNestedPluginType {
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.errors.txt b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.errors.txt
index 9743ae4f68..0e92fce154 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.errors.txt
+++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.errors.txt
@@ -1 +1 @@
-2:1:module "com.nokia.AutoTestQmlNestedPluginType.Nested" version 6.66 is not installed
+2:1:module "org.qtproject.AutoTestQmlNestedPluginType.Nested" version 6.66 is not installed
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.qml
index dce8b7564a..32a4385fbf 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.qml
@@ -1,5 +1,5 @@
-import com.nokia.AutoTestQmlNestedPluginType 1.0
-import com.nokia.AutoTestQmlNestedPluginType.Nested 6.66
+import org.qtproject.AutoTestQmlNestedPluginType 1.0
+import org.qtproject.AutoTestQmlNestedPluginType.Nested 6.66
MyNestedPluginType {
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/incorrectCase.qml b/tests/auto/qml/qqmlmoduleplugin/data/incorrectCase.qml
index a21ece7058..86504269fa 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/incorrectCase.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/incorrectCase.qml
@@ -1,4 +1,4 @@
-import com.nokia.WrongCase 1.0
+import org.qtproject.WrongCase 1.0
MyPluginType { value: 123 }
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/pluginWithQmlFile.qml b/tests/auto/qml/qqmlmoduleplugin/data/pluginWithQmlFile.qml
index a9e28e5d8b..237c49d8eb 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/pluginWithQmlFile.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/pluginWithQmlFile.qml
@@ -1,3 +1,3 @@
-import com.nokia.AutoTestPluginWithQmlFile 1.0
+import org.qtproject.AutoTestPluginWithQmlFile 1.0
MyQmlFile {}
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.errors.txt b/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.errors.txt
index a40c1c8211..8790d4e545 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.errors.txt
+++ b/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.errors.txt
@@ -1 +1 @@
-1:1:module "com.nokia.AutoTestQmlVersionPluginType" version 1.9 is not installed
+1:1:module "org.qtproject.AutoTestQmlVersionPluginType" version 1.9 is not installed
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.qml b/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.qml
index bda59f0a32..28351cf7f9 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.2.qml
@@ -1,4 +1,4 @@
-import com.nokia.AutoTestQmlVersionPluginType 1.9
+import org.qtproject.AutoTestQmlVersionPluginType 1.9
import QtQuick 2.0
QtObject {
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.errors.txt b/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.errors.txt
index 2634223de7..f6b502e99c 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.errors.txt
+++ b/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.errors.txt
@@ -1 +1 @@
-1:1:module "com.nokia.AutoTestQmlVersionPluginType" version 1.1 is not installed
+1:1:module "org.qtproject.AutoTestQmlVersionPluginType" version 1.1 is not installed
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.qml b/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.qml
index 2e556e76d6..9f599c5c15 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/versionNotInstalled.qml
@@ -1,4 +1,4 @@
-import com.nokia.AutoTestQmlVersionPluginType 1.1
+import org.qtproject.AutoTestQmlVersionPluginType 1.1
import QtQuick 2.0
QtObject {
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/works.qml b/tests/auto/qml/qqmlmoduleplugin/data/works.qml
index f29ae24ea2..58f5212b90 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/works.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/works.qml
@@ -1,3 +1,3 @@
-import com.nokia.AutoTestQmlPluginType 1.0
+import org.qtproject.AutoTestQmlPluginType 1.0
MyPluginType { value: 123 }
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/works2.qml b/tests/auto/qml/qqmlmoduleplugin/data/works2.qml
index cc322bf26b..c3a21e0d16 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/works2.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/works2.qml
@@ -1,3 +1,3 @@
-import com.nokia.AutoTestQmlPluginType 2.0
+import org.qtproject.AutoTestQmlPluginType 2.0
MyPluginType { valueOnlyIn2: 123 }
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/works21.qml b/tests/auto/qml/qqmlmoduleplugin/data/works21.qml
index c08160ac5a..939cea8bc7 100644
--- a/tests/auto/qml/qqmlmoduleplugin/data/works21.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/data/works21.qml
@@ -1,3 +1,3 @@
-import com.nokia.AutoTestQmlPluginType 2.1
+import org.qtproject.AutoTestQmlPluginType 2.1
MyPluginType { valueOnlyIn2: 123 }
diff --git a/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/ComponentA.qml b/tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/ComponentA.qml
index 617bdaaf67..617bdaaf67 100644
--- a/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/ComponentA.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/ComponentA.qml
diff --git a/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/ComponentB.qml b/tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/ComponentB.qml
index fac5d8f4b9..fac5d8f4b9 100644
--- a/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/ComponentB.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/ComponentB.qml
diff --git a/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/qmldir
index 167bb10c21..167bb10c21 100644
--- a/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/PureQmlModule/qmldir
+++ b/tests/auto/qml/qqmlmoduleplugin/imports/org/qtproject/PureQmlModule/qmldir
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/invalidFirstCommandModule.pro b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/invalidFirstCommandModule.pro
index 8e37a2d16b..9a6ee63b88 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/invalidFirstCommandModule.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/invalidFirstCommandModule.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/InvalidFirstCommandModule
+DESTDIR = ../imports/org/qtproject/InvalidFirstCommandModule
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp
index 925f3cdf86..f8f1386e84 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp
@@ -61,8 +61,8 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.InvalidFirstCommandModule");
- qmlRegisterType<MyPluginType>("com.nokia.InvalidFirstCommandModule", 1, 0, "MyPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.InvalidFirstCommandModule");
+ qmlRegisterType<MyPluginType>("org.qtproject.InvalidFirstCommandModule", 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/qmldir
index 90b607e793..9ecbf14516 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/qmldir
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/qmldir
@@ -1,3 +1,3 @@
plugin invalidNamespaceModule
-module com.nokia.InvalidFirstCommandModule
+module org.qtproject.InvalidFirstCommandModule
# comment.
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/invalidNamespaceModule.pro b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/invalidNamespaceModule.pro
index b53ae1f9c3..002f177cfd 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/invalidNamespaceModule.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/invalidNamespaceModule.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/InvalidNamespaceModule
+DESTDIR = ../imports/org/qtproject/InvalidNamespaceModule
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp
index 0ed1b20446..edf524a240 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp
@@ -61,8 +61,8 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.InvalidStrictModule");
- qmlRegisterType<MyPluginType>("com.nokia.SomeOtherModule", 1, 0, "MyPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.InvalidStrictModule");
+ qmlRegisterType<MyPluginType>("org.qtproject.SomeOtherModule", 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/qmldir
index 5f349709f2..051e88d46e 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/qmldir
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/qmldir
@@ -1,2 +1,2 @@
-module com.nokia.AwesomeModule
+module org.qtproject.AwesomeModule
plugin invalidNamespaceModule
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro
index a348d5d6a6..562d109179 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/InvalidStrictModule
+DESTDIR = ../imports/org/qtproject/InvalidStrictModule
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp
index 0ed1b20446..edf524a240 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp
@@ -61,8 +61,8 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.InvalidStrictModule");
- qmlRegisterType<MyPluginType>("com.nokia.SomeOtherModule", 1, 0, "MyPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.InvalidStrictModule");
+ qmlRegisterType<MyPluginType>("org.qtproject.SomeOtherModule", 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir
index 45752a9bca..20716dc9f9 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir
@@ -1,2 +1,2 @@
-module com.nokia.InvalidStrictModule
+module org.qtproject.InvalidStrictModule
plugin invalidStrictModule
diff --git a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp
index 8b434dfb12..edd5577335 100644
--- a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp
@@ -76,7 +76,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.AutoTestQmlNestedPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlNestedPluginType");
qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType");
QString nestedUri(uri);
diff --git a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.pro b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.pro
index a2e582a604..5636941951 100644
--- a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += nestedPlugin
SOURCES = nestedPlugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/AutoTestQmlNestedPluginType
+DESTDIR = ../imports/org/qtproject/AutoTestQmlNestedPluginType
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/nonstrictModule.pro b/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/nonstrictModule.pro
index 5ad1bd5eca..0d900eb707 100644
--- a/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/nonstrictModule.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/nonstrictModule.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/NonstrictModule
+DESTDIR = ../imports/org/qtproject/NonstrictModule
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp
index 1cdd0f7754..f6db5bf9ea 100644
--- a/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp
@@ -61,10 +61,10 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.NonstrictModule");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.NonstrictModule");
// Install into a namespace that should be protected
- qmlRegisterType<MyPluginType>("com.nokia.StrictModule", 1, 0, "MyPluginType");
+ qmlRegisterType<MyPluginType>("org.qtproject.StrictModule", 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.2.1.pro b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.2.1.pro
index 560450832c..445b98d647 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.2.1.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.2.1.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/AutoTestQmlPluginType.2.1
+DESTDIR = ../imports/org/qtproject/AutoTestQmlPluginType.2.1
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp
index 6b5c38f29a..360f387310 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp
@@ -76,7 +76,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.AutoTestQmlPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlPluginType");
qmlRegisterType<MyPluginType>(uri, 2, 1, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.2.pro b/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.2.pro
index ed70708e1d..00c076d9cf 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.2.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.2.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/AutoTestQmlPluginType.2
+DESTDIR = ../imports/org/qtproject/AutoTestQmlPluginType.2
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp
index 12e31a4cb8..41c6987462 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp
@@ -76,7 +76,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.AutoTestQmlPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlPluginType");
qmlRegisterType<MyPluginType>(uri, 2, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp
index ee07c77e2f..59f7fa1082 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp
@@ -75,7 +75,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.AutoTestQmlPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlPluginType");
qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.pro b/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.pro
index b78e85c86b..3a0455569e 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/AutoTestQmlPluginType
+DESTDIR = ../imports/org/qtproject/AutoTestQmlPluginType
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp
index 4512f9a642..bce746afd4 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginMixed/plugin.cpp
@@ -65,7 +65,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.AutoTestQmlMixedPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlMixedPluginType");
qmlRegisterType<BarPluginType>(uri, 1, 0, "Bar");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginMixed/pluginMixed.pro b/tests/auto/qml/qqmlmoduleplugin/pluginMixed/pluginMixed.pro
index 9076c3ebab..d3b237b0f7 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginMixed/pluginMixed.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginMixed/pluginMixed.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/AutoTestQmlMixedPluginType
+DESTDIR = ../imports/org/qtproject/AutoTestQmlMixedPluginType
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp
index dfe2262e36..1ac546c39f 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginVersion/plugin.cpp
@@ -65,7 +65,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.AutoTestQmlVersionPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlVersionPluginType");
qmlRegisterType<FloorPluginType>(uri, 1, 4, "Floor");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginVersion/pluginVersion.pro b/tests/auto/qml/qqmlmoduleplugin/pluginVersion/pluginVersion.pro
index ba07180953..5cec9b8ebd 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginVersion/pluginVersion.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginVersion/pluginVersion.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/AutoTestQmlVersionPluginType
+DESTDIR = ../imports/org/qtproject/AutoTestQmlVersionPluginType
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp
index 34cf311b6b..9f8af9e5fa 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/plugin.cpp
@@ -51,7 +51,7 @@ class MyPlugin : public QQmlExtensionPlugin
public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.AutoTestPluginWithQmlFile");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestPluginWithQmlFile");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/pluginWithQmlFile.pro b/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/pluginWithQmlFile.pro
index 8cb40456cf..ba66d60f18 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/pluginWithQmlFile.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginWithQmlFile/pluginWithQmlFile.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/AutoTestPluginWithQmlFile
+DESTDIR = ../imports/org/qtproject/AutoTestPluginWithQmlFile
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp
index 3daba28b3d..96a61fa8c4 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp
@@ -75,7 +75,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.WrongCase");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.WrongCase");
qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/pluginWrongCase.pro b/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/pluginWrongCase.pro
index 0e3757b6ca..99bac141de 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/pluginWrongCase.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/pluginWrongCase.pro
@@ -3,7 +3,7 @@ CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
TARGET = Plugin
-DESTDIR = ../imports/com/nokia/WrongCase
+DESTDIR = ../imports/org/qtproject/WrongCase
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp
index 1b73f02934..11c75a8dd5 100644
--- a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp
@@ -61,7 +61,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.PreemptedStrictModule");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.PreemptedStrictModule");
qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/preemptedStrictModule.pro b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/preemptedStrictModule.pro
index 0aab522d04..22926bf1ca 100644
--- a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/preemptedStrictModule.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/preemptedStrictModule.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/PreemptedStrictModule
+DESTDIR = ../imports/org/qtproject/PreemptedStrictModule
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/qmldir
index c82acd2fd3..28deed1561 100644
--- a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/qmldir
+++ b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/qmldir
@@ -1,2 +1,2 @@
-module com.nokia.PreemptedStrictModule
+module org.qtproject.PreemptedStrictModule
plugin preemptedStrictModule
diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp
index 3a62650b13..35e8670509 100644
--- a/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp
@@ -61,11 +61,11 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.PreemptiveModule");
- qmlRegisterType<MyPluginType>("com.nokia.PreemptiveModule", 1, 0, "MyPluginType");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.PreemptiveModule");
+ qmlRegisterType<MyPluginType>("org.qtproject.PreemptiveModule", 1, 0, "MyPluginType");
// Install into another namespace that should be protected
- qmlRegisterType<MyPluginType>("com.nokia.PreemptedStrictModule", 1, 0, "MyPluginType");
+ qmlRegisterType<MyPluginType>("org.qtproject.PreemptedStrictModule", 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/preemptiveModule.pro b/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/preemptiveModule.pro
index 5bb6520b80..c07f0621f7 100644
--- a/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/preemptiveModule.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/preemptiveModule.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/PreemptiveModule
+DESTDIR = ../imports/org/qtproject/PreemptiveModule
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp
index 8353c6b012..e2849f8b64 100644
--- a/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp
@@ -61,7 +61,7 @@ public:
void registerTypes(const char *uri)
{
- Q_ASSERT(QLatin1String(uri) == "com.nokia.StrictModule");
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.StrictModule");
qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType");
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/strictModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/strictModule/qmldir
index ff06446fbd..26c408587d 100644
--- a/tests/auto/qml/qqmlmoduleplugin/strictModule/qmldir
+++ b/tests/auto/qml/qqmlmoduleplugin/strictModule/qmldir
@@ -1,2 +1,2 @@
-module com.nokia.StrictModule
+module org.qtproject.StrictModule
plugin strictModule
diff --git a/tests/auto/qml/qqmlmoduleplugin/strictModule/strictModule.pro b/tests/auto/qml/qqmlmoduleplugin/strictModule/strictModule.pro
index 7b818c0481..bf1c5df1a7 100644
--- a/tests/auto/qml/qqmlmoduleplugin/strictModule/strictModule.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/strictModule/strictModule.pro
@@ -2,7 +2,7 @@ TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
-DESTDIR = ../imports/com/nokia/StrictModule
+DESTDIR = ../imports/org/qtproject/StrictModule
QT += core-private gui-private qml-private
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index 147bdb6ffb..a6d9fb5601 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -142,7 +142,7 @@ void tst_qqmlmoduleplugin::importsPlugin()
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin created");
QTest::ignoreMessage(QtWarningMsg, "import worked");
- QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
@@ -159,7 +159,7 @@ void tst_qqmlmoduleplugin::importsPlugin2()
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin2 created");
QTest::ignoreMessage(QtWarningMsg, "import2 worked");
- QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works2.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
@@ -176,7 +176,7 @@ void tst_qqmlmoduleplugin::importsPlugin21()
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin2.1 created");
QTest::ignoreMessage(QtWarningMsg, "import2.1 worked");
- QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works21.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
@@ -197,21 +197,21 @@ void tst_qqmlmoduleplugin::incorrectPluginCase()
QList<QQmlError> errors = component.errors();
QCOMPARE(errors.count(), 1);
+ QString expectedError = QLatin1String("module \"org.qtproject.WrongCase\" plugin \"PluGin\" not found");
+
#if defined(Q_OS_MAC) || defined(Q_OS_WIN32)
+ bool caseSensitive = true;
#if defined(Q_OS_MAC)
+ caseSensitive = pathconf(QDir::currentPath().toLatin1().constData(), _PC_CASE_SENSITIVE);
QString libname = "libPluGin.dylib";
#elif defined(Q_OS_WIN32)
+ caseSensitive = false;
QString libname = "PluGin.dll";
#endif
- QString expectedError = QLatin1String("plugin cannot be loaded for module \"com.nokia.WrongCase\": File name case mismatch for \"") + QDir(m_importsDirectory).filePath("com/nokia/WrongCase/" + libname) + QLatin1String("\"");
-#else
- QString expectedError = QLatin1String("module \"com.nokia.WrongCase\" plugin \"PluGin\" not found");
+ if (!caseSensitive)
+ expectedError = QLatin1String("plugin cannot be loaded for module \"org.qtproject.WrongCase\": File name case mismatch for \"") + QDir(m_importsDirectory).filePath("org/qtproject/WrongCase/" + libname) + QLatin1String("\"");
#endif
-#ifdef Q_OS_OSX
- if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_8)
- QEXPECT_FAIL("", "See QTBUG-32652", Continue);
-#endif
QCOMPARE(errors.at(0).description(), expectedError);
}
@@ -229,7 +229,7 @@ void tst_qqmlmoduleplugin::importPluginWithQmlFile()
QQmlEngine engine;
engine.addImportPath(path);
- QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestPluginWithQmlFile' does not contain a module identifier directive - it cannot be protected from external registrations.");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestPluginWithQmlFile' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("pluginWithQmlFile.qml")));
foreach (QQmlError err, component.errors())
@@ -248,7 +248,7 @@ void tst_qqmlmoduleplugin::remoteImportWithQuotedUrl()
QQmlEngine engine;
QQmlComponent component(&engine);
- component.setData("import \"" SERVER_ADDR "/com/nokia/PureQmlModule\" \nComponentA { width: 300; ComponentB{} }", QUrl());
+ component.setData("import \"" SERVER_ADDR "/org/qtproject/PureQmlModule\" \nComponentA { width: 300; ComponentB{} }", QUrl());
QTRY_COMPARE(component.status(), QQmlComponent::Ready);
QObject *object = component.create();
@@ -270,7 +270,7 @@ void tst_qqmlmoduleplugin::remoteImportWithUnquotedUri()
QQmlEngine engine;
engine.addImportPath(m_dataImportsDirectory);
QQmlComponent component(&engine);
- component.setData("import com.nokia.PureQmlModule 1.0 \nComponentA { width: 300; ComponentB{} }", QUrl());
+ component.setData("import org.qtproject.PureQmlModule 1.0 \nComponentA { width: 300; ComponentB{} }", QUrl());
QTRY_COMPARE(component.status(), QQmlComponent::Ready);
@@ -291,7 +291,7 @@ void tst_qqmlmoduleplugin::importsMixedQmlCppPlugin()
QQmlEngine engine;
engine.addImportPath(m_importsDirectory);
- QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlMixedPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlMixedPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
{
QQmlComponent component(&engine, testFileUrl(QStringLiteral("importsMixedQmlCppPlugin.qml")));
@@ -334,7 +334,7 @@ void tst_qqmlmoduleplugin::versionNotInstalled()
static int count = 0;
if (++count == 1)
- QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlVersionPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlVersionPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(file));
VERIFY_ERRORS(errorFile.toLatin1().constData());
@@ -406,7 +406,7 @@ void tst_qqmlmoduleplugin::importsNested()
static int count = 0;
if (++count == 1)
- QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlNestedPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlNestedPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFile(file));
QObject *obj = component.create();
@@ -506,38 +506,38 @@ void tst_qqmlmoduleplugin::importStrictModule_data()
QTest::addColumn<QString>("error");
QTest::newRow("success")
- << "import com.nokia.StrictModule 1.0\n"
+ << "import org.qtproject.StrictModule 1.0\n"
"MyPluginType {}"
<< QString()
<< QString();
QTest::newRow("wrong target")
- << "import com.nokia.InvalidStrictModule 1.0\n"
+ << "import org.qtproject.InvalidStrictModule 1.0\n"
"MyPluginType {}"
<< QString()
- << ":1:1: plugin cannot be loaded for module \"com.nokia.InvalidStrictModule\": Cannot install element 'MyPluginType' into unregistered namespace 'com.nokia.SomeOtherModule'";
+ << ":1:1: plugin cannot be loaded for module \"org.qtproject.InvalidStrictModule\": Cannot install element 'MyPluginType' into unregistered namespace 'org.qtproject.SomeOtherModule'";
QTest::newRow("non-strict clash")
- << "import com.nokia.NonstrictModule 1.0\n"
+ << "import org.qtproject.NonstrictModule 1.0\n"
"MyPluginType {}"
- << "Module 'com.nokia.NonstrictModule' does not contain a module identifier directive - it cannot be protected from external registrations."
- << ":1:1: plugin cannot be loaded for module \"com.nokia.NonstrictModule\": Cannot install element 'MyPluginType' into protected namespace 'com.nokia.StrictModule'";
+ << "Module 'org.qtproject.NonstrictModule' does not contain a module identifier directive - it cannot be protected from external registrations."
+ << ":1:1: plugin cannot be loaded for module \"org.qtproject.NonstrictModule\": Cannot install element 'MyPluginType' into protected namespace 'org.qtproject.StrictModule'";
QTest::newRow("non-strict preemption")
- << "import com.nokia.PreemptiveModule 1.0\n"
- "import com.nokia.PreemptedStrictModule 1.0\n"
+ << "import org.qtproject.PreemptiveModule 1.0\n"
+ "import org.qtproject.PreemptedStrictModule 1.0\n"
"MyPluginType {}"
- << "Module 'com.nokia.PreemptiveModule' does not contain a module identifier directive - it cannot be protected from external registrations."
- << ":2:1: plugin cannot be loaded for module \"com.nokia.PreemptedStrictModule\": Namespace 'com.nokia.PreemptedStrictModule' has already been used for type registration";
+ << "Module 'org.qtproject.PreemptiveModule' does not contain a module identifier directive - it cannot be protected from external registrations."
+ << ":2:1: plugin cannot be loaded for module \"org.qtproject.PreemptedStrictModule\": Namespace 'org.qtproject.PreemptedStrictModule' has already been used for type registration";
QTest::newRow("invalid namespace")
- << "import com.nokia.InvalidNamespaceModule 1.0\n"
+ << "import org.qtproject.InvalidNamespaceModule 1.0\n"
"MyPluginType {}"
<< QString()
- << ":1:1: plugin cannot be loaded for module \"com.nokia.InvalidNamespaceModule\": Module namespace 'com.nokia.AwesomeModule' does not match import URI 'com.nokia.InvalidNamespaceModule'";
+ << ":1:1: plugin cannot be loaded for module \"org.qtproject.InvalidNamespaceModule\": Module namespace 'org.qtproject.AwesomeModule' does not match import URI 'org.qtproject.InvalidNamespaceModule'";
QTest::newRow("module directive must be first")
- << "import com.nokia.InvalidFirstCommandModule 1.0\n"
+ << "import org.qtproject.InvalidFirstCommandModule 1.0\n"
"MyPluginType {}"
<< QString()
<< ":1:1: module identifier directive must be the first directive in a qmldir file";
diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
index fa3b190826..f1b48df437 100644
--- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
+++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
@@ -98,6 +98,7 @@ public:
void verifyReceiverCount()
{
+ //Note: QTBUG-34829 means we can't call this from within disconnectNotify or it can lock
QCOMPARE(receivers(SIGNAL(qmlObjectPropChanged())), qmlObjectPropConnections);
QCOMPARE(receivers(SIGNAL(cppObjectPropChanged())), cppObjectPropConnections);
QCOMPARE(receivers(SIGNAL(unboundPropChanged())), unboundPropConnections);
@@ -134,7 +135,6 @@ protected:
if (signal.name() == "scriptBindingPropChanged") scriptBindingPropConnections--;
if (signal.name() == "boundSignal") boundSignalConnections--;
if (signal.name() == "unusedSignal") unusedSignalConnections--;
- verifyReceiverCount();
//qDebug() << Q_FUNC_INFO << this << signal.methodSignature();
}
@@ -205,6 +205,7 @@ void tst_qqmlnotifier::createObjects()
exportedClass = qobject_cast<ExportedClass *>(
root->findChild<ExportedClass*>("exportedClass"));
QVERIFY(exportedClass != 0);
+ exportedClass->verifyReceiverCount();
}
void tst_qqmlnotifier::cleanupTestCase()
diff --git a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp
index 897450823c..7b5ed5e236 100644
--- a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp
+++ b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp
@@ -65,6 +65,7 @@ private slots:
void aliases();
void categories();
void siblings();
+ void initial();
};
class CppObject : public QObject
@@ -579,6 +580,23 @@ void tst_QQmlSettings::siblings()
QCOMPARE(settings.value("alias2").toString(), QStringLiteral("value2"));
}
+void tst_QQmlSettings::initial()
+{
+ QSettings qs;
+ qs.setValue("value", QStringLiteral("initial"));
+ qs.sync();
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import Qt.labs.settings 1.0; Settings { property var value }", QUrl());
+ QScopedPointer<QObject> settings(component.create());
+ QVERIFY(settings.data());
+
+ // verify that the initial value from QSettings gets properly loaded
+ // even if no initial value is set in QML
+ QCOMPARE(settings->property("value").toString(), QStringLiteral("initial"));
+}
+
QTEST_MAIN(tst_QQmlSettings)
#include "tst_qqmlsettings.moc"
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 3ae27fe9c3..9c67e6e2e9 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -127,8 +127,8 @@ private:
void tst_qqmlxmlhttprequest::domExceptionCodes()
{
QQmlComponent component(&engine, testFileUrl("domExceptionCodes.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("index_size_err").toInt(), 1);
QCOMPARE(object->property("domstring_size_err").toInt(), 2);
@@ -147,8 +147,6 @@ void tst_qqmlxmlhttprequest::domExceptionCodes()
QCOMPARE(object->property("invalid_access_err").toInt(), 15);
QCOMPARE(object->property("validation_err").toInt(), 16);
QCOMPARE(object->property("type_mismatch_err").toInt(), 17);
-
- delete object;
}
void tst_qqmlxmlhttprequest::callbackException_data()
@@ -172,15 +170,13 @@ void tst_qqmlxmlhttprequest::callbackException()
QTest::ignoreMessage(QtWarningMsg, expect.toLatin1());
QQmlComponent component(&engine, testFileUrl("callbackException.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
object->setProperty("which", which);
component.completeCreate();
QTRY_VERIFY(object->property("threw").toBool() == true);
-
- delete object;
}
// Test that the state value properties on the XMLHttpRequest constructor have the correct values.
@@ -188,61 +184,53 @@ void tst_qqmlxmlhttprequest::callbackException()
void tst_qqmlxmlhttprequest::staticStateValues()
{
QQmlComponent component(&engine, testFileUrl("staticStateValues.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("unsent").toInt(), 0);
QCOMPARE(object->property("opened").toInt(), 1);
QCOMPARE(object->property("headers_received").toInt(), 2);
QCOMPARE(object->property("loading").toInt(), 3);
QCOMPARE(object->property("done").toInt(), 4);
-
- delete object;
}
// Test that the state value properties on instances have the correct values.
void tst_qqmlxmlhttprequest::instanceStateValues()
{
QQmlComponent component(&engine, testFileUrl("instanceStateValues.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("unsent").toInt(), 0);
QCOMPARE(object->property("opened").toInt(), 1);
QCOMPARE(object->property("headers_received").toInt(), 2);
QCOMPARE(object->property("loading").toInt(), 3);
QCOMPARE(object->property("done").toInt(), 4);
-
- delete object;
}
// Test calling constructor
void tst_qqmlxmlhttprequest::constructor()
{
QQmlComponent component(&engine, testFileUrl("constructor.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("calledAsConstructor").toBool(), true);
QCOMPARE(object->property("calledAsFunction").toBool(), true);
-
- delete object;
}
// Test that all the properties are set correctly before any request is sent
void tst_qqmlxmlhttprequest::defaultState()
{
QQmlComponent component(&engine, testFileUrl("defaultState.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("readState").toInt(), 0);
QCOMPARE(object->property("statusIsException").toBool(), true);
QCOMPARE(object->property("statusTextIsException").toBool(), true);
QCOMPARE(object->property("responseText").toString(), QString());
QCOMPARE(object->property("responseXMLIsNull").toBool(), true);
-
- delete object;
}
// Test valid XMLHttpRequest.open() calls
@@ -262,8 +250,8 @@ void tst_qqmlxmlhttprequest::open()
}
QQmlComponent component(&engine, qmlFile);
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", url);
component.completeCreate();
@@ -275,8 +263,6 @@ void tst_qqmlxmlhttprequest::open()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::open_data()
@@ -297,24 +283,20 @@ void tst_qqmlxmlhttprequest::open_data()
void tst_qqmlxmlhttprequest::open_invalid_method()
{
QQmlComponent component(&engine, testFileUrl("open_invalid_method.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Test that calling XMLHttpRequest.open() with sync raises an exception
void tst_qqmlxmlhttprequest::open_sync()
{
QQmlComponent component(&engine, testFileUrl("open_sync.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Calling with incorrect arg count raises an exception
@@ -322,22 +304,18 @@ void tst_qqmlxmlhttprequest::open_arg_count()
{
{
QQmlComponent component(&engine, testFileUrl("open_arg_count.1.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
{
QQmlComponent component(&engine, testFileUrl("open_arg_count.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
}
@@ -351,14 +329,12 @@ void tst_qqmlxmlhttprequest::setRequestHeader()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test valid setRequestHeader() calls with different header cases
@@ -371,25 +347,21 @@ void tst_qqmlxmlhttprequest::setRequestHeader_caseInsensitive()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_caseInsensitive.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test setting headers before open() throws exception
void tst_qqmlxmlhttprequest::setRequestHeader_unsent()
{
QQmlComponent component(&engine, testFileUrl("setRequestHeader_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::setRequestHeader_illegalName_data()
@@ -432,8 +404,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_illegalName.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("header", name);
component.completeCreate();
@@ -446,8 +418,6 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test that attempting to set a header after a request is sent throws an exception
@@ -460,53 +430,45 @@ void tst_qqmlxmlhttprequest::setRequestHeader_sent()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_sent.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QCOMPARE(object->property("test").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::setRequestHeader_args()
{
QQmlComponent component(&engine, testFileUrl("setRequestHeader_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Test that calling send() in UNSENT state throws an exception
void tst_qqmlxmlhttprequest::send_unsent()
{
QQmlComponent component(&engine, testFileUrl("send_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test attempting to resend a sent request throws an exception
void tst_qqmlxmlhttprequest::send_alreadySent()
{
QQmlComponent component(&engine, testFileUrl("send_alreadySent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test that sends for GET, HEAD and DELETE ignore data
@@ -520,15 +482,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "GET");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
{
@@ -539,15 +499,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
QUrl()));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "HEAD");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
{
@@ -558,15 +516,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
QUrl()));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "DELETE");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
}
@@ -583,14 +539,12 @@ void tst_qqmlxmlhttprequest::send_withdata()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl(file_qml));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::send_withdata_data()
@@ -611,8 +565,8 @@ void tst_qqmlxmlhttprequest::send_withdata_data()
void tst_qqmlxmlhttprequest::abort_unsent()
{
QQmlComponent component(&engine, testFileUrl("abort_unsent.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
component.completeCreate();
@@ -624,16 +578,14 @@ void tst_qqmlxmlhttprequest::abort_unsent()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test abort() cancels an open (but unsent) request
void tst_qqmlxmlhttprequest::abort_opened()
{
QQmlComponent component(&engine, testFileUrl("abort_opened.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
component.completeCreate();
@@ -645,8 +597,6 @@ void tst_qqmlxmlhttprequest::abort_opened()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test abort() aborts in progress send
@@ -659,8 +609,8 @@ void tst_qqmlxmlhttprequest::abort()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("abort.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("urlDummy", "http://127.0.0.1:14449/testdocument.html");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -670,8 +620,6 @@ void tst_qqmlxmlhttprequest::abort()
QCOMPARE(object->property("endStateUnsent").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::getResponseHeader()
@@ -686,8 +634,8 @@ void tst_qqmlxmlhttprequest::getResponseHeader()
QQmlComponent component(&engine, testFileUrl("getResponseHeader.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -709,44 +657,36 @@ void tst_qqmlxmlhttprequest::getResponseHeader()
QCOMPARE(object->property("doneValidHeader").toBool(), true);
QCOMPARE(object->property("doneMultiValidHeader").toBool(), true);
QCOMPARE(object->property("doneCookieHeader").toBool(), true);
-
- delete object;
}
// Test getResponseHeader throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getResponseHeader_unsent()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test getResponseHeader throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getResponseHeader_sent()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_sent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::getResponseHeader_args()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::getAllResponseHeaders()
@@ -760,8 +700,8 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -777,44 +717,36 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders()
QCOMPARE(object->property("doneState").toBool(), true);
QCOMPARE(object->property("doneHeader").toBool(), true);
-
- delete object;
}
// Test getAllResponseHeaders throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getAllResponseHeaders_unsent()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test getAllResponseHeaders throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getAllResponseHeaders_sent()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_sent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::getAllResponseHeaders_args()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::status()
@@ -829,8 +761,8 @@ void tst_qqmlxmlhttprequest::status()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("status.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedStatus", status);
component.completeCreate();
@@ -844,8 +776,6 @@ void tst_qqmlxmlhttprequest::status()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("resetException").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::status_data()
@@ -870,8 +800,8 @@ void tst_qqmlxmlhttprequest::statusText()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("statusText.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedStatus", statusText);
component.completeCreate();
@@ -885,8 +815,6 @@ void tst_qqmlxmlhttprequest::statusText()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("resetException").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::statusText_data()
@@ -912,8 +840,8 @@ void tst_qqmlxmlhttprequest::responseText()
bodyUrl));
QQmlComponent component(&engine, testFileUrl("responseText.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedText", responseText);
component.completeCreate();
@@ -927,8 +855,6 @@ void tst_qqmlxmlhttprequest::responseText()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("reset").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::responseText_data()
@@ -950,11 +876,11 @@ void tst_qqmlxmlhttprequest::nonUtf8()
QFETCH(QString, xmlRootNodeValue);
QQmlComponent component(&engine, testFileUrl("utf16.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
object->setProperty("fileName", fileName);
- QMetaObject::invokeMethod(object, "startRequest");
+ QMetaObject::invokeMethod(object.data(), "startRequest");
QTRY_VERIFY(object->property("dataOK").toBool() == true);
@@ -964,8 +890,6 @@ void tst_qqmlxmlhttprequest::nonUtf8()
QString rootNodeValue = object->property("responseXmlRootNodeValue").toString();
QCOMPARE(rootNodeValue, xmlRootNodeValue);
}
-
- delete object;
}
void tst_qqmlxmlhttprequest::nonUtf8_data()
@@ -989,8 +913,8 @@ void tst_qqmlxmlhttprequest::nonUtf8_data()
void tst_qqmlxmlhttprequest::invalidMethodUsage()
{
QQmlComponent component(&engine, testFileUrl("invalidMethodUsage.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("readyState").toBool(), true);
QCOMPARE(object->property("status").toBool(), true);
@@ -1004,8 +928,6 @@ void tst_qqmlxmlhttprequest::invalidMethodUsage()
QCOMPARE(object->property("abort").toBool(), true);
QCOMPARE(object->property("getResponseHeader").toBool(), true);
QCOMPARE(object->property("getAllResponseHeaders").toBool(), true);
-
- delete object;
}
// Test that XMLHttpRequest transparently redirects
@@ -1018,16 +940,14 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirects.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
QTRY_VERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
{
@@ -1037,16 +957,14 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirectError.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
QTRY_VERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
{
@@ -1056,8 +974,8 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirectRecur.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
@@ -1069,92 +987,78 @@ void tst_qqmlxmlhttprequest::redirects()
QVERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
}
void tst_qqmlxmlhttprequest::responseXML_invalid()
{
QQmlComponent component(&engine, testFileUrl("responseXML_invalid.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlNull").toBool(), true);
-
- delete object;
}
// Test the Document DOM element
void tst_qqmlxmlhttprequest::document()
{
QQmlComponent component(&engine, testFileUrl("document.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Element DOM element
void tst_qqmlxmlhttprequest::element()
{
QQmlComponent component(&engine, testFileUrl("element.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Attr DOM element
void tst_qqmlxmlhttprequest::attr()
{
QQmlComponent component(&engine, testFileUrl("attr.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Text DOM element
void tst_qqmlxmlhttprequest::text()
{
QQmlComponent component(&engine, testFileUrl("text.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the CDataSection DOM element
void tst_qqmlxmlhttprequest::cdata()
{
QQmlComponent component(&engine, testFileUrl("cdata.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::stateChangeCallingContext()
@@ -1171,11 +1075,10 @@ void tst_qqmlxmlhttprequest::stateChangeCallingContext()
server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
QQmlComponent component(&engine, testFileUrl("stateChangeCallingContext.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
server.sendDelayedItem();
QTRY_VERIFY(object->property("success").toBool() == true);
- delete object;
}
QTEST_MAIN(tst_qqmlxmlhttprequest)
diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
index 9fbcb4a118..15a6acc272 100644
--- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
@@ -45,6 +45,9 @@
#include <private/qv4debugging_p.h>
#include <private/qv8engine_p.h>
+using namespace QV4;
+using namespace QV4::Debugging;
+
static bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000)
{
QEventLoop loop;
@@ -77,7 +80,7 @@ public:
QV4::ExecutionEngine *v4Engine() { return QV8Engine::getV4(this); }
- typedef QV4::ReturnedValue (*InjectedFunction)(QV4::SimpleCallContext*);
+ typedef QV4::ReturnedValue (*InjectedFunction)(QV4::CallContext*);
Q_INVOKABLE void injectFunction(const QString &functionName, TestEngine::InjectedFunction injectedFunction)
{
@@ -95,26 +98,109 @@ signals:
Q_DECLARE_METATYPE(TestEngine::InjectedFunction)
+namespace {
+class TestCollector: public QV4::Debugging::Debugger::Collector
+{
+public:
+ TestCollector(QV4::ExecutionEngine *engine)
+ : Collector(engine)
+ , destination(0)
+ {}
+
+ virtual ~TestCollector() {}
+
+ void setDestination(QVariantMap *dest)
+ { destination = dest; }
+
+protected:
+ virtual void addUndefined(const QString &name)
+ {
+ destination->insert(name, QStringLiteral("undefined")); // TODO: add a user-defined type for this
+ }
+
+ virtual void addNull(const QString &name)
+ {
+ destination->insert(name, QStringLiteral("null")); // TODO: add a user-defined type for this
+ }
+
+ virtual void addBoolean(const QString &name, bool value)
+ {
+ destination->insert(name, value);
+ }
+
+ virtual void addString(const QString &name, const QString &value)
+ {
+ destination->insert(name, value);
+ }
+
+ virtual void addObject(const QString &name, QV4::ValueRef value)
+ {
+ QV4::Scope scope(engine());
+ QV4::ScopedObject obj(scope, value->asObject());
+
+ QVariantMap props, *prev = &props;
+ qSwap(destination, prev);
+ collect(obj);
+ qSwap(destination, prev);
+
+ destination->insert(name, props);
+ }
+
+ virtual void addInteger(const QString &name, int value)
+ {
+ destination->insert(name, QVariant::fromValue<double>(static_cast<double>(value)));
+ }
+
+ virtual void addDouble(const QString &name, double value)
+ {
+ destination->insert(name, QVariant::fromValue<double>(value));
+ }
+
+private:
+ QVariantMap *destination;
+};
+}
+
class TestAgent : public QV4::Debugging::DebuggerAgent
{
Q_OBJECT
public:
TestAgent()
: m_wasPaused(false)
+ , m_captureContextInfo(false)
{
}
- virtual void debuggerPaused(QV4::Debugging::Debugger *debugger)
+ virtual void debuggerPaused(Debugger *debugger, PauseReason reason)
{
Q_ASSERT(m_debuggers.count() == 1 && m_debuggers.first() == debugger);
m_wasPaused = true;
+ m_pauseReason = reason;
m_statesWhenPaused << debugger->currentExecutionState();
+ TestCollector collector(debugger->engine());
+ QVariantMap tmp;
+ collector.setDestination(&tmp);
+ debugger->collectThrownValue(&collector);
+ m_thrownValue = tmp["exception"];
+
foreach (const TestBreakPoint &bp, m_breakPointsToAddWhenPaused)
debugger->addBreakPoint(bp.fileName, bp.lineNumber);
m_breakPointsToAddWhenPaused.clear();
- debugger->resume();
+ m_stackTrace = debugger->stackTrace();
+
+ if (m_captureContextInfo)
+ captureContextInfo(debugger);
+
+ debugger->resume(Debugger::FullThrottle);
+ }
+
+ virtual void sourcesCollected(Debugger *debugger, QStringList sources, int requestSequenceNr)
+ {
+ Q_UNUSED(debugger);
+ Q_UNUSED(sources);
+ Q_UNUSED(requestSequenceNr);
}
int debuggerCount() const { return m_debuggers.count(); }
@@ -128,18 +214,52 @@ public:
int lineNumber;
};
+ void captureContextInfo(Debugger *debugger)
+ {
+ TestCollector collector(debugger->engine());
+
+ for (int i = 0, ei = m_stackTrace.size(); i != ei; ++i) {
+ QVariantMap args;
+ collector.setDestination(&args);
+ debugger->collectArgumentsInContext(&collector, i);
+ m_capturedArguments.append(args);
+
+ QVariantMap locals;
+ collector.setDestination(&locals);
+ debugger->collectLocalsInContext(&collector, i);
+ m_capturedLocals.append(locals);
+ }
+ }
+
bool m_wasPaused;
- QList<QV4::Debugging::Debugger::ExecutionState> m_statesWhenPaused;
+ PauseReason m_pauseReason;
+ bool m_captureContextInfo;
+ QList<Debugger::ExecutionState> m_statesWhenPaused;
QList<TestBreakPoint> m_breakPointsToAddWhenPaused;
+ QVector<QV4::StackFrame> m_stackTrace;
+ QList<QVariantMap> m_capturedArguments;
+ QList<QVariantMap> m_capturedLocals;
+ QVariant m_thrownValue;
+
+ // Utility methods:
+ void dumpStackTrace() const
+ {
+ qDebug() << "Stack depth:" << m_stackTrace.size();
+ foreach (const QV4::StackFrame &frame, m_stackTrace)
+ qDebug("\t%s (%s:%d:%d)", qPrintable(frame.function), qPrintable(frame.source),
+ frame.line, frame.column);
+ }
};
class tst_qv4debugger : public QObject
{
Q_OBJECT
+
private slots:
void init();
void cleanup();
+ // breakpoints:
void breakAnywhere();
void pendingBreakpoint();
void liveBreakPoint();
@@ -147,6 +267,15 @@ private slots:
void addBreakPointWhilePaused();
void removeBreakPointForNextInstruction();
+ // context access:
+ void readArguments();
+ void readLocals();
+ void readObject();
+ void readContextInAllFrames();
+
+ // exceptions:
+ void pauseOnThrow();
+
private:
void evaluateJavaScript(const QString &script, const QString &fileName, int lineNumber = 1)
{
@@ -235,8 +364,8 @@ void tst_qv4debugger::removePendingBreakPoint()
"var i = 42;\n"
"var j = i + 1\n"
"var k = i\n";
- m_debuggerAgent->addBreakPoint("removePendingBreakPoint", 2);
- m_debuggerAgent->removeBreakPoint("removePendingBreakPoint", 2);
+ int id = m_debuggerAgent->addBreakPoint("removePendingBreakPoint", 2);
+ m_debuggerAgent->removeBreakPoint(id);
evaluateJavaScript(script, "removePendingBreakPoint");
QVERIFY(!m_debuggerAgent->m_wasPaused);
}
@@ -262,7 +391,7 @@ void tst_qv4debugger::addBreakPointWhilePaused()
QCOMPARE(state.lineNumber, 2);
}
-static QV4::ReturnedValue someCall(QV4::SimpleCallContext *ctx)
+static QV4::ReturnedValue someCall(QV4::CallContext *ctx)
{
ctx->engine->debugger->removeBreakPoint("removeBreakPointForNextInstruction", 2);
return QV4::Encode::undefined();
@@ -283,6 +412,134 @@ void tst_qv4debugger::removeBreakPointForNextInstruction()
QVERIFY(!m_debuggerAgent->m_wasPaused);
}
+void tst_qv4debugger::readArguments()
+{
+ m_debuggerAgent->m_captureContextInfo = true;
+ QString script =
+ "function f(a, b, c, d) {\n"
+ " return a === b\n"
+ "}\n"
+ "var four;\n"
+ "f(1, 'two', null, four);\n";
+ m_debuggerAgent->addBreakPoint("readArguments", 2);
+ evaluateJavaScript(script, "readArguments");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[0].size(), 4);
+ QVERIFY(m_debuggerAgent->m_capturedArguments[0].contains(QStringLiteral("a")));
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[0]["a"].type(), QVariant::Double);
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[0]["a"].toDouble(), 1.0);
+ QVERIFY(m_debuggerAgent->m_capturedArguments[0].contains("b"));
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[0]["b"].type(), QVariant::String);
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[0]["b"].toString(), QLatin1String("two"));
+}
+
+void tst_qv4debugger::readLocals()
+{
+ m_debuggerAgent->m_captureContextInfo = true;
+ QString script =
+ "function f(a, b) {\n"
+ " var c = a + b\n"
+ " var d = a - b\n" // breakpoint, c should be set, d should be undefined
+ " return c === d\n"
+ "}\n"
+ "f(1, 2, 3);\n";
+ m_debuggerAgent->addBreakPoint("readLocals", 3);
+ evaluateJavaScript(script, "readLocals");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[0].size(), 2);
+ QVERIFY(m_debuggerAgent->m_capturedLocals[0].contains("c"));
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["c"].type(), QVariant::Double);
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["c"].toDouble(), 3.0);
+ QVERIFY(m_debuggerAgent->m_capturedLocals[0].contains("d"));
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["d"].toString(), QString("undefined"));
+}
+
+void tst_qv4debugger::readObject()
+{
+ m_debuggerAgent->m_captureContextInfo = true;
+ QString script =
+ "function f(a) {\n"
+ " var b = a\n"
+ " return b\n"
+ "}\n"
+ "f({head: 1, tail: { head: 'asdf', tail: null }});\n";
+ m_debuggerAgent->addBreakPoint("readObject", 3);
+ evaluateJavaScript(script, "readObject");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[0].size(), 1);
+ QVERIFY(m_debuggerAgent->m_capturedLocals[0].contains("b"));
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["b"].type(), QVariant::Map);
+
+ QVariantMap b = m_debuggerAgent->m_capturedLocals[0]["b"].toMap();
+ QCOMPARE(b.size(), 2);
+ QVERIFY(b.contains("head"));
+ QCOMPARE(b["head"].type(), QVariant::Double);
+ QCOMPARE(b["head"].toDouble(), 1.0);
+ QVERIFY(b.contains("tail"));
+ QCOMPARE(b["tail"].type(), QVariant::Map);
+
+ QVariantMap b_tail = b["tail"].toMap();
+ QCOMPARE(b_tail.size(), 2);
+ QVERIFY(b_tail.contains("head"));
+ QCOMPARE(b_tail["head"].type(), QVariant::String);
+ QCOMPARE(b_tail["head"].toString(), QString("asdf"));
+}
+
+void tst_qv4debugger::readContextInAllFrames()
+{
+ m_debuggerAgent->m_captureContextInfo = true;
+ QString script =
+ "function fact(n) {\n"
+ " if (n > 1) {\n"
+ " var n_1 = n - 1;\n"
+ " n_1 = fact(n_1);\n"
+ " return n * n_1;\n"
+ " } else\n"
+ " return 1;\n" // breakpoint
+ "}\n"
+ "fact(12);\n";
+ m_debuggerAgent->addBreakPoint("readFormalsInAllFrames", 7);
+ evaluateJavaScript(script, "readFormalsInAllFrames");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 13);
+ QCOMPARE(m_debuggerAgent->m_capturedArguments.size(), 13);
+ QCOMPARE(m_debuggerAgent->m_capturedLocals.size(), 13);
+
+ for (int i = 0; i < 12; ++i) {
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[i].size(), 1);
+ QVERIFY(m_debuggerAgent->m_capturedArguments[i].contains("n"));
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[i]["n"].type(), QVariant::Double);
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[i]["n"].toDouble(), i + 1.0);
+
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[i].size(), 1);
+ QVERIFY(m_debuggerAgent->m_capturedLocals[i].contains("n_1"));
+ if (i == 0) {
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[i]["n_1"].toString(), QString("undefined"));
+ } else {
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[i]["n_1"].type(), QVariant::Double);
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[i]["n_1"].toInt(), i);
+ }
+ }
+ QCOMPARE(m_debuggerAgent->m_capturedArguments[12].size(), 0);
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[12].size(), 0);
+}
+
+void tst_qv4debugger::pauseOnThrow()
+{
+ QString script =
+ "function die(n) {\n"
+ " throw n\n"
+ "}\n"
+ "die('hard');\n";
+ m_debuggerAgent->setBreakOnThrow(true);
+ evaluateJavaScript(script, "pauseOnThrow");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QCOMPARE(m_debuggerAgent->m_pauseReason, Throwing);
+ QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 2);
+ QCOMPARE(m_debuggerAgent->m_thrownValue.type(), QVariant::String);
+ QCOMPARE(m_debuggerAgent->m_thrownValue.toString(), QString("hard"));
+}
+
QTEST_MAIN(tst_qv4debugger)
#include "tst_qv4debugger.moc"
diff --git a/tests/auto/qmltest/fontloader/tst_fontloader.qml b/tests/auto/qmltest/fontloader/tst_fontloader.qml
index 59aa72a8eb..be24bb603d 100644
--- a/tests/auto/qmltest/fontloader/tst_fontloader.qml
+++ b/tests/auto/qmltest/fontloader/tst_fontloader.qml
@@ -63,9 +63,6 @@ Item {
name: "FontLoader"
function test_fontloading() {
- if (Qt.platform.os === "osx")
- skip("See QTBUG-32650")
-
compare(fontloader.status, FontLoader.Null)
compare(testinput.font.family, "")
fontloader.source = "tarzeau_ocr_a.ttf";
@@ -81,9 +78,6 @@ Item {
}
function test_fontswitching() {
- if (Qt.platform.os === "osx")
- skip("See QTBUG-32650")
-
compare(fontswitch.status, FontLoader.Null)
fontswitch.source = "tarzeau_ocr_a.ttf";
tryCompare(fontswitch, 'status', FontLoader.Ready)
diff --git a/tests/auto/quick/nodes/tst_nodestest.cpp b/tests/auto/quick/nodes/tst_nodestest.cpp
index 3ba7771538..d07fd7177d 100644
--- a/tests/auto/quick/nodes/tst_nodestest.cpp
+++ b/tests/auto/quick/nodes/tst_nodestest.cpp
@@ -48,6 +48,8 @@
#include <QtQuick/qsgnode.h>
#include <QtQuick/private/qsgbatchrenderer_p.h>
#include <QtQuick/private/qsgnodeupdater_p.h>
+#include <QtQuick/private/qsgrenderloop_p.h>
+#include <QtQuick/private/qsgcontext_p.h>
#include <QtQuick/qsgsimplerectnode.h>
@@ -75,16 +77,22 @@ private Q_SLOTS:
private:
QOffscreenSurface *surface;
QOpenGLContext *context;
+ QSGRenderContext *renderContext;
};
void NodesTest::initTestCase()
{
+ QSGRenderLoop *renderLoop = QSGRenderLoop::instance();
+
surface = new QOffscreenSurface;
surface->create();
context = new QOpenGLContext();
context->create();
context->makeCurrent(surface);
+
+ renderContext = renderLoop->createRenderContext(renderLoop->sceneGraphContext());
+ renderContext->initialize(context);
}
void NodesTest::cleanupTestCase()
@@ -97,8 +105,8 @@ void NodesTest::cleanupTestCase()
class DummyRenderer : public QSGBatchRenderer::Renderer
{
public:
- DummyRenderer(QSGRootNode *root)
- : QSGBatchRenderer::Renderer(QSGContext::createDefaultContext())
+ DummyRenderer(QSGRootNode *root, QSGRenderContext *renderContext)
+ : QSGBatchRenderer::Renderer(renderContext)
, changedNode(0)
, changedState(0)
, renderCount(0)
@@ -138,7 +146,7 @@ void NodesTest::propegate()
QSGNode child; child.setFlag(QSGNode::OwnedByParent, false);
root.appendChildNode(&child);
- DummyRenderer renderer(&root);
+ DummyRenderer renderer(&root, renderContext);
child.markDirty(QSGNode::DirtyGeometry);
@@ -158,8 +166,8 @@ void NodesTest::propegateWithMultipleRoots()
child2.appendChildNode(&root3);
root3.appendChildNode(&child4);
- DummyRenderer ren1(&root1);
- DummyRenderer ren2(&root3);
+ DummyRenderer ren1(&root1, renderContext);
+ DummyRenderer ren2(&root3, renderContext);
child4.markDirty(QSGNode::DirtyGeometry);
@@ -195,7 +203,7 @@ void NodesTest::opacityPropegation()
QSGSimpleRectNode *geometry = new QSGSimpleRectNode;
geometry->setRect(0, 0, 100, 100);
- DummyRenderer renderer(&root);
+ DummyRenderer renderer(&root, renderContext);
root.appendChildNode(a);
a->appendChildNode(b);
diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp
index 7146b1483a..bc8821ae60 100644
--- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp
+++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp
@@ -68,7 +68,6 @@
#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
#include <QtQuick/private/qsgdistancefieldutil_p.h>
-#include <QtQuick/private/qsgflashnode_p.h>
#include <QtQuick/private/qsggeometry_p.h>
#include <QtQuick/private/qsgnode_p.h>
#include <QtQuick/private/qsgnodeupdater_p.h>
diff --git a/tests/auto/quick/qquickanimations/data/parallelAnimationNullChildBug.qml b/tests/auto/quick/qquickanimations/data/parallelAnimationNullChildBug.qml
new file mode 100644
index 0000000000..8da3e8e1af
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/parallelAnimationNullChildBug.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.2
+
+Item {
+ id: root
+ Component.onCompleted: Qt.createQmlObject("import QtQuick 2.2; ParallelAnimation{animations: [null]}", root)
+}
diff --git a/tests/auto/quick/qquickanimations/data/sequentialAnimationNullChildBug.qml b/tests/auto/quick/qquickanimations/data/sequentialAnimationNullChildBug.qml
new file mode 100644
index 0000000000..7a5c6063c4
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/sequentialAnimationNullChildBug.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.2
+
+Item {
+ id: root
+ Component.onCompleted: Qt.createQmlObject("import QtQuick 2.2; SequentialAnimation{animations: [null]}", root)
+}
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index 94726aa5fe..c6f4779819 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -110,6 +110,7 @@ private slots:
void anchorBug();
void pathAnimationInOutBackBug();
void scriptActionBug();
+ void groupAnimationNullChildBug();
};
#define QTIMED_COMPARE(lhs, rhs) do { \
@@ -1450,6 +1451,31 @@ void tst_qquickanimations::scriptActionBug()
QCOMPARE(obj->property("actionTriggered").toBool(), true);
}
+//QTBUG-34851
+void tst_qquickanimations::groupAnimationNullChildBug()
+{
+ {
+ QQmlEngine engine;
+
+ QQmlComponent c(&engine, testFileUrl("sequentialAnimationNullChildBug.qml"));
+ QQuickItem *root = qobject_cast<QQuickItem*>(c.create());
+ QVERIFY(root);
+
+ delete root;
+ }
+
+ {
+ QQmlEngine engine;
+
+ QQmlComponent c(&engine, testFileUrl("parallelAnimationNullChildBug.qml"));
+ QQuickItem *root = qobject_cast<QQuickItem*>(c.create());
+ QVERIFY(root);
+
+ delete root;
+ }
+}
+
+
QTEST_MAIN(tst_qquickanimations)
#include "tst_qquickanimations.moc"
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index 97e002361b..2c6dcd72ba 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -44,7 +44,6 @@
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickwindow.h>
#include <QtQuick/qquickview.h>
-#include <QtWidgets/QGraphicsSceneMouseEvent>
#include "private/qquickfocusscope_p.h"
#include "private/qquickitem_p.h"
#include <qpa/qwindowsysteminterface.h>
@@ -1151,6 +1150,30 @@ void tst_qquickitem::enabledFocus()
QCOMPARE(child2.hasFocus(), false);
QCOMPARE(child2.hasActiveFocus(), false);
QCOMPARE(window.activeFocusItem(), static_cast<QQuickItem *>(&child1));
+
+ child2.setFocus(true);
+ QCOMPARE(root.isEnabled(), true);
+ QCOMPARE(root.hasFocus(), true);
+ QCOMPARE(root.hasActiveFocus(), true);
+ QCOMPARE(child1.isEnabled(), true);
+ QCOMPARE(child1.hasFocus(), false);
+ QCOMPARE(child1.hasActiveFocus(), false);
+ QCOMPARE(child2.isEnabled(), false);
+ QCOMPARE(child2.hasFocus(), true);
+ QCOMPARE(child2.hasActiveFocus(), false);
+ QCOMPARE(window.activeFocusItem(), static_cast<QQuickItem *>(&root));
+
+ root.setEnabled(false);
+ QCOMPARE(root.isEnabled(), false);
+ QCOMPARE(root.hasFocus(), true);
+ QCOMPARE(root.hasActiveFocus(), false);
+ QCOMPARE(child1.isEnabled(), false);
+ QCOMPARE(child1.hasFocus(), false);
+ QCOMPARE(child1.hasActiveFocus(), false);
+ QCOMPARE(child2.isEnabled(), false);
+ QCOMPARE(child2.hasFocus(), true);
+ QCOMPARE(child2.hasActiveFocus(), false);
+ QCOMPARE(window.activeFocusItem(), window.contentItem());
}
static inline QByteArray msgItem(const QQuickItem *item)
diff --git a/tests/auto/quick/qquickitem2/data/keynavigationtest_focusscope.qml b/tests/auto/quick/qquickitem2/data/keynavigationtest_focusscope.qml
new file mode 100644
index 0000000000..985086ff49
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/keynavigationtest_focusscope.qml
@@ -0,0 +1,93 @@
+import QtQuick 2.0
+
+Grid {
+ columns: 2
+ width: 100; height: 100
+ function verify() {
+ if (item1.KeyNavigation.right != item2)
+ return false;
+ if (item1.KeyNavigation.down != item3)
+ return false;
+ if (item1.KeyNavigation.tab != item2)
+ return false;
+ if (item1.KeyNavigation.backtab != item4)
+ return false;
+
+ if (item2.KeyNavigation.left != item1)
+ return false;
+ if (item2.KeyNavigation.down != item4)
+ return false;
+ if (item2.KeyNavigation.tab != item3)
+ return false;
+ if (item2.KeyNavigation.backtab != item1)
+ return false;
+
+ if (item3.KeyNavigation.right != item4)
+ return false;
+ if (item3.KeyNavigation.up != item1)
+ return false;
+ if (item3.KeyNavigation.tab != item4)
+ return false;
+ if (item3.KeyNavigation.backtab != item2)
+ return false;
+
+ if (item4.KeyNavigation.left != item3)
+ return false;
+ if (item4.KeyNavigation.up != item2)
+ return false;
+ if (item4.KeyNavigation.tab != item1)
+ return false;
+ if (item4.KeyNavigation.backtab != item3)
+ return false;
+
+ return true;
+ }
+
+ Rectangle {
+ id: item1
+ objectName: "item1"
+ focus: true
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.right: item2
+ KeyNavigation.down: item3
+ KeyNavigation.tab: item2
+ KeyNavigation.backtab: item4
+ }
+ FocusScope {
+ Rectangle {
+ id: item2
+ objectName: "item2"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.left: item1
+ KeyNavigation.down: item4
+ KeyNavigation.tab: item3
+ KeyNavigation.backtab: item1
+ }
+ }
+ FocusScope {
+ Rectangle {
+ id: item3
+ objectName: "item3"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.right: item4
+ KeyNavigation.up: item1
+ KeyNavigation.tab: item4
+ KeyNavigation.backtab: item2
+ }
+ FocusScope {
+ Rectangle {
+ id: item4
+ objectName: "item4"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.left: item3
+ KeyNavigation.up: item2
+ KeyNavigation.tab: item1
+ KeyNavigation.backtab: item3
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index c451ea5e0a..8a4ed5ae4c 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -83,6 +83,7 @@ private slots:
void standardKeys();
void keysProcessingOrder();
void keysim();
+ void keyNavigation_data();
void keyNavigation();
void keyNavigation_RightToLeft();
void keyNavigation_skipNotVisible();
@@ -1408,12 +1409,21 @@ void tst_QQuickItem::layoutMirroringIllegalParent()
QVERIFY(object != 0);
}
+void tst_QQuickItem::keyNavigation_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::newRow("KeyNavigation") << QStringLiteral("keynavigationtest.qml");
+ QTest::newRow("KeyNavigation_FocusScope") << QStringLiteral("keynavigationtest_focusscope.qml");
+}
+
void tst_QQuickItem::keyNavigation()
{
+ QFETCH(QString, source);
+
QQuickView *window = new QQuickView(0);
window->setBaseSize(QSize(240,320));
- window->setSource(testFileUrl("keynavigationtest.qml"));
+ window->setSource(testFileUrl(source));
window->show();
window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
diff --git a/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml b/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml
new file mode 100644
index 0000000000..b32f7a1236
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ ListView {
+ id: list
+ anchors.fill: parent
+ objectName: "list"
+ delegate: Text {}
+ header: Text {
+ objectName: "header"
+ text: "ninjas"
+ height: headerHeight
+ width: headerWidth
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/typedModel.qml b/tests/auto/quick/qquicklistview/data/typedModel.qml
new file mode 100644
index 0000000000..d2b3f7e42f
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/typedModel.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+
+ delegate: Item {
+ width: 100
+ height: 10
+ }
+ model: listModel
+
+ ListModel {
+ id: listModel
+
+ ListElement { label: "a" }
+ ListElement { label: "b" }
+ ListElement { label: "c" }
+ ListElement { label: "d" }
+ ListElement { label: "e" }
+ ListElement { label: "f" }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index f62151c2d8..fb0b1c95ca 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -150,6 +150,7 @@ private slots:
void header();
void header_data();
void header_delayItemCreation();
+ void headerChangesViewport();
void footer();
void footer_data();
void extents();
@@ -213,6 +214,8 @@ private slots:
void outsideViewportChangeNotAffectingView();
void testProxyModelChangedAfterMove();
+ void typedModel();
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -3655,6 +3658,35 @@ void tst_QQuickListView::header_delayItemCreation()
delete window;
}
+void tst_QQuickListView::headerChangesViewport()
+{
+ QQuickView *window = getView();
+ window->rootContext()->setContextProperty("headerHeight", 20);
+ window->rootContext()->setContextProperty("headerWidth", 240);
+ window->setSource(testFileUrl("headerchangesviewport.qml"));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+ QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+ QQuickItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QQuickText *header = 0;
+ QTRY_VERIFY(header = findItem<QQuickText>(contentItem, "header"));
+ QVERIFY(header == listview->headerItem());
+
+ QCOMPARE(header->height(), 20.);
+ QCOMPARE(listview->contentHeight(), 20.);
+
+ // change height
+ window->rootContext()->setContextProperty("headerHeight", 50);
+
+ // verify that list content height updates also
+ QCOMPARE(header->height(), 50.);
+ QCOMPARE(listview->contentHeight(), 50.);
+}
+
void tst_QQuickListView::footer()
{
QFETCH(QQuickListView::Orientation, orientation);
@@ -6960,6 +6992,24 @@ void tst_QQuickListView::testProxyModelChangedAfterMove()
delete window;
}
+void tst_QQuickListView::typedModel()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("typedModel.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(object.data());
+ QVERIFY(listview);
+
+ QCOMPARE(listview->count(), 6);
+
+ QQmlListModel *listModel = 0;
+
+ listview->setModel(QVariant::fromValue(listModel));
+ QCOMPARE(listview->count(), 0);
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"
diff --git a/tests/auto/quick/qquickmousearea/data/qtbug34368.qml b/tests/auto/quick/qquickmousearea/data/qtbug34368.qml
new file mode 100644
index 0000000000..42d8ddd3b6
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/qtbug34368.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.2
+
+Rectangle {
+ id: root
+ color: "green"
+ width: 200
+ height: 200
+ property int clicksEnabled: 0
+ property int clicksDisabled: 0
+ property bool disableLower: false
+ MouseArea {
+ anchors.fill: parent
+ propagateComposedEvents: true
+ z: 1
+ onClicked: {
+ mouse.accepted = false;
+ clicksEnabled += 1;
+ //console.log("Upper click");
+ }
+ }
+ MouseArea {
+ anchors.fill: parent
+ propagateComposedEvents: true
+ z: 0
+ enabled: !disableLower
+ onClicked: {
+ mouse.accepted = false;
+ clicksDisabled += 1;
+ //console.log("Lower click");
+ }
+ }
+ Text {
+ anchors.fill: parent
+ text: "A: " + clicksEnabled + " B:" + clicksDisabled
+ focus: true
+ Keys.onSpacePressed: root.disableLower = !root.disableLower;
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 0c0b51d9c2..72639556ec 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -995,6 +995,29 @@ void tst_QQuickMouseArea::clickThrough()
QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 2);
QCOMPARE(window->rootObject()->property("doubleClicks").toInt(), 1);
QCOMPARE(window->rootObject()->property("pressAndHolds").toInt(), 1);
+
+ window.reset(new QQuickView);
+
+ //QTBUG-34368 - Shouldn't propagate to disabled mouse areas
+ QVERIFY2(initView(*window.data(), testFileUrl("qtbug34368.qml"), true, &errorMessage), errorMessage.constData());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ QVERIFY(window->rootObject() != 0);
+
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+
+ QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 1);
+ QCOMPARE(window->rootObject()->property("clicksDisabled").toInt(), 1); //Not disabled yet
+
+ window->rootObject()->setProperty("disableLower", QVariant(true));
+
+ QTest::qWait(doubleClickInterval); // to avoid generating a double click.
+ QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+ QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100));
+
+ QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 2);
+ QCOMPARE(window->rootObject()->property("clicksDisabled").toInt(), 1); //disabled, shouldn't increment
}
void tst_QQuickMouseArea::hoverPosition()
diff --git a/tests/auto/quick/qquickspringanimation/data/inTransition.qml b/tests/auto/quick/qquickspringanimation/data/inTransition.qml
new file mode 100644
index 0000000000..68d3125e40
--- /dev/null
+++ b/tests/auto/quick/qquickspringanimation/data/inTransition.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 250
+ height: 250
+
+ ListView {
+ anchors.fill: parent
+ model: ListModel {
+ ListElement { text: "A" }
+ ListElement { text: "B" }
+ }
+
+ populate: Transition {
+ SpringAnimation { properties: "x"; from: 0; to: 100; spring: 4; damping: 0.3 }
+ }
+
+ delegate: Text {
+ text: "Test"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp b/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp
index 78d114c904..137b5c08e4 100644
--- a/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp
+++ b/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp
@@ -41,6 +41,7 @@
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
+#include <QtQuick/qquickview.h>
#include <private/qquickspringanimation_p.h>
#include <private/qqmlvaluetype_p.h>
#include "../../shared/util.h"
@@ -55,6 +56,7 @@ private slots:
void defaultValues();
void values();
void disabled();
+ void inTransition();
private:
QQmlEngine engine;
@@ -128,6 +130,14 @@ void tst_qquickspringanimation::disabled()
delete obj;
}
+void tst_qquickspringanimation::inTransition()
+{
+ QQuickView view(testFileUrl("inTransition.qml"));
+ view.show();
+ // this used to crash after ~1 sec, once the spring animation was done
+ QTest::qWait(2000);
+}
+
QTEST_MAIN(tst_qquickspringanimation)
#include "tst_qquickspringanimation.moc"
diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
index e165b559f7..0c9b75636f 100644
--- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp
+++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
@@ -1567,7 +1567,7 @@ void tst_qquickstates::QTBUG_14830()
QVERIFY(rect != 0);
QQuickItem *item = rect->findChild<QQuickItem*>("area");
- QCOMPARE(item->width(), qreal(171));
+ QCOMPARE(item->width(), qreal(170));
}
void tst_qquickstates::avoidFastForward()
diff --git a/tests/auto/quick/qquicktext/data/hover.qml b/tests/auto/quick/qquicktext/data/hover.qml
new file mode 100644
index 0000000000..36d9b5c691
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/hover.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.1
+import QtQuick.Window 2.1
+
+Window {
+ width: 100
+ height: 100
+ property alias mouseArea: mouseArea
+ property alias textItem: textItem
+ MouseArea {
+ id: mouseArea
+ hoverEnabled: true
+ anchors.fill: parent
+ acceptedButtons: Qt.NoButton
+ property bool wasHovered: false
+ onPositionChanged: wasHovered = true
+ Text {
+ id: textItem
+ text: "plain text"
+ anchors.fill: parent
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 6b93791545..78e03be9c2 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -44,6 +44,7 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/private/qquicktext_p.h>
+#include <QtQuick/private/qquickmousearea_p.h>
#include <private/qquicktext_p_p.h>
#include <private/qquickvaluetypes_p.h>
#include <QFontMetrics>
@@ -151,6 +152,8 @@ private slots:
void elideBeforeMaximumLineCount();
+ void hover();
+
private:
QStringList standard;
QStringList richText;
@@ -3744,6 +3747,31 @@ void tst_qquicktext::elideBeforeMaximumLineCount()
QCOMPARE(item->lineCount(), 2);
}
+void tst_qquicktext::hover()
+{ // QTBUG-33842
+ QQmlComponent component(&engine, testFile("hover.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(object.data());
+ QVERIFY(window);
+
+ QQuickMouseArea *mouseArea = window->property("mouseArea").value<QQuickMouseArea *>();
+ QVERIFY(mouseArea);
+ QQuickText *textItem = window->property("textItem").value<QQuickText *>();
+ QVERIFY(textItem);
+
+ QVERIFY(!mouseArea->property("wasHovered").toBool());
+
+ QPoint center(window->width() / 2, window->height() / 2);
+ QPoint delta(window->width() / 10, window->height() / 10);
+
+ QTest::mouseMove(window, center - delta);
+ QTest::mouseMove(window, center + delta);
+
+ QVERIFY(mouseArea->property("wasHovered").toBool());
+}
+
QTEST_MAIN(tst_qquicktext)
#include "tst_qquicktext.moc"
diff --git a/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml b/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml
new file mode 100644
index 0000000000..2ec5ce6676
--- /dev/null
+++ b/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.2
+
+Item {
+ property variant input1: input1
+ property variant input2: input2
+
+ width: 800; height: 600;
+
+ Column{
+ TextInput { id: input1; }
+ TextInput { id: input2; }
+ }
+}
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index 1c2ab4d948..80726720e4 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -146,6 +146,8 @@ private slots:
void validators();
void inputMethods();
+ void signal_editingfinished();
+
void passwordCharacter();
void cursorDelegate_data();
void cursorDelegate();
@@ -2303,6 +2305,49 @@ void tst_qquicktextinput::inputMethods()
QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), false);
}
+void tst_qquicktextinput::signal_editingfinished()
+{
+ QQuickView window(testFileUrl("signal_editingfinished.qml"));
+ window.show();
+ window.requestActivate();
+ QTest::qWaitForWindowActive(&window);
+
+ QVERIFY(window.rootObject() != 0);
+
+ QQuickTextInput *input1 = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("input1")));
+ QVERIFY(input1);
+ QQuickTextInput *input2 = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("input2")));
+ QVERIFY(input2);
+ QSignalSpy input1Spy(input1, SIGNAL(editingFinished()));
+
+ input1->setFocus(true);
+ QTRY_VERIFY(input1->hasActiveFocus());
+ QTRY_VERIFY(!input2->hasActiveFocus());
+
+ QTest::keyPress(&window, Qt::Key_A);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
+ QTRY_COMPARE(input1->text(), QLatin1String("a"));
+
+ QTest::keyPress(&window, Qt::Key_Enter);
+ QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
+ QTRY_COMPARE(input1Spy.count(), 1);
+
+ QSignalSpy input2Spy(input2, SIGNAL(editingFinished()));
+
+ input2->setFocus(true);
+ QTRY_VERIFY(!input1->hasActiveFocus());
+ QTRY_VERIFY(input2->hasActiveFocus());
+
+ QTest::keyPress(&window, Qt::Key_A);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
+ QTRY_COMPARE(input2->text(), QLatin1String("a"));
+
+ input1->setFocus(true);
+ QTRY_VERIFY(input1->hasActiveFocus());
+ QTRY_VERIFY(!input2->hasActiveFocus());
+ QTRY_COMPARE(input2Spy.count(), 1);
+}
+
/*
TextInput element should only handle left/right keys until the cursor reaches
the extent of the text, then they should ignore the keys.
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 28dacb1f81..984881c8da 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -1093,7 +1093,11 @@ void tst_qquickwindow::noUpdateWhenNothingChanges()
QQuickRectangle rect(window.contentItem());
window.showNormal();
- QTRY_VERIFY(window.isExposed());
+ QTest::qWaitForWindowExposed(&window);
+ // Many platforms are broken in the sense that that they follow up
+ // the initial expose with a second expose or more. Let these go
+ // through before we let the test continue.
+ QTest::qWait(100);
if (window.openglContext()->thread() == QGuiApplication::instance()->thread()) {
QSKIP("Only threaded renderloop implements this feature");
@@ -1102,7 +1106,8 @@ void tst_qquickwindow::noUpdateWhenNothingChanges()
QSignalSpy spy(&window, SIGNAL(frameSwapped()));
rect.update();
- QTest::qWait(500);
+ // Wait a while and verify that no more frameSwapped come our way.
+ QTest::qWait(100);
QCOMPARE(spy.size(), 0);
}
@@ -1348,11 +1353,6 @@ void tst_qquickwindow::hideThenDelete_data()
void tst_qquickwindow::hideThenDelete()
{
- if (QGuiApplication::platformName() == QStringLiteral("xcb")) {
- QSKIP("For some obscure reason this test fails in CI only");
- return;
- }
-
QFETCH(bool, persistentSG);
QFETCH(bool, persistentGL);
diff --git a/tests/auto/quick/rendernode/data/RenderOrder.qml b/tests/auto/quick/rendernode/data/RenderOrder.qml
index 739aa9cc06..c7cc6cdeb9 100644
--- a/tests/auto/quick/rendernode/data/RenderOrder.qml
+++ b/tests/auto/quick/rendernode/data/RenderOrder.qml
@@ -4,8 +4,8 @@ import Test 1.0
Rectangle {
id: root
- width: 160
- height: 240
+ width: 200
+ height: 200
color: "black"
Rectangle {
diff --git a/tests/auto/quick/rendernode/rendernode.pro b/tests/auto/quick/rendernode/rendernode.pro
index b195b97dcf..b55b7b0bec 100644
--- a/tests/auto/quick/rendernode/rendernode.pro
+++ b/tests/auto/quick/rendernode/rendernode.pro
@@ -15,4 +15,3 @@ OTHER_FILES += \
data/RenderOrder.qml \
data/MessUpState.qml \
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
-CONFIG+=insignificant_test
diff --git a/tests/auto/quick/rendernode/tst_rendernode.cpp b/tests/auto/quick/rendernode/tst_rendernode.cpp
index 90a9488047..7d1590e5f6 100644
--- a/tests/auto/quick/rendernode/tst_rendernode.cpp
+++ b/tests/auto/quick/rendernode/tst_rendernode.cpp
@@ -59,14 +59,13 @@ public:
{
QQuickView view;
view.setSource(testFileUrl(fileName));
-
+ view.setResizeMode(QQuickView::SizeViewToRootObject);
const QRect screenGeometry = view.screen()->availableGeometry();
const QSize size = view.size();
const QPoint offset = QPoint(size.width() / 2, size.height() / 2);
view.setFramePosition(screenGeometry.center() - offset);
view.showNormal();
QTest::qWaitForWindowExposed(&view);
-
return view.grabWindow();
}
@@ -207,34 +206,33 @@ static inline QByteArray msgColorMismatchAt(const QByteArray &colorMsg, int x, i
return colorMsg + QByteArrayLiteral(" at ") + QByteArray::number(x) +',' + QByteArray::number(y);
}
+/* The test draws four rects, each 100x100 and verifies
+ * that a rendernode which calls glClear() is stacked
+ * correctly. The red rectangles come under the white
+ * and are obscured.
+ */
void tst_rendernode::renderOrder()
{
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
QImage fb = runTest("RenderOrder.qml");
- int x1 = fb.width() / 8;
- int x2 = fb.width() * 3 / 8;
- int x3 = fb.width() * 5 / 8;
- int x4 = fb.width() * 7 / 8;
- int y1 = fb.height() / 8;
- int y2 = fb.height() * 3 / 8;
- int y3 = fb.height() * 5 / 8;
- int y4 = fb.height() * 7 / 8;
+
+ QCOMPARE(fb.width(), 200);
+ QCOMPARE(fb.height(), 200);
+
+ QCOMPARE(fb.pixel(50, 50), qRgb(0xff, 0xff, 0xff));
+ QCOMPARE(fb.pixel(50, 150), qRgb(0xff, 0xff, 0xff));
+ QCOMPARE(fb.pixel(150, 50), qRgb(0x00, 0x00, 0xff));
QByteArray errorMessage;
- QVERIFY2(fuzzyCompareColor(fb.pixel(x1, y1), qRgb(0x7f, 0x00, 0x00), &errorMessage),
- msgColorMismatchAt(errorMessage, x1, y1).constData());
- QCOMPARE(fb.pixel(x2, y2), qRgb(0xff, 0xff, 0xff));
- QCOMPARE(fb.pixel(x3, y2), qRgb(0x00, 0x00, 0xff));
- QCOMPARE(fb.pixel(x4, y1), qRgb(0x00, 0x00, 0xff));
- QCOMPARE(fb.pixel(x1, y4), qRgb(0xff, 0x00, 0x00));
- QCOMPARE(fb.pixel(x2, y3), qRgb(0xff, 0xff, 0xff));
- QVERIFY2(fuzzyCompareColor(fb.pixel(x3, y3), qRgb(0x7f, 0x7f, 0xff), &errorMessage),
- msgColorMismatchAt(errorMessage, x3, y3).constData());
- QVERIFY2(fuzzyCompareColor(fb.pixel(x4, y4), qRgb(0x00, 0x00, 0x7f), &errorMessage),
- msgColorMismatchAt(errorMessage, x4, y4).constData());
+ QVERIFY2(fuzzyCompareColor(fb.pixel(150, 150), qRgb(0x7f, 0x7f, 0xff), &errorMessage),
+ msgColorMismatchAt(errorMessage, 150, 150).constData());
}
+/* The test uses a number of nested rectangles with clipping
+ * and rotation to verify that using a render node which messes
+ * with the state does not break rendering that comes after it.
+ */
void tst_rendernode::messUpState()
{
if (QGuiApplication::primaryScreen()->depth() < 24)
diff --git a/tests/auto/quick/scenegraph/data/RenderTestBase.qml b/tests/auto/quick/scenegraph/data/RenderTestBase.qml
new file mode 100644
index 0000000000..06e5f7c6e3
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/RenderTestBase.qml
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.2
+
+Item
+{
+ id: root
+
+ width: 200
+ height: 200
+
+ signal enterFinalStage
+
+ property bool finalStageComplete: false;
+
+ /* What comes below is some convenience for running the .qml files s
+ * standalone using qmlscene. This can be quite handy when debugging
+ * issues.
+ */
+
+ onFinalStageCompleteChanged: {
+ if (typeof suite == 'undefined') {
+ print("-> final stage complete");
+ }
+ }
+
+ Component.onCompleted: {
+ if (typeof suite == 'undefined') {
+ print("-> not running in testsuite, now in initial state")
+ suiteFaker.running = true;
+ }
+ }
+
+ Timer {
+ id: suiteFaker
+ running: false;
+ interval: 1000
+ repeat: false;
+ onTriggered: {
+ print("-> entering final stage")
+ enterFinalStage();
+ }
+ }
+
+}
diff --git a/tests/auto/quick/scenegraph/data/logo-big.jpg b/tests/auto/quick/scenegraph/data/logo-big.jpg
new file mode 100644
index 0000000000..1be71d9945
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/logo-big.jpg
Binary files differ
diff --git a/tests/auto/quick/scenegraph/data/logo-small.jpg b/tests/auto/quick/scenegraph/data/logo-small.jpg
new file mode 100644
index 0000000000..f11a5dfc6b
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/logo-small.jpg
Binary files differ
diff --git a/src/quick/scenegraph/qsgflashnode_p.h b/tests/auto/quick/scenegraph/data/manyWindows_dftext.qml
index 96496158ae..69d235d021 100644
--- a/src/quick/scenegraph/qsgflashnode_p.h
+++ b/tests/auto/quick/scenegraph/data/manyWindows_dftext.qml
@@ -3,7 +3,7 @@
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQuick module of the Qt Toolkit.
+** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,25 +39,12 @@
**
****************************************************************************/
-#ifndef QSGFLASHNODE_H
-#define QSGFLASHNODE_H
+import QtQuick 2.2
-#include <QtQuick/QSGSimpleRectNode>
-
-QT_BEGIN_NAMESPACE
-
-class QSGFlashNode : public QSGSimpleRectNode
+Text
{
-public:
- QSGFlashNode();
-
- void preprocess();
-
-private:
- int m_counter;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSGFLASHNODE_H
-
+ width: 100
+ height: 100
+ text: "abcdefghijklmnopqrstuwABCDEFGHIJKLMNOPPQRSTUWXYZ1234567890!@#$%^&*()_"
+ wrapMode: Text.WrapAnywhere
+}
diff --git a/src/quick/scenegraph/qsgflashnode.cpp b/tests/auto/quick/scenegraph/data/manyWindows_image.qml
index 7fbe673e15..1b356110ed 100644
--- a/src/quick/scenegraph/qsgflashnode.cpp
+++ b/tests/auto/quick/scenegraph/data/manyWindows_image.qml
@@ -3,7 +3,7 @@
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQuick module of the Qt Toolkit.
+** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,24 +39,14 @@
**
****************************************************************************/
-#include "qsgflashnode_p.h"
+import QtQuick 2.2
-QT_BEGIN_NAMESPACE
-
-QSGFlashNode::QSGFlashNode()
- : m_counter(1)
-{
- setFlag(UsePreprocess);
- setColor(QColor(rand()%56 + 200, rand()%56 + 200, rand()%156 + 100)); // A random, mostly yellow, color
-}
-
-void QSGFlashNode::preprocess()
-{
- if (m_counter) {
- --m_counter;
- } else {
- delete this;
+Image {
+ width: 100
+ height: 100
+ source: "logo-big.jpg"
+ Image {
+ anchors.centerIn: parent
+ source: "logo-small.jpg"
}
}
-
-QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4unwindhelper_p.h b/tests/auto/quick/scenegraph/data/manyWindows_ntext.qml
index 9ef564449a..ebd06e360b 100644
--- a/src/qml/jsruntime/qv4unwindhelper_p.h
+++ b/tests/auto/quick/scenegraph/data/manyWindows_ntext.qml
@@ -3,7 +3,7 @@
** 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.
+** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,34 +39,13 @@
**
****************************************************************************/
-#ifndef QV4UNWINDHELPER_H
-#define QV4UNWINDHELPER_H
+import QtQuick 2.2
-#include <QtCore/QVector>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-struct Function;
-struct ExecutionContext;
-
-class UnwindHelper
+Text
{
-public:
- static void prepareForUnwind(ExecutionContext *ctx);
- static void registerFunction(Function *function);
- static void registerFunctions(const QVector<Function *> &functions);
- static void deregisterFunction(Function *function);
- static void deregisterFunctions(const QVector<Function *> &functions);
-#ifdef Q_PROCESSOR_ARM
- static int unwindInfoSize();
- static void writeARMUnwindInfo(void *codeAddr, int codeSize);
-#endif
-};
-
+ width: 100
+ height: 100
+ text: "abcdefghijklmnopqrstuwABCDEFGHIJKLMNOPPQRSTUWXYZ1234567890!@#$%^&*()_"
+ wrapMode: Text.WrapAnywhere
+ renderType: Text.NativeRendering
}
-
-QT_END_NAMESPACE
-
-#endif // QV4UNWINDHELPER_H
diff --git a/tests/auto/quick/scenegraph/data/manyWindows_rects.qml b/tests/auto/quick/scenegraph/data/manyWindows_rects.qml
new file mode 100644
index 0000000000..984968985a
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/manyWindows_rects.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.2
+
+Rectangle {
+ width: 100
+ height: 100
+
+ gradient: Gradient {
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: 1; color: "red" }
+ }
+
+ Rectangle {
+ width: 40
+ height: 40
+ rotation: 30
+ color: "#00ff00";
+ antialiasing: true
+ x: parent.width / 3 - width / 2
+ y: parent.height / 3 - height/ 2
+ }
+ Rectangle {
+ width: 40
+ height: 40
+ rotation: 30
+ color: "blue"
+ x: parent.width * 2 / 3 - width / 2
+ y: parent.height * 2 / 3 - height/ 2
+ }
+}
diff --git a/tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml b/tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml
new file mode 100644
index 0000000000..a43d7c5449
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.2
+
+/*
+ The test verifies that batches of translucent items get split
+ into multiple batches when an item in them change opacity.
+
+ PixelPos R G B Error-tolerance
+ #base: 0 0 1.0 0.5 0.5 0.05
+ #base: 100 0 0.5 0.5 1.0 0.05
+ #base: 0 100 1.0 0.5 0.5 0.05
+ #base: 100 100 0.5 0.5 1.0 0.05
+ #final: 0 0 1.0 0.5 0.5 0.05
+ #final: 100 0 0.1 0.1 1.0 0.05
+ #final: 0 100 1.0 0.5 0.5 0.05
+ #final: 100 100 0.9 0.9 1.0 0.05
+
+ #samples: 8
+*/
+
+RenderTestBase {
+
+ Item {
+ Rectangle { id: redUnclipped; opacity: 0.5; width: 50; height: 50; color: "red" }
+ Rectangle { id: blueUnclipped; opacity: 0.5; width: 50; height: 50; color: "blue"; x: 100 }
+ }
+
+ Item {
+ clip: true;
+ y: 100
+ width: 200
+ height: 100
+ Rectangle { id: redClipped; opacity: 0.5; width: 50; height: 50; color: "red" }
+ Rectangle { id: blueClipped; opacity: 0.5; width: 50; height: 50; color: "blue"; x: 100 }
+ }
+
+ onEnterFinalStage: {
+ blueUnclipped.opacity = 0.9
+ blueClipped.opacity = 0.1
+ finalStageComplete = true;
+ }
+
+}
diff --git a/tests/auto/quick/scenegraph/data/render_DrawSets.qml b/tests/auto/quick/scenegraph/data/render_DrawSets.qml
new file mode 100644
index 0000000000..7515bcf95a
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/render_DrawSets.qml
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.2
+
+/*
+ The purpose of the test is to verify that a batch of more than 64K
+ vertices gets split into multiple drawsets and still rendered correctly.
+ Both the clipped and unclipped batches have 50.000 rectangles resulting
+ in 200.000 vertices in each batch, which should be plenty..
+
+ #samples: 8
+
+ PixelPos R G B Error-tolerance
+ #base: 0 0 1.0 0.0 0.0 0.0
+ #base: 99 199 1.0 0.0 0.0 0.0
+ #base: 100 0 0.0 0.0 0.0 0.0
+ #base: 199 199 0.0 0.0 0.0 0.0
+ #final: 0 0 0.0 0.0 1.0 0.0
+ #final: 99 199 0.0 0.0 1.0 0.0
+ #final: 100 0 0.0 1.0 0.0 0.0
+ #final: 199 199 0.0 1.0 0.0 0.0
+*/
+
+RenderTestBase
+{
+ id: root
+
+ Grid {
+ id: clipped
+ width: 100
+ height: 500
+ clip: true
+ columns: 100
+ Repeater {
+ id: clippedRepeater
+ model: clipped.width * clipped.height
+ Rectangle {
+ width: 1
+ height: 1
+ color: index < clippedRepeater.model / 2 ? "red" : "blue";
+ }
+ }
+ }
+
+ Grid {
+ id: unclipped
+ x: 100
+ width: 100
+ height: 500
+ clip: true
+ columns: 100
+ Repeater {
+ id: unclippedRepeater
+ model: unclipped.width * unclipped.height
+ Rectangle {
+ width: 1
+ height: 1
+ color: index < unclippedRepeater.model / 2 ? "black" : "#00ff00";
+ }
+ }
+ }
+
+ SequentialAnimation {
+ id: animation
+ NumberAnimation { target: clipped; property: "y"; from: 0; to: -clipped.height + root.height; duration: 100 }
+ NumberAnimation { target: unclipped; property: "y"; from: 0; to: -unclipped.height + root.height; duration: 100 }
+ PropertyAction { target: root; property: "finalStageComplete"; value: true; }
+ }
+
+ onEnterFinalStage: {
+ animation.running = true;
+
+ }
+}
diff --git a/tests/auto/quick/scenegraph/data/render_MovingOverlap.qml b/tests/auto/quick/scenegraph/data/render_MovingOverlap.qml
new file mode 100644
index 0000000000..562f367500
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/render_MovingOverlap.qml
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.2
+
+/*
+ This test verifies that items that go from being batched because
+ of no overlap will be split into multiple batches because of an
+ overlap and that no rendering errors occur as a result of this.
+
+ #samples: 8
+ PixelPos R G B Error-tolerance
+ #base: 0 0 0.0 0.0 0.0 0.0
+ #base: 10 10 0.5 0.0 0.0 0.05
+ #base: 100 100 0.0 0.0 0.0 0.0
+ #base: 110 110 0.5 0.0 0.0 0.05
+ #final: 40 40 0.0 0.0 0.0 0.0
+ #final: 50 50 0.5 0.0 0.0 0.05
+ #final: 60 60 0.0 0.0 0.0 0.0
+ #final: 70 70 0.5 0.0 0.0 0.05
+*/
+
+RenderTestBase {
+ id: root
+
+ Rectangle {
+ id: one
+ x: 0
+ y: x
+ width: 80
+ height: 80
+ color: "black"
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 10
+ color: "red"
+ opacity: 0.5
+ }
+ }
+
+ Rectangle {
+ id: two
+ x: 100
+ y: x
+ width: 80
+ height: 80
+ color: "black"
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 10
+ color: "red"
+ opacity: 0.5
+ }
+ }
+
+ SequentialAnimation {
+ id: animation
+ ParallelAnimation {
+ NumberAnimation { target: one; property: "x"; from: 0; to: 40; duration: 100 }
+ NumberAnimation { target: two; property: "x"; from: 100; to: 60; duration: 100 }
+ }
+ PropertyAction { target: root; property: "finalStageComplete"; value: true; }
+ }
+
+ onEnterFinalStage: {
+ animation.running = true;
+ }
+
+}
diff --git a/tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml b/tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml
new file mode 100644
index 0000000000..60caa4d561
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.2
+
+/*
+ The test verifies that batching does not interfere with overlapping
+ regions.
+
+ #samples: 8
+ PixelPos R G B Error-tolerance
+ #base: 10 10 1.0 0.0 0.0 0.0
+ #base: 10 110 1.0 0.0 0.0 0.0
+ #base: 10 11 0.0 0.0 1.0 0.0
+ #base: 10 111 0.0 0.0 1.0 0.0
+
+ #final: 10 10 1.0 0.0 0.0 0.05
+ #final: 10 110 1.0 0.0 0.0 0.05
+ #final: 10 11 0.0 0.0 1.0 0.05
+ #final: 10 111 0.0 0.0 1.0 0.05
+*/
+
+RenderTestBase
+{
+ id: root
+ property real offset: 0;
+ property real farAway: 10000000;
+
+ Item {
+ y: -root.offset + 10
+ x: 10
+ Repeater {
+ model: 200
+ Rectangle {
+ x: index % 100
+ y: root.offset + (index < 100 ? 0 : 1);
+ width: 1
+ height: 1
+ color: index < 100 ? "red" : "blue"
+ antialiasing: true;
+ }
+ }
+ }
+
+ Item {
+ y: -root.offset + 110
+ x: 10
+ Item {
+ y: root.offset
+
+ Repeater {
+ model: 200
+ Rectangle {
+ x: index % 100
+ y: (index < 100 ? 0 : 1);
+ width: 1
+ height: 1
+ color: index < 100 ? "red" : "blue"
+ antialiasing: true;
+ }
+ }
+ }
+ }
+
+ onEnterFinalStage: {
+ root.offset = root.farAway;
+ root.finalStageComplete = true;
+ }
+
+}
diff --git a/tests/auto/quick/scenegraph/data/render_Overlap.qml b/tests/auto/quick/scenegraph/data/render_Overlap.qml
new file mode 100644
index 0000000000..8047114833
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/render_Overlap.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.2
+
+/*
+ The test verifies that batching does not interfere with overlapping
+ regions.
+
+ #samples: 4
+ PixelPos R G B Error-tolerance
+ #base: 20 20 0.0 0.0 0.0 0.0
+ #base: 30 30 0.5 0.0 0.0 0.05
+ #final: 50 50 0.0 0.0 0.0 0.0
+ #final: 60 60 0.5 0.0 0.0 0.05
+*/
+
+RenderTestBase
+{
+ Rectangle {
+ x: 20
+ y: 20
+ width: 80
+ height: 80
+ color: "black"
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 10
+ color: "red"
+ opacity: 0.5
+ }
+ }
+
+ Rectangle {
+ x: 50
+ y: 50
+ width: 80
+ height: 80
+ color: "black"
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 10
+ color: "red"
+ opacity: 0.5
+ }
+ }
+
+ finalStageComplete: true
+}
diff --git a/tests/auto/quick/scenegraph/data/render_StackingOrder.qml b/tests/auto/quick/scenegraph/data/render_StackingOrder.qml
new file mode 100644
index 0000000000..ab335004c2
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/render_StackingOrder.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.2
+
+/*
+ This test verifies that items that go from being batched because
+ of no overlap will be split into multiple batches because of an
+ overlap and that no rendering errors occur as a result of this.
+
+ #samples: 3
+ PixelPos R G B Error-tolerance
+ #final: 10 10 1.0 0.0 0.0 0.05
+ #final: 10 110 0.0 1.0 0.0 0.05
+ #final: 10 120 0.0 0.0 1.0 0.05
+*/
+
+RenderTestBase {
+ Item {
+ opacity: 0.99; // Just to trigger alpha batches
+ Rectangle { color: "#ff0000"; x: 10; y: 10; width: 20; height: 20; }
+ Image { source: "logo-small.jpg"; x: 10; y: 50; width: 50; height: 51; }
+ Rectangle { color: "#00ff00"; x: 10; y: 100; width: 50; height: 50; }
+ Rectangle { color: "#0000ff"; x: 10; y: 120; width: 10; height: 10; }
+ }
+ onEnterFinalStage: finalStageComplete = true;
+}
diff --git a/tests/auto/quick/scenegraph/scenegraph.pro b/tests/auto/quick/scenegraph/scenegraph.pro
new file mode 100644
index 0000000000..105221b7f4
--- /dev/null
+++ b/tests/auto/quick/scenegraph/scenegraph.pro
@@ -0,0 +1,14 @@
+CONFIG += testcase
+TARGET = tst_scenegraph
+SOURCES += tst_scenegraph.cpp
+
+include (../../shared/util.pri)
+
+macx:CONFIG -= app_bundle
+
+QT += core-private gui-private qml-private quick-private testlib
+
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+OTHER_FILES += \
+ data/render_OutOfFloatRange.qml
diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
new file mode 100644
index 0000000000..3b79f01f12
--- /dev/null
+++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
@@ -0,0 +1,407 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+#include <qtest.h>
+
+#include <QtQuick>
+
+#include <private/qsgcontext_p.h>
+
+
+#include <QtQml>
+
+class tst_SceneGraph : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void manyWindows_data();
+ void manyWindows();
+
+ void render_data();
+ void render();
+};
+
+template <typename T> class ScopedList : public QList<T> {
+public:
+ ~ScopedList() { qDeleteAll(*this); }
+};
+
+QQuickView *createView(const QString &file, QWindow *parent = 0, int x = -1, int y = -1, int w = -1, int h = -1)
+{
+ QQuickView *view = new QQuickView(parent);
+ view->setSource(QUrl::fromLocalFile("data/" + file));
+ if (x >= 0 && y >= 0) view->setPosition(x, y);
+ if (w >= 0 && h >= 0) view->resize(w, h);
+ view->show();
+ return view;
+}
+
+QImage showAndGrab(const QString &file, int w, int h)
+{
+ QQuickView view;
+ view.setSource(QUrl::fromLocalFile(QStringLiteral("data/") + file));
+ if (w >= 0 && h >= 0)
+ view.resize(w, h);
+ view.create();
+ return view.grabWindow();
+}
+
+// Assumes the images are opaque white...
+bool containsSomethingOtherThanWhite(const QImage &image)
+{
+ Q_ASSERT(image.format() == QImage::Format_ARGB32_Premultiplied
+ || image.format() == QImage::Format_RGB32);
+ int w = image.width();
+ int h = image.height();
+ for (int y=0; y<h; ++y) {
+ const uint *pixels = (const uint *) image.constScanLine(y);
+ for (int x=0; x<w; ++x)
+ if (pixels[x] != 0xffffffff)
+ return true;
+ }
+ return false;
+}
+
+// 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 = 1;
+ 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_SceneGraph::manyWindows_data()
+{
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<bool>("toplevel");
+ QTest::addColumn<bool>("shared");
+
+ QTest::newRow("image,toplevel") << QStringLiteral("manyWindows_image.qml") << true << false;
+ QTest::newRow("image,subwindow") << QStringLiteral("manyWindows_image.qml") << false << false;
+ QTest::newRow("dftext,toplevel") << QStringLiteral("manyWindows_dftext.qml") << true << false;
+ QTest::newRow("dftext,subwindow") << QStringLiteral("manyWindows_dftext.qml") << false << false;
+ QTest::newRow("ntext,toplevel") << QStringLiteral("manyWindows_ntext.qml") << true << false;
+ QTest::newRow("ntext,subwindow") << QStringLiteral("manyWindows_ntext.qml") << false << false;
+ QTest::newRow("rects,toplevel") << QStringLiteral("manyWindows_rects.qml") << true << false;
+ QTest::newRow("rects,subwindow") << QStringLiteral("manyWindows_rects.qml") << false << false;
+
+ QTest::newRow("image,toplevel,sharing") << QStringLiteral("manyWindows_image.qml") << true << true;
+ QTest::newRow("image,subwindow,sharing") << QStringLiteral("manyWindows_image.qml") << false << true;
+ QTest::newRow("dftext,toplevel,sharing") << QStringLiteral("manyWindows_dftext.qml") << true << true;
+ QTest::newRow("dftext,subwindow,sharing") << QStringLiteral("manyWindows_dftext.qml") << false << true;
+ QTest::newRow("ntext,toplevel,sharing") << QStringLiteral("manyWindows_ntext.qml") << true << true;
+ QTest::newRow("ntext,subwindow,sharing") << QStringLiteral("manyWindows_ntext.qml") << false << true;
+ QTest::newRow("rects,toplevel,sharing") << QStringLiteral("manyWindows_rects.qml") << true << true;
+ QTest::newRow("rects,subwindow,sharing") << QStringLiteral("manyWindows_rects.qml") << false << true;
+}
+
+struct ShareContextResetter {
+public:
+ ~ShareContextResetter() { QSGContext::setSharedOpenGLContext(0); }
+};
+
+void tst_SceneGraph::manyWindows()
+{
+ QFETCH(QString, file);
+ QFETCH(bool, toplevel);
+ QFETCH(bool, shared);
+
+ QOpenGLContext sharedGLContext;
+ ShareContextResetter cleanup; // To avoid dangling pointer in case of test-failure.
+ if (shared) {
+ sharedGLContext.create();
+ QSGContext::setSharedOpenGLContext(&sharedGLContext);
+ }
+
+ QScopedPointer<QWindow> parent;
+ if (!toplevel) {
+ parent.reset(new QWindow());
+ parent->resize(200, 200);
+ parent->show();
+ }
+
+ ScopedList <QQuickView *> views;
+
+ const int COUNT = 4;
+
+ QImage baseLine;
+ for (int i=0; i<COUNT; ++i) {
+ views << createView(file, parent.data(), (i % 2) * 100, (i / 2) * 100, 100, 100);
+ }
+ for (int i=0; i<COUNT; ++i) {
+ QQuickView *view = views.at(i);
+ QTest::qWaitForWindowExposed(view);
+ QImage content = view->grabWindow();
+ if (i == 0) {
+ baseLine = content;
+ QVERIFY(containsSomethingOtherThanWhite(baseLine));
+ } else {
+ QVERIFY(compareImages(content, baseLine));
+ }
+ }
+
+ // Wipe and recreate one (scope pointer delets it...)
+ delete views.takeLast();
+ QQuickView *last = createView(file, parent.data(), 100, 100, 100, 100);
+ QTest::qWaitForWindowExposed(last);
+ views << last;
+ QVERIFY(compareImages(baseLine, last->grabWindow()));
+
+ // Wipe and recreate all
+ qDeleteAll(views);
+ views.clear();
+
+ for (int i=0; i<COUNT; ++i) {
+ views << createView(file, parent.data(), (i % 2) * 100, (i / 2) * 100, 100, 100);
+ }
+ for (int i=0; i<COUNT; ++i) {
+ QQuickView *view = views.at(i);
+ QTest::qWaitForWindowExposed(view);
+ QImage content = view->grabWindow();
+ QVERIFY(compareImages(content, baseLine));
+ }
+}
+
+struct Sample {
+ Sample(int xx, int yy, qreal rr, qreal gg, qreal bb, qreal errorMargin = 0.05)
+ : x(xx)
+ , y(yy)
+ , r(rr)
+ , g(gg)
+ , b(bb)
+ , tolerance(errorMargin)
+ {
+ }
+ Sample(const Sample &o) : x(o.x), y(o.y), r(o.r), g(o.g), b(o.b), tolerance(o.tolerance) { }
+ Sample() : x(0), y(0), r(0), g(0), b(0), tolerance(0) { }
+
+ QString toString(const QImage &image) const {
+ QColor color(image.pixel(x,y));
+ return QString::fromLatin1("pixel(%1,%2), rgb(%3,%4,%5), tolerance=%6 -- image(%7,%8,%9)")
+ .arg(x).arg(y)
+ .arg(r).arg(g).arg(b)
+ .arg(tolerance)
+ .arg(color.redF()).arg(color.greenF()).arg(color.blueF());
+ }
+
+ bool check(const QImage &image) {
+ QColor color(image.pixel(x, y));
+ return qAbs(color.redF() - r) <= tolerance
+ && qAbs(color.greenF() - g) <= tolerance
+ && qAbs(color.blueF() - b) <= tolerance;
+ }
+
+
+ int x, y;
+ qreal r, g, b;
+ qreal tolerance;
+};
+
+static Sample sample_from_regexp(QRegExp *re) {
+ return Sample(re->cap(1).toInt(),
+ re->cap(2).toInt(),
+ re->cap(3).toFloat(),
+ re->cap(4).toFloat(),
+ re->cap(5).toFloat(),
+ re->cap(6).toFloat()
+ );
+}
+
+Q_DECLARE_METATYPE(Sample);
+
+/*
+ The render() test implements a small test framework for itself with
+ the purpose of testing odds and ends of the scene graph
+ rendering. Each .qml file can consist of one or two stages. The
+ first stage is when the file is first displayed. The content is
+ grabbed and matched against 'base' samples defined in the .qml file
+ itself. The samples contain a pixel position, and RGB value and a
+ margin of error. The samples are defined in the .qml file so it is
+ easy to make the connection between colors and positions on the screen.
+
+ If the base stage samples all succeed, the test emits
+ 'enterFinalStage' on the root item and waits for the .qml file to
+ update the value of 'finalStageComplete' The test can set this
+ directly or run an animation and set it later. Once the
+ 'finalStageComplete' variable is true, we grab and match against the
+ second set of samples 'final'
+
+ The samples in the .qml file are defined in comments on the format:
+ #base: x y r g b error-tolerance
+ #final: x y r g b error-tolerance
+ - x and y are integers
+ - r g b are floats in the range of 0.0-1.0
+ - error-tolerance is a float in the range of 0.0-1.0
+
+ We also include a
+ #samples: count
+ to sanity check that all base/final samples were matched correctly
+ as the matching regexp is a bit crude.
+
+ To add new tests, add them to the 'files' list and put #base,
+ #final, #samples tags into the .qml file
+*/
+
+void tst_SceneGraph::render_data()
+{
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<QList<Sample> >("baseStage");
+ QTest::addColumn<QList<Sample> >("finalStage");
+
+ QList<QString> files;
+ files << "data/render_DrawSets.qml"
+ << "data/render_Overlap.qml"
+ << "data/render_MovingOverlap.qml"
+ << "data/render_BreakOpacityBatch.qml"
+ << "data/render_OutOfFloatRange.qml"
+ << "data/render_StackingOrder.qml"
+ ;
+
+ QRegExp sampleCount("#samples: *(\\d+)");
+ // X:int Y:int R:float G:float B:float Error:float
+ QRegExp baseSamples("#base: *(\\d+) *(\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+)");
+ QRegExp finalSamples("#final: *(\\d+) *(\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+)");
+
+ foreach (QString fileName, files) {
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ qFatal("render_data: QFile::open failed! file=%s, error=%s",
+ qPrintable(fileName), qPrintable(file.errorString()));
+ }
+ QStringList contents = QString::fromLatin1(file.readAll()).split(QLatin1Char('\n'));
+
+ int samples = -1;
+ foreach (QString line, contents) {
+ if (sampleCount.indexIn(line) >= 0) {
+ samples = sampleCount.cap(1).toInt();
+ break;
+ }
+ }
+ if (samples == -1)
+ qFatal("render_data: failed to find string '#samples: [count], file=%s", qPrintable(fileName));
+
+ QList<Sample> baseStage, finalStage;
+ foreach (QString line, contents) {
+ if (baseSamples.indexIn(line) >= 0)
+ baseStage << sample_from_regexp(&baseSamples);
+ else if (finalSamples.indexIn(line) >= 0)
+ finalStage << sample_from_regexp(&finalSamples);
+ }
+
+ if (baseStage.size() + finalStage.size() != samples)
+ qFatal("render_data: #samples does not add up to number of counted samples, file=%s", qPrintable(fileName));
+
+ QTest::newRow(qPrintable(fileName)) << fileName << baseStage << finalStage;
+ }
+}
+
+void tst_SceneGraph::render()
+{
+ QFETCH(QString, file);
+ QFETCH(QList<Sample>, baseStage);
+ QFETCH(QList<Sample>, finalStage);
+
+ QObject suite;
+ suite.setObjectName("The Suite");
+
+ QQuickView view;
+ view.rootContext()->setContextProperty("suite", &suite);
+ view.setSource(QUrl::fromLocalFile(file));
+ view.setResizeMode(QQuickView::SizeViewToRootObject);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ // Grab the window and check all our base stage samples
+ QImage content = view.grabWindow();
+ for (int i=0; i<baseStage.size(); ++i) {
+ Sample sample = baseStage.at(i);
+ QVERIFY2(sample.check(content), qPrintable(sample.toString(content)));
+ }
+
+ // Put the qml file into the final stage and wait for it to
+ // complete it.
+ QQuickItem *rootItem = view.rootObject();
+ QMetaObject::invokeMethod(rootItem, "enterFinalStage");
+ QTRY_VERIFY(rootItem->property("finalStageComplete").toBool());
+
+ // The grab the results and verify the samples in the end state.
+ content = view.grabWindow();
+ for (int i=0; i<finalStage.size(); ++i) {
+ Sample sample = finalStage.at(i);
+ QVERIFY2(sample.check(content), qPrintable(sample.toString(content)));
+ }
+}
+
+#include "tst_scenegraph.moc"
+
+QTEST_MAIN(tst_SceneGraph)
+
diff --git a/tests/auto/shared/testhttpserver.cpp b/tests/auto/shared/testhttpserver.cpp
index fd681710de..20df0c12f5 100644
--- a/tests/auto/shared/testhttpserver.cpp
+++ b/tests/auto/shared/testhttpserver.cpp
@@ -88,7 +88,7 @@ The following request urls will then result in the appropriate action:
\endtable
*/
TestHTTPServer::TestHTTPServer(quint16 port)
-: m_hasFailed(false)
+: m_state(AwaitingHeader)
{
QObject::connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection()));
@@ -122,7 +122,8 @@ void TestHTTPServer::addRedirect(const QString &filename, const QString &redirec
bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &body)
{
- m_hasFailed = false;
+ m_state = AwaitingHeader;
+ m_data.clear();
QFile expectFile(expect.toLocalFile());
if (!expectFile.open(QIODevice::ReadOnly)) return false;
@@ -175,7 +176,7 @@ bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &bod
bool TestHTTPServer::hasFailed() const
{
- return m_hasFailed;
+ return m_state == Failed;
}
void TestHTTPServer::newConnection()
@@ -216,33 +217,41 @@ void TestHTTPServer::readyRead()
return;
}
- if (m_hasFailed || (waitData.body.isEmpty() && waitData.headers.count() == 0)) {
+ if (m_state == Failed || (waitData.body.isEmpty() && waitData.headers.count() == 0)) {
qWarning() << "TestHTTPServer: Unexpected data" << socket->readAll();
return;
}
- QByteArray line;
- while (!(line = socket->readLine()).isEmpty()) {
- line.replace('\r', "");
- if (line.at(0) == '\n') {
- QByteArray data = socket->readAll();
- if (waitData.body != data) {
- qWarning() << "TestHTTPServer: Unexpected data" << data << "\nExpected: " << waitData.body;
- m_hasFailed = true;
- socket->disconnectFromHost();
- return;
+ if (m_state == AwaitingHeader) {
+ QByteArray line;
+ while (!(line = socket->readLine()).isEmpty()) {
+ line.replace('\r', "");
+ if (line.at(0) == '\n') {
+ m_state = AwaitingData;
+ m_data += socket->readAll();
+ break;
+ } else {
+ if (!waitData.headers.contains(line)) {
+ qWarning() << "TestHTTPServer: Unexpected header:" << line << "\nExpected headers: " << waitData.headers;
+ m_state = Failed;
+ socket->disconnectFromHost();
+ return;
+ }
}
}
- else if (!waitData.headers.contains(line)) {
- qWarning() << "TestHTTPServer: Unexpected header:" << line << "\nExpected headers: " << waitData.headers;
- m_hasFailed = true;
- socket->disconnectFromHost();
- return;
- }
+ } else {
+ m_data += socket->readAll();
}
- socket->write(replyData);
- socket->disconnectFromHost();
+ if (!m_data.isEmpty() || waitData.body.isEmpty()) {
+ if (waitData.body != m_data) {
+ qWarning() << "TestHTTPServer: Unexpected data" << m_data << "\nExpected: " << waitData.body;
+ m_state = Failed;
+ } else {
+ socket->write(replyData);
+ }
+ socket->disconnectFromHost();
+ }
}
bool TestHTTPServer::reply(QTcpSocket *socket, const QByteArray &fileName)
diff --git a/tests/auto/shared/testhttpserver.h b/tests/auto/shared/testhttpserver.h
index ce0501f170..ae7d137143 100644
--- a/tests/auto/shared/testhttpserver.h
+++ b/tests/auto/shared/testhttpserver.h
@@ -74,6 +74,12 @@ private slots:
void sendOne();
private:
+ enum State {
+ AwaitingHeader,
+ AwaitingData,
+ Failed
+ };
+
void serveGET(QTcpSocket *, const QByteArray &);
bool reply(QTcpSocket *, const QByteArray &);
@@ -87,7 +93,8 @@ private:
} waitData;
QByteArray replyData;
QByteArray bodyData;
- bool m_hasFailed;
+ QByteArray m_data;
+ State m_state;
QHash<QString,QString> aliases;
QHash<QString,QString> redirects;
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 804e907cc0..804241f023 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -42,13 +42,17 @@
#include "conf.h"
#include <QCoreApplication>
+
+#ifdef QT_GUI_LIB
#include <QGuiApplication>
+#include <QWindow>
+#include <QFileOpenEvent>
#ifdef QT_WIDGETS_LIB
#include <QApplication>
-#endif
-#include <QWindow>
+#endif // QT_WIDGETS_LIB
+#endif // QT_GUI_LIB
+
#include <QQmlApplicationEngine>
-#include <QFileOpenEvent>
#include <QFile>
#include <QFileInfo>
#include <QRegularExpression>
@@ -68,8 +72,11 @@
#define VERSION_MIN 0
#define VERSION_STR "1.0"
+#define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms
+
static Config *conf = 0;
static QQmlApplicationEngine *qae = 0;
+static int exitTimerId = -1;
static void loadConf(const QString &override, bool quiet) // Terminates app on failure
{
@@ -90,7 +97,8 @@ static void loadConf(const QString &override, bool quiet) // Terminates app on f
QFileInfo fi;
fi.setFile(override);
if (!fi.exists()) {
- qCritical() << QObject::tr("qml: Couldn't find required configuration file:") << fi.absoluteFilePath();
+ printf("qml: Couldn't find required configuration file: %s\n",
+ qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath())));
exit(1);
}
settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath());
@@ -98,9 +106,12 @@ static void loadConf(const QString &override, bool quiet) // Terminates app on f
if (!quiet) {
if (builtIn)
- qWarning() << QObject::tr("qml: Using built-in configuration.");
+ printf("qml: Using built-in configuration.\n");
else
- qWarning() << QObject::tr("qml: Using configuration file:") << settingsUrl;
+ printf("qml: Using configuration file: %s\n",
+ qPrintable(settingsUrl.isLocalFile()
+ ? QDir::toNativeSeparators(settingsUrl.toLocalFile())
+ : settingsUrl.toString()));
}
// TODO: When we have better engine control, ban QtQuick* imports on this engine
@@ -109,7 +120,7 @@ static void loadConf(const QString &override, bool quiet) // Terminates app on f
conf = qobject_cast<Config*>(c2.create());
if (!conf){
- qCritical() << QObject::tr("qml: Error loading configuration file:") << c2.errorString();
+ printf("qml: Error loading configuration file: %s\n", qPrintable(c2.errorString()));
exit(1);
}
}
@@ -128,6 +139,10 @@ void contain(QObject *o, const QUrl &containPath)
o->setParent(o2); //Set QObject parent, and assume container will react as needed
}
+#ifdef QT_GUI_LIB
+
+void noFilesGiven();
+
// Loads qml after receiving a QFileOpenEvent
class LoaderApplication : public QGuiApplication
{
@@ -136,14 +151,25 @@ public:
bool event(QEvent *ev)
{
- if (ev->type() == QEvent::FileOpen)
+ if (ev->type() == QEvent::FileOpen) {
+ if (exitTimerId >= 0) {
+ killTimer(exitTimerId);
+ exitTimerId = -1;
+ }
qae->load(static_cast<QFileOpenEvent *>(ev)->url());
+ }
else
return QGuiApplication::event(ev);
return true;
}
+
+ void timerEvent(QTimerEvent *) {
+ noFilesGiven();
+ }
};
+#endif // QT_GUI_LIB
+
// Listens to the appEngine signals to determine if all files failed to load
class LoadWatcher : public QObject
{
@@ -176,7 +202,7 @@ public Q_SLOTS:
return;
if (! --expect) {
- qCritical() << QObject::tr("qml: Did not load any objects, exiting.");
+ printf("qml: Did not load any objects, exiting.\n");
exit(2);//Different return code from qFatal
}
}
@@ -200,9 +226,24 @@ void quietMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, const Q
// ### Should command line arguments have translations? Qt creator doesn't, so maybe it's not worth it.
-bool useCoreApp = false;
-bool useWidgetApp = false;
+enum QmlApplicationType {
+ QmlApplicationTypeUnknown
+ , QmlApplicationTypeCore
+#ifdef QT_GUI_LIB
+ , QmlApplicationTypeGui
+#ifdef QT_WIDGETS_LIB
+ , QmlApplicationTypeWidget
+#endif // QT_WIDGETS_LIB
+#endif // QT_GUI_LIB
+};
+
+#ifndef QT_GUI_LIB
+QmlApplicationType applicationType = QmlApplicationTypeCore;
+#else
+QmlApplicationType applicationType = QmlApplicationTypeGui;
+#endif // QT_GUI_LIB
bool quietMode = false;
+bool verboseMode = false;
void printVersion()
{
printf("qml binary version ");
@@ -220,19 +261,26 @@ void printUsage()
printf("Any argument ending in .qml will be treated as a QML file to be loaded.\n");
printf("Any number of QML files can be loaded. They will share the same engine.\n");
printf("Any argument which is not a recognized option and which does not end in .qml will be ignored.\n");
+ printf("'gui' application type is only available if the QtGui module is avaialble.\n");
printf("'widget' application type is only available if the QtWidgets module is avaialble.\n");
printf("\n");
printf("General Options:\n");
printf("\t-h, -help..................... Print this usage information and exit.\n");
printf("\t-v, -version.................. Print the version information and exit.\n");
+#ifdef QT_GUI_LIB
+#ifndef QT_WIDGETS_LIB
+ printf("\t-apptype [core|gui] .......... Select which application class to use. Default is gui.\n");
+#else
printf("\t-apptype [core|gui|widget] ... Select which application class to use. Default is gui.\n");
+#endif // QT_WIDGETS_LIB
+#endif // QT_GUI_LIB
printf("\t-quiet ....................... Suppress all output.\n");
printf("\t-I [path] .................... Prepend the given path to the import paths.\n");
printf("\t-f [file] .................... Load the given file as a QML file.\n");
printf("\t-config [file] ............... Load the given file as the configuration file.\n");
printf("\t-- ........................... Arguments after this one are ignored by the launcher, but may be used within the QML application.\n");
printf("\tDebugging options:\n");
- printf("\t-enable-debugger ............. Allow the QML debugger to connect to the application (also requires debugger arguments).\n");
+ printf("\t-verbose ..................... Print information about what qml is doing, like specific file urls being loaded.\n");
printf("\t-translation [file] .......... Load the given file as the translations file.\n");
printf("\t-dummy-data [directory] ...... Load QML files from the given directory as context properties.\n");
printf("\t-slow-animations ............. Run all animations in slow motion.\n");
@@ -240,59 +288,58 @@ void printUsage()
exit(0);
}
+void noFilesGiven()
+{
+ if (!quietMode)
+ printf("qml: No files specified. Terminating.\n");
+ exit(1);
+}
+
//Called before application initialization, removes arguments it uses
void getAppFlags(int &argc, char **argv)
{
+#ifdef QT_GUI_LIB
for (int i=0; i<argc; i++) {
if (!strcmp(argv[i], "-apptype")) { // Must be done before application, as it selects application
- int type = 0;
+ applicationType = QmlApplicationTypeUnknown;
if (i+1 < argc) {
if (!strcmp(argv[i+1], "core"))
- type = 1;
+ applicationType = QmlApplicationTypeCore;
else if (!strcmp(argv[i+1], "gui"))
- type = 2;
+ applicationType = QmlApplicationTypeGui;
#ifdef QT_WIDGETS_LIB
else if (!strcmp(argv[i+1], "widget"))
- type = 3;
-#endif
+ applicationType = QmlApplicationTypeWidget;
+#endif // QT_WIDGETS_LIB
}
- if (!type) {
-#ifdef QT_WIDGETS_LIB
- printf("-apptype must be followed by one of the following: core gui widget\n");
-#else
+ if (applicationType == QmlApplicationTypeUnknown) {
+#ifndef QT_WIDGETS_LIB
printf("-apptype must be followed by one of the following: core gui\n");
-#endif
+#else
+ printf("-apptype must be followed by one of the following: core gui widget\n");
+#endif // QT_WIDGETS_LIB
printUsage();
}
-
- switch (type) {
- case 1: useCoreApp = true; break;
- case 2: useCoreApp = false; break;
-#ifdef QT_WIDGETS_LIB
- case 3: useWidgetApp = true; break;
-#endif
- }
for (int j=i; j<argc-2; j++)
argv[j] = argv[j+2];
argc -= 2;
- } else if (!strcmp(argv[i], "-enable-debugger")) { // Normally done via a define in the include, so expects to be before application (and must be before engine)
- static QQmlDebuggingEnabler qmlEnableDebuggingHelper(true);
- for (int j=i; j<argc-1; j++)
- argv[j] = argv[j+1];
- argc --;
}
}
+#endif // QT_GUI_LIB
}
-void getFileSansBangLine(const QString &path, QByteArray &output)
+bool getFileSansBangLine(const QString &path, QByteArray &output)
{
QFile f(path);
if (!f.open(QFile::ReadOnly | QFile::Text))
- return;
+ return false;
output = f.readAll();
- if (output.startsWith("#!"))//Remove first line in this case (except \n, to avoid disturbing line count)
+ if (output.startsWith("#!")) {//Remove first line in this case (except \n, to avoid disturbing line count)
output.remove(0, output.indexOf('\n'));
+ return true;
+ }
+ return false;
}
static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
@@ -315,7 +362,7 @@ static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
}
if (dummyData && !quietMode) {
- qWarning() << QObject::tr("qml: Loaded dummy data:") << dir.filePath(qml);
+ printf("qml: Loaded dummy data: %s\n", qPrintable(dir.filePath(qml)));
qml.truncate(qml.length()-4);
engine.rootContext()->setContextProperty(qml, dummyData);
dummyData->setParent(&engine);
@@ -326,15 +373,25 @@ static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
int main(int argc, char *argv[])
{
getAppFlags(argc, argv);
- QCoreApplication *app;
- if (useCoreApp)
+ QCoreApplication *app = 0;
+ switch (applicationType) {
+ case QmlApplicationTypeCore:
app = new QCoreApplication(argc, argv);
+ break;
+#ifdef QT_GUI_LIB
+ case QmlApplicationTypeGui:
+ app = new LoaderApplication(argc, argv);
+ break;
#ifdef QT_WIDGETS_LIB
- else if (useWidgetApp)
+ case QmlApplicationTypeWidget:
app = new QApplication(argc, argv);
-#endif
- else
- app = new LoaderApplication(argc, argv);
+ break;
+#endif // QT_WIDGETS_LIB
+#endif // QT_GUI_LIB
+ default:
+ Q_ASSERT_X(false, Q_FUNC_INFO, "impossible case");
+ break;
+ }
app->setApplicationName("Qml Runtime");
app->setOrganizationName("Qt Project");
@@ -360,6 +417,8 @@ int main(int argc, char *argv[])
printUsage();
else if (arg == QLatin1String("--"))
break;
+ else if (arg == QLatin1String("-verbose"))
+ verboseMode = true;
else if (arg == QLatin1String("-slow-animations"))
QUnifiedTimer::instance()->setSlowModeEnabled(true);
else if (arg == QLatin1String("-fixed-animations"))
@@ -396,39 +455,44 @@ int main(int argc, char *argv[])
}
}
+ if (quietMode && verboseMode)
+ verboseMode = false;
+
#ifndef QT_NO_TRANSLATION
//qt_ translations loaded by QQmlApplicationEngine
- QTranslator qmlTranslator;
QString sysLocale = QLocale::system().name();
- if (qmlTranslator.load(QLatin1String("qml_") + sysLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
- app->installTranslator(&qmlTranslator);
if (!translationFile.isEmpty()) { //Note: installed before QQmlApplicationEngine's automatic translation loading
QTranslator translator;
if (translator.load(translationFile)) {
app->installTranslator(&translator);
+ if (verboseMode)
+ printf("qml: Loaded translation file %s\n", qPrintable(QDir::toNativeSeparators(translationFile)));
} else {
if (!quietMode)
- qWarning() << "qml: Could not load the translation file" << translationFile;
+ printf("qml: Could not load the translation file %s\n", qPrintable(QDir::toNativeSeparators(translationFile)));
}
}
#else
if (!translationFile.isEmpty() && !quietMode)
- qWarning() << "qml: Translation file specified, but Qt built without translation support.";
+ printf("qml: Translation file specified, but Qt built without translation support.\n");
#endif
if (quietMode)
qInstallMessageHandler(quietMessageHandler);
if (files.count() <= 0) {
- if (!quietMode)
- qCritical() << QObject::tr("qml: No files specified. Terminating.");
- exit(1);
+#if defined(Q_OS_MAC)
+ if (applicationType == QmlApplicationTypeGui)
+ exitTimerId = static_cast<LoaderApplication *>(app)->startTimer(FILE_OPEN_EVENT_WAIT_TIME);
+ else
+#endif
+ noFilesGiven();
}
qae = &e;
- loadConf(confFile, quietMode);
+ loadConf(confFile, !verboseMode);
//Load files
LoadWatcher lw(&e, files.count());
@@ -438,22 +502,21 @@ int main(int argc, char *argv[])
QRegularExpression urlRe("[[:word:]]+://.*");
if (urlRe.match(path).hasMatch()) { //Treat as a URL
QUrl url = QUrl::fromUserInput(path);
- if (!quietMode)
- qDebug() << QObject::tr("qml: loading ") << url;
+ if (verboseMode)
+ printf("qml: loading %s\n",
+ qPrintable(url.isLocalFile()
+ ? QDir::toNativeSeparators(url.toLocalFile())
+ : url.toString()));
e.load(url);
} else { //Local file path
- if (!quietMode) {
- qDebug() << QObject::tr("qml: loading ") << path;
- QByteArray strippedFile;
- getFileSansBangLine(path, strippedFile);
- if (strippedFile.isEmpty())
- // If there's an error opening the file, this will give us the right error message
- e.load(path);
- else
- e.loadData(strippedFile, QUrl::fromLocalFile(path));
- } else {
+ if (verboseMode)
+ printf("qml: loading %s\n", qPrintable(QDir::toNativeSeparators(path)));
+
+ QByteArray strippedFile;
+ if (getFileSansBangLine(path, strippedFile))
+ e.loadData(strippedFile, e.baseUrl().resolved(QUrl::fromLocalFile(path))); //QQmlComponent won't resolve it for us, it doesn't know it's a valid file if we loadData
+ else //Errors or no bang line
e.load(path);
- }
}
}
diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro
index fd4021c340..fe90916980 100644
--- a/tools/qml/qml.pro
+++ b/tools/qml/qml.pro
@@ -1,4 +1,5 @@
-QT += qml gui core-private
+QT = qml core-private
+qtHaveModule(gui): QT += gui
qtHaveModule(widgets): QT += widgets
HEADERS += conf.h
@@ -11,4 +12,6 @@ mac {
ICON = qml.icns
}
+DEFINES += QT_QML_DEBUG_NO_WARNING
+
load(qt_tool)
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 755ab452ee..08b88142bb 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -47,6 +47,7 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
+#include <QtCore/QDirIterator>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QSet>
@@ -68,12 +69,13 @@ QStringList g_qmlImportPaths;
void printUsage(const QString &appName)
{
std::cerr << qPrintable(QString::fromLatin1(
- "Usage: %1 -rootPath qmldir -importPath importPath \n"
- "Example: %1 -rootPath qmldir -importPath importPath").arg(
+ "Usage: %1 -rootPath path/to/app/qml/directory -importPath path/to/qt/qml/directory \n"
+ " %1 -qmlFiles file1 file2 -importPath path/to/qt/qml/directory \n"
+ "Example: %1 -rootPath . -importPath /home/user/dev/qt-install/qml \n").arg(
appName));
}
-QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, const QByteArray &code, const QString &path)
+QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, const QString &code, const QString &path)
{
QVariantList imports;
@@ -87,8 +89,13 @@ QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, con
if (!importNode->fileName.isEmpty()) {
QString name = importNode->fileName.toString();
import[QStringLiteral("name")] = name;
- import[QStringLiteral("type")] = QStringLiteral("directory");
- import[QStringLiteral("path")] = path + QLatin1Char('/') + name;
+ if (name.endsWith(QStringLiteral(".js"))) {
+ import[QStringLiteral("type")] = QStringLiteral("javascript");
+ } else {
+ import[QStringLiteral("type")] = QStringLiteral("directory");
+ }
+
+ import[QStringLiteral("path")] = QDir::cleanPath(path + QLatin1Char('/') + name);
} else {
// Walk the id chain ("Foo" -> "Bar" -> etc)
QString name;
@@ -111,51 +118,6 @@ QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, con
return imports;
}
-// Scan a single qml file for import statements
-QVariantList findQmlImportsInFile(const QString &qmlFilePath)
-{
- QFile qmlFile(qmlFilePath);
- if (!qmlFile.open(QIODevice::ReadOnly)) {
- std::cerr << "Cannot open input file " << qPrintable(QDir::toNativeSeparators(qmlFile.fileName()))
- << ':' << qPrintable(qmlFile.errorString()) << std::endl;
- return QVariantList();
- }
- QByteArray code = qmlFile.readAll();
-
- QQmlJS::Engine engine;
- QQmlJS::Lexer lexer(&engine);
- lexer.setCode(QString::fromUtf8(code), /*line = */ 1);
- QQmlJS::Parser parser(&engine);
-
- if (!parser.parse() || !parser.diagnosticMessages().isEmpty()) {
- // Extract errors from the parser
- foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
- std::cerr << qPrintable(QDir::toNativeSeparators(qmlFile.fileName())) << ':'
- << m.loc.startLine << ':' << qPrintable(m.message) << std::endl;
- }
- return QVariantList();
- }
-
- return findImportsInAst(parser.ast()->headers, code, QFileInfo(qmlFilePath).absolutePath());
-}
-
-// Scan all qml files in directory for import statements
-QVariantList findQmlImportsInDirectory(const QString &qmlDir)
-{
- QVariantList ret;
- if (qmlDir.isEmpty())
- return ret;
-
- QStringList qmlFileNames = QDir(qmlDir).entryList(QStringList(QStringLiteral("*.qml")));
- foreach (const QString &qmlFileName, qmlFileNames) {
- QString qmlFilePath = qmlDir + QLatin1Char('/') + qmlFileName;
- QVariantList imports = findQmlImportsInFile(qmlFilePath);
- ret.append(imports);
-
- }
- return ret;
-}
-
// Read the qmldir file, extract a list of plugins by
// parsing the "plugin" and "classname" lines.
QVariantMap pluginsForModulePath(const QString &modulePath) {
@@ -221,21 +183,51 @@ QVariantList findPathsForModuleImports(const QVariantList &imports)
foreach (QVariant importVariant, imports) {
QVariantMap import = qvariant_cast<QVariantMap>(importVariant);
if (import[QStringLiteral("type")] == QStringLiteral("module")) {
- import[QStringLiteral("path")] = resolveImportPath(import[QStringLiteral("name")].toString(), import[QStringLiteral("version")].toString());
- QVariantMap plugininfo = pluginsForModulePath(import[QStringLiteral("path")].toString());
- QString plugins = plugininfo[QStringLiteral("plugins")].toString();
- QString classnames = plugininfo[QStringLiteral("classnames")].toString();
- if (!plugins.isEmpty()) {
+ QString path = resolveImportPath(import.value(QStringLiteral("name")).toString(), import.value(QStringLiteral("version")).toString());
+ if (!path.isEmpty())
+ import[QStringLiteral("path")] = path;
+ QVariantMap plugininfo = pluginsForModulePath(import.value(QStringLiteral("path")).toString());
+ QString plugins = plugininfo.value(QStringLiteral("plugins")).toString();
+ QString classnames = plugininfo.value(QStringLiteral("classnames")).toString();
+ if (!plugins.isEmpty())
import[QStringLiteral("plugin")] = plugins;
+ if (!classnames.isEmpty())
import[QStringLiteral("classname")] = classnames;
- }
}
- if (!import[QStringLiteral("path")].isNull())
- done.append(import);
+ done.append(import);
}
return done;
}
+// Scan a single qml file for import statements
+QVariantList findQmlImportsInFile(const QString &qmlFilePath)
+{
+ QFile qmlFile(qmlFilePath);
+ if (!qmlFile.open(QIODevice::ReadOnly)) {
+ std::cerr << "Cannot open input file " << QDir::toNativeSeparators(qmlFile.fileName()).toStdString()
+ << ':' << qmlFile.errorString().toStdString() << std::endl;
+ return QVariantList();
+ }
+ QString code = QString::fromUtf8(qmlFile.readAll());
+
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(code, /*line = */ 1);
+ QQmlJS::Parser parser(&engine);
+
+ if (!parser.parse() || !parser.diagnosticMessages().isEmpty()) {
+ // Extract errors from the parser
+ foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
+ std::cerr << QDir::toNativeSeparators(qmlFile.fileName()).toStdString() << ':'
+ << m.loc.startLine << ':' << m.message.toStdString() << std::endl;
+ }
+ return QVariantList();
+ }
+
+ return findPathsForModuleImports(
+ findImportsInAst(parser.ast()->headers, code, QFileInfo(qmlFilePath).absolutePath()));
+}
+
// Merge two lists of imports, discard duplicates.
QVariantList mergeImports(const QVariantList &a, const QVariantList &b)
{
@@ -247,12 +239,72 @@ QVariantList mergeImports(const QVariantList &a, const QVariantList &b)
return merged;
}
-// find Qml Imports Recursively
-QVariantList findQmlImportsRecursively(const QStringList &qmlDirs)
+// Scan all qml files in directory for import statements
+QVariantList findQmlImportsInDirectory(const QString &qmlDir)
{
QVariantList ret;
+ if (qmlDir.isEmpty())
+ return ret;
+
+ QDirIterator iterator(qmlDir, QDirIterator::Subdirectories);
+ while (iterator.hasNext()) {
+ iterator.next();
+ QString path = iterator.filePath();
+ if (!path.endsWith(QStringLiteral(".qml")))
+ continue;
+
+ // skip obvious build output directories
+ if (path.contains(QStringLiteral("Debug-iphoneos")) || path.contains(QStringLiteral("Release-iphoneos")) ||
+ path.contains(QStringLiteral("Debug-iphonesimulator")) || path.contains(QStringLiteral("Release-iphonesimulator"))
+#ifdef Q_OS_WIN
+ || path.contains(QStringLiteral("/release/")) || path.contains(QStringLiteral("/debug/"))
+#endif
+ ){
+ continue;
+ }
+
+ QVariantList imports = findQmlImportsInFile(path);
+ ret = mergeImports(ret, imports);
+ }
+ return ret;
+}
+
+QSet<QString> importModulePaths(QVariantList imports) {
+ QSet<QString> ret;
+ foreach (const QVariant &importVariant, imports) {
+ QVariantMap import = qvariant_cast<QVariantMap>(importVariant);
+ QString path = import.value(QStringLiteral("path")).toString();
+ QString type = import.value(QStringLiteral("type")).toString();
+ if (type == QStringLiteral("module") && !path.isEmpty())
+ ret.insert(QDir(path).canonicalPath());
+ }
+ return ret;
+}
- QSet<QString> toVisit = qmlDirs.toSet();
+// Find Qml Imports Recursively from a root set of qml files.
+// The directories in qmlDirs are searched recursively.
+// The files in qmlFiles parsed directly.
+QVariantList findQmlImportsRecursively(const QStringList &qmlDirs, const QStringList &qmlFiles)
+{
+ QVariantList ret;
+
+ // scan all app root qml directories for imports
+ foreach (const QString &qmlDir, qmlDirs) {
+ QVariantList imports = findQmlImportsInDirectory(qmlDir);
+ ret = mergeImports(ret, imports);
+ }
+
+ // scan app qml files for imports
+ foreach (const QString &qmlFile, qmlFiles) {
+ QVariantList imports = findQmlImportsInFile(qmlFile);
+ ret = mergeImports(ret, imports);
+ }
+
+
+ // get the paths to theimports found in the app qml
+ QSet<QString> toVisit = importModulePaths(ret);
+
+ // recursivly scan for import dependencies.
QSet<QString> visited;
while (!toVisit.isEmpty()) {
QString qmlDir = *toVisit.begin();
@@ -260,20 +312,12 @@ QVariantList findQmlImportsRecursively(const QStringList &qmlDirs)
visited.insert(qmlDir);
QVariantList imports = findQmlImportsInDirectory(qmlDir);
- imports = findPathsForModuleImports(imports);
-
- // schedule recursive visit of imports
- foreach (const QVariant &importVariant, imports) {
- QVariantMap import = qvariant_cast<QVariantMap>(importVariant);
- QString path = import[QStringLiteral("path")].toString();
- if (!path.isEmpty() && !visited.contains(path)) {
- toVisit.insert(path);
- }
- }
-
ret = mergeImports(ret, imports);
- }
+ QSet<QString> candidatePaths = importModulePaths(ret);
+ candidatePaths.subtract(visited);
+ toVisit.unite(candidatePaths);
+ }
return ret;
}
@@ -288,46 +332,46 @@ int main(int argc, char *argv[])
}
QStringList qmlRootPaths;
+ QStringList qmlFiles;
QStringList qmlImportPaths;
int i = 1;
while (i < args.count()) {
const QString &arg = args.at(i);
++i;
+ QStringList *argReceiver = 0;
if (!arg.startsWith(QLatin1Char('-'))) {
qmlRootPaths += arg;
} else if (arg == QLatin1String("-rootPath")) {
if (i >= args.count())
std::cerr << "-rootPath requires an argument\n";
-
- while (i < args.count()) {
- const QString arg = args.at(i);
- if (arg.startsWith(QLatin1Char('-')))
- break;
- ++i;
- qmlRootPaths += arg;
- }
+ argReceiver = &qmlRootPaths;
+ } else if (arg == QLatin1String("-qmlFiles")) {
+ if (i >= args.count())
+ std::cerr << "-qmlFiles requires an argument\n";
+ argReceiver = &qmlFiles;
} else if (arg == QLatin1String("-importPath")) {
if (i >= args.count())
std::cerr << "-importPath requires an argument\n";
-
- while (i < args.count()) {
- const QString arg = args.at(i);
- if (arg.startsWith(QLatin1Char('-')))
- break;
- ++i;
- qmlImportPaths += arg;
- }
+ argReceiver = &qmlImportPaths;
} else {
std::cerr << "Invalid argument: \"" << qPrintable(arg) << "\"\n";
return 1;
}
+
+ while (i < args.count()) {
+ const QString arg = args.at(i);
+ if (arg.startsWith(QLatin1Char('-')))
+ break;
+ ++i;
+ *argReceiver += arg;
+ }
}
g_qmlImportPaths = qmlImportPaths;
// Find the imports!
- QVariantList imports = findQmlImportsRecursively(qmlRootPaths);
+ QVariantList imports = findQmlImportsRecursively(qmlRootPaths, qmlFiles);
// Convert to JSON
QByteArray json = QJsonDocument(QJsonArray::fromVariantList(imports)).toJson();
diff --git a/tools/qmlimportscanner/qmlimportscanner.pro b/tools/qmlimportscanner/qmlimportscanner.pro
index 8c9dc5ab90..c8e458c6ae 100644
--- a/tools/qmlimportscanner/qmlimportscanner.pro
+++ b/tools/qmlimportscanner/qmlimportscanner.pro
@@ -1,15 +1,8 @@
option(host_build)
-force_bootstrap {
- QT = bootstrap-private
-} else {
- QT = core
-}
-
-QT += qmldevtools-private
+QT = core qmldevtools-private
DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
-CONFIG -= app_bundle
SOURCES += main.cpp
load(qt_tool)
diff --git a/tools/qmljs/main.cpp b/tools/qmljs/main.cpp
index 2d31dbfc0f..32a45d9289 100644
--- a/tools/qmljs/main.cpp
+++ b/tools/qmljs/main.cpp
@@ -202,22 +202,22 @@ int main(int argc, char *argv[])
const QString code = QString::fromUtf8(file.readAll());
file.close();
- try {
- QV4::Script script(ctx, code, fn);
- script.parseAsBinding = runAsQml;
- script.parse();
- QV4::ScopedValue result(scope, script.run());
- if (!result->isUndefined()) {
- if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
- std::cout << "exit value: " << qPrintable(result->toString(ctx)->toQString()) << std::endl;
- }
- } catch (...) {
+ QV4::ScopedValue result(scope);
+ QV4::Script script(ctx, code, fn);
+ script.parseAsBinding = runAsQml;
+ script.parse();
+ if (!scope.engine->hasException)
+ result = script.run();
+ if (scope.engine->hasException) {
QV4::StackTrace trace;
QV4::ScopedValue ex(scope, ctx->catchException(&trace));
showException(ctx, ex, trace);
return EXIT_FAILURE;
}
-
+ if (!result->isUndefined()) {
+ if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
+ std::cout << "exit value: " << qPrintable(result->toString(ctx)->toQString()) << std::endl;
+ }
} else {
std::cerr << "Error: cannot open file " << fn.toUtf8().constData() << std::endl;
return EXIT_FAILURE;
diff --git a/tools/qmljs/qmljs.pro b/tools/qmljs/qmljs.pro
index c67bb9caaf..3f984951f3 100644
--- a/tools/qmljs/qmljs.pro
+++ b/tools/qmljs/qmljs.pro
@@ -4,6 +4,4 @@ SOURCES = main.cpp
include($$PWD/../../src/3rdparty/masm/masm-defs.pri)
-CONFIG += exceptions
-
load(qt_tool)
diff --git a/tools/qmlmin/qmlmin.pro b/tools/qmlmin/qmlmin.pro
index 0b5ef2baee..2cbf196863 100644
--- a/tools/qmlmin/qmlmin.pro
+++ b/tools/qmlmin/qmlmin.pro
@@ -1,13 +1,5 @@
option(host_build)
-
-force_bootstrap {
- QT = bootstrap-private
-} else {
- QT = core
-}
-
-QT += qmldevtools-private
-
+QT = core qmldevtools-private
SOURCES += main.cpp
load(qt_tool)
diff --git a/tools/tools.pro b/tools/tools.pro
index 217748915b..a1b48789b8 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -1,15 +1,28 @@
TEMPLATE = subdirs
-qtHaveModule(quick): !android|android_app: SUBDIRS += qmlscene qmlplugindump
-qtHaveModule(qmltest): !android|android_app: SUBDIRS += qmltestrunner
SUBDIRS += \
qmlmin \
- qmlprofiler
-!android|android_app: SUBDIRS += \
- qml \
- qmlbundle
-qtHaveModule(quick):qtHaveModule(widgets): SUBDIRS += qmleasing
+ qmlimportscanner
-# qmlmin & qmlbundle are build tools.
+qmlmin.CONFIG = host_build
+qmlimportscanner.CONFIG = host_build
+
+!android|android_app {
+ SUBDIRS += \
+ qml \
+ qmlprofiler \
+ qmlbundle
+ qtHaveModule(quick) {
+ SUBDIRS += qmlscene qmlplugindump
+ qtHaveModule(widgets): SUBDIRS += qmleasing
+ }
+ qtHaveModule(qmltest): SUBDIRS += qmltestrunner
+ contains(QT_CONFIG, private_tests): SUBDIRS += qmljs
+}
+
+qml.depends = qmlimportscanner
+qmleasing.depends = qmlimportscanner
+
+# qmlmin, qmlimportscanner & qmlbundle are build tools.
# qmlscene is needed by the autotests.
# qmltestrunner may be useful for manual testing.
# qmlplugindump cannot be a build tool, because it loads target plugins.
@@ -19,10 +32,3 @@ qtNomakeTools( \
qmlplugindump \
qmleasing \
)
-
-contains(QT_CONFIG, private_tests): SUBDIRS += qmljs
-
-qtHaveModule(quick) {
- for(subdir, SUBDIRS): $${subdir}.depends += qmlimportscanner
- SUBDIRS += qmlimportscanner
-}